TimesFM Forecasting
google-research/timesfm
Forecasts any univariate time series zero-shot with Google's TimesFM model, returning point forecasts and calibrated prediction intervals without training.
Agent skill
by datadrivenconstruction in datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
Aggregate and analyze IoT sensor data from construction sites.
$ npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction sensor-data-aggregator --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction.git skills-src && mkdir -p .claude/skills && cp -r skills-src/5_DDC_Innovative/sensor-data-aggregator .claude/skills/sensor-data-aggregator && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "sensor-data-aggregator" agent skill from https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction/tree/main/5_DDC_Innovative/sensor-data-aggregator into .claude/skills/sensor-data-aggregator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "sensor-data-aggregator", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction/tree/main/5_DDC_Innovative/sensor-data-aggregatorType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction sensor-data-aggregator --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction.git skills-src && mkdir -p .agents/skills && cp -r skills-src/5_DDC_Innovative/sensor-data-aggregator .agents/skills/sensor-data-aggregator && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "sensor-data-aggregator" agent skill from https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction/tree/main/5_DDC_Innovative/sensor-data-aggregator into .agents/skills/sensor-data-aggregator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "sensor-data-aggregator", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction sensor-data-aggregator --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/5_DDC_Innovative/sensor-data-aggregator .cursor/skills/sensor-data-aggregator && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "sensor-data-aggregator" agent skill from https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction/tree/main/5_DDC_Innovative/sensor-data-aggregator into .cursor/skills/sensor-data-aggregator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "sensor-data-aggregator", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction.git --path 5_DDC_Innovative/sensor-data-aggregator--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction sensor-data-aggregator --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/5_DDC_Innovative/sensor-data-aggregator .gemini/skills/sensor-data-aggregator && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "sensor-data-aggregator" agent skill from https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction/tree/main/5_DDC_Innovative/sensor-data-aggregator into .gemini/skills/sensor-data-aggregator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "sensor-data-aggregator", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction sensor-data-aggregatorInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction.git skills-src && mkdir -p .github/skills && cp -r skills-src/5_DDC_Innovative/sensor-data-aggregator .github/skills/sensor-data-aggregator && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "sensor-data-aggregator" agent skill from https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction/tree/main/5_DDC_Innovative/sensor-data-aggregator into .github/skills/sensor-data-aggregator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "sensor-data-aggregator", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction sensor-data-aggregator --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/5_DDC_Innovative/sensor-data-aggregator .opencode/skills/sensor-data-aggregator && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "sensor-data-aggregator" agent skill from https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction/tree/main/5_DDC_Innovative/sensor-data-aggregator into .opencode/skills/sensor-data-aggregator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "sensor-data-aggregator", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
sensor-data-aggregatorAggregate and analyze IoT sensor data from construction sites.
Sensor Data Aggregator is an agent skill from datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction. Aggregate and analyze IoT sensor data from construction sites. Collect data from multiple sensor types, detect anomalies, and trigger alerts for safety and quality monitoring.
Its SKILL.md is about 5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files (for example `claw.json` and `instructions.md`).
It sits in Data & Analytics, covering Anomaly detection. The repository describes itself as: 221 AI skills for construction: BIM analysis, cost estimation, scheduling, document control, and automation with Claude Code. The licence is MIT.
Read from SKILL.md and the folder at commit ce45bbf. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pipFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use pip, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Sensor Data Aggregator loads about 5k tokens when it runs. Until then it costs about 50 tokens; SKILL.md has 41 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction at commit ce45bbf, republished under its MIT licence (© datadrivenconstruction). 41 words, ~4,974 tokens.
.claude/skills/sensor-data-aggregator/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.Collect, aggregate, and analyze data from IoT sensors deployed across construction sites. Support real-time monitoring of environmental conditions, equipment status, structural integrity, and worker safety through unified data processing.
┌─────────────────────────────────────────────────────────────────┐
│ SENSOR DATA AGGREGATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ SENSORS AGGREGATOR OUTPUTS │
│ ─────── ────────── ─────── │
│ │
│ 🌡️ Temperature ─────┐ 📊 Dashboard │
│ 💧 Humidity ─────┤ ┌──────────────┐ ⚠️ Alerts │
│ 📊 Vibration ─────┼───→│ AGGREGATE │───→ 📈 Analytics │
│ 🔊 Noise ─────┤ │ PROCESS │ 📋 Reports │
│ 💨 Air Quality ─────┤ │ ANALYZE │ 🔄 API │
│ 📍 Location ─────┘ └──────────────┘ │
│ │
│ DATA FLOW: │
│ Raw → Validate → Transform → Store → Analyze → Alert │
│ │
│ ANALYSIS: │
│ • Real-time monitoring │
│ • Trend detection │
│ • Anomaly identification │
│ • Threshold alerting │
│ │
└─────────────────────────────────────────────────────────────────┘from dataclasses import dataclass, field
from typing import List, Dict, Optional, Callable, Tuple
from datetime import datetime, timedelta
from enum import Enum
import statistics
import json
class SensorType(Enum):
TEMPERATURE = "temperature"
HUMIDITY = "humidity"
VIBRATION = "vibration"
NOISE = "noise"
AIR_QUALITY = "air_quality"
DUST = "dust"
GAS = "gas"
PRESSURE = "pressure"
STRAIN = "strain"
TILT = "tilt"
GPS = "gps"
PROXIMITY = "proximity"
class AlertSeverity(Enum):
INFO = "info"
WARNING = "warning"
CRITICAL = "critical"
EMERGENCY = "emergency"
class DataQuality(Enum):
GOOD = "good"
SUSPECT = "suspect"
BAD = "bad"
MISSING = "missing"
@dataclass
class SensorReading:
sensor_id: str
sensor_type: SensorType
timestamp: datetime
value: float
unit: str
quality: DataQuality = DataQuality.GOOD
location: Optional[Dict] = None
metadata: Dict = field(default_factory=dict)
@dataclass
class Sensor:
id: str
name: str
sensor_type: SensorType
unit: str
location: Dict # {zone, floor, coordinates}
thresholds: Dict # {warning, critical, min, max}
calibration_date: datetime
battery_level: float = 100.0
status: str = "active"
@dataclass
class Alert:
id: str
sensor_id: str
sensor_type: SensorType
severity: AlertSeverity
timestamp: datetime
value: float
threshold: float
message: str
acknowledged: bool = False
resolved: bool = False
@dataclass
class AggregatedMetric:
sensor_type: SensorType
period_start: datetime
period_end: datetime
readings_count: int
min_value: float
max_value: float
avg_value: float
std_dev: float
alerts_triggered: int
class SensorDataAggregator:
"""Aggregate and analyze IoT sensor data."""
# Default thresholds by sensor type
DEFAULT_THRESHOLDS = {
SensorType.TEMPERATURE: {"warning": 35, "critical": 40, "unit": "°C"},
SensorType.HUMIDITY: {"warning": 80, "critical": 90, "unit": "%"},
SensorType.VIBRATION: {"warning": 10, "critical": 25, "unit": "mm/s"},
SensorType.NOISE: {"warning": 85, "critical": 100, "unit": "dB"},
SensorType.AIR_QUALITY: {"warning": 100, "critical": 150, "unit": "AQI"},
SensorType.DUST: {"warning": 3, "critical": 10, "unit": "mg/m³"},
SensorType.GAS: {"warning": 20, "critical": 50, "unit": "ppm"},
}
def __init__(self, site_name: str):
self.site_name = site_name
self.sensors: Dict[str, Sensor] = {}
self.readings: List[SensorReading] = []
self.alerts: List[Alert] = []
self.alert_handlers: List[Callable] = []
def register_sensor(self, id: str, name: str, sensor_type: SensorType,
unit: str, location: Dict,
thresholds: Dict = None) -> Sensor:
"""Register a new sensor."""
if thresholds is None:
thresholds = self.DEFAULT_THRESHOLDS.get(sensor_type, {})
sensor = Sensor(
id=id,
name=name,
sensor_type=sensor_type,
unit=unit,
location=location,
thresholds=thresholds,
calibration_date=datetime.now()
)
self.sensors[id] = sensor
return sensor
def ingest_reading(self, sensor_id: str, value: float,
timestamp: datetime = None,
metadata: Dict = None) -> SensorReading:
"""Ingest a sensor reading."""
if sensor_id not in self.sensors:
raise ValueError(f"Unknown sensor: {sensor_id}")
sensor = self.sensors[sensor_id]
# Validate data quality
quality = self._validate_reading(sensor, value)
reading = SensorReading(
sensor_id=sensor_id,
sensor_type=sensor.sensor_type,
timestamp=timestamp or datetime.now(),
value=value,
unit=sensor.unit,
quality=quality,
location=sensor.location,
metadata=metadata or {}
)
self.readings.append(reading)
# Check thresholds
if quality == DataQuality.GOOD:
self._check_thresholds(sensor, reading)
return reading
def ingest_batch(self, readings: List[Dict]) -> int:
"""Ingest multiple readings at once."""
count = 0
for r in readings:
try:
self.ingest_reading(
sensor_id=r['sensor_id'],
value=r['value'],
timestamp=r.get('timestamp', datetime.now()),
metadata=r.get('metadata')
)
count += 1
except Exception:
pass # Log error but continue
return count
def _validate_reading(self, sensor: Sensor, value: float) -> DataQuality:
"""Validate reading quality."""
thresholds = sensor.thresholds
# Check if value is within physical limits
if 'min' in thresholds and value < thresholds['min']:
return DataQuality.SUSPECT
if 'max' in thresholds and value > thresholds['max']:
return DataQuality.SUSPECT
# Check for sudden spikes (compare with recent readings)
recent = self.get_recent_readings(sensor.id, minutes=5)
if len(recent) >= 3:
avg = statistics.mean([r.value for r in recent])
if abs(value - avg) > avg * 0.5: # 50% deviation
return DataQuality.SUSPECT
return DataQuality.GOOD
def _check_thresholds(self, sensor: Sensor, reading: SensorReading):
"""Check if reading exceeds thresholds."""
thresholds = sensor.thresholds
if 'critical' in thresholds and reading.value >= thresholds['critical']:
self._create_alert(sensor, reading, AlertSeverity.CRITICAL)
elif 'warning' in thresholds and reading.value >= thresholds['warning']:
self._create_alert(sensor, reading, AlertSeverity.WARNING)
def _create_alert(self, sensor: Sensor, reading: SensorReading,
severity: AlertSeverity):
"""Create and dispatch alert."""
threshold = sensor.thresholds.get(severity.value, 0)
alert = Alert(
id=f"ALERT-{len(self.alerts)+1:06d}",
sensor_id=sensor.id,
sensor_type=sensor.sensor_type,
severity=severity,
timestamp=reading.timestamp,
value=reading.value,
threshold=threshold,
message=f"{sensor.name}: {reading.value} {reading.unit} exceeds {severity.value} threshold ({threshold})"
)
self.alerts.append(alert)
# Dispatch to handlers
for handler in self.alert_handlers:
try:
handler(alert)
except Exception:
pass
def register_alert_handler(self, handler: Callable):
"""Register alert callback handler."""
self.alert_handlers.append(handler)
def get_recent_readings(self, sensor_id: str,
minutes: int = 60) -> List[SensorReading]:
"""Get recent readings for sensor."""
cutoff = datetime.now() - timedelta(minutes=minutes)
return [r for r in self.readings
if r.sensor_id == sensor_id and r.timestamp > cutoff]
def get_readings_by_type(self, sensor_type: SensorType,
start: datetime = None,
end: datetime = None) -> List[SensorReading]:
"""Get readings by sensor type."""
readings = [r for r in self.readings if r.sensor_type == sensor_type]
if start:
readings = [r for r in readings if r.timestamp >= start]
if end:
readings = [r for r in readings if r.timestamp <= end]
return readings
def aggregate_by_period(self, sensor_type: SensorType,
period_minutes: int = 60) -> List[AggregatedMetric]:
"""Aggregate readings into time periods."""
readings = self.get_readings_by_type(sensor_type)
if not readings:
return []
# Group by period
periods: Dict[datetime, List[SensorReading]] = {}
for r in readings:
# Round to period start
period_start = r.timestamp.replace(
minute=(r.timestamp.minute // period_minutes) * period_minutes,
second=0,
microsecond=0
)
if period_start not in periods:
periods[period_start] = []
periods[period_start].append(r)
# Calculate aggregates
aggregates = []
for period_start, period_readings in sorted(periods.items()):
values = [r.value for r in period_readings]
# Count alerts in period
period_end = period_start + timedelta(minutes=period_minutes)
period_alerts = len([a for a in self.alerts
if a.sensor_type == sensor_type
and period_start <= a.timestamp < period_end])
aggregates.append(AggregatedMetric(
sensor_type=sensor_type,
period_start=period_start,
period_end=period_end,
readings_count=len(values),
min_value=min(values),
max_value=max(values),
avg_value=statistics.mean(values),
std_dev=statistics.stdev(values) if len(values) > 1 else 0,
alerts_triggered=period_alerts
))
return aggregates
def detect_anomalies(self, sensor_id: str,
lookback_hours: int = 24) -> List[Dict]:
"""Detect anomalies in sensor data."""
cutoff = datetime.now() - timedelta(hours=lookback_hours)
readings = [r for r in self.readings
if r.sensor_id == sensor_id and r.timestamp > cutoff]
if len(readings) < 10:
return []
values = [r.value for r in readings]
avg = statistics.mean(values)
std = statistics.stdev(values)
anomalies = []
for r in readings:
# Z-score based anomaly detection
if std > 0:
z_score = abs(r.value - avg) / std
if z_score > 3: # 3 standard deviations
anomalies.append({
"timestamp": r.timestamp,
"value": r.value,
"expected": avg,
"z_score": z_score,
"type": "statistical_outlier"
})
return anomalies
def get_sensor_health(self) -> List[Dict]:
"""Get health status of all sensors."""
health = []
now = datetime.now()
for sensor in self.sensors.values():
recent = self.get_recent_readings(sensor.id, minutes=30)
# Determine status
if not recent:
status = "offline"
elif sensor.battery_level < 20:
status = "low_battery"
elif any(r.quality != DataQuality.GOOD for r in recent[-5:]):
status = "degraded"
else:
status = "healthy"
health.append({
"sensor_id": sensor.id,
"sensor_name": sensor.name,
"type": sensor.sensor_type.value,
"status": status,
"battery": sensor.battery_level,
"last_reading": recent[-1].timestamp if recent else None,
"readings_30min": len(recent)
})
return sorted(health, key=lambda x: x['status'] != 'healthy', reverse=True)
def get_zone_summary(self, zone: str) -> Dict:
"""Get summary for specific zone."""
zone_sensors = [s for s in self.sensors.values()
if s.location.get('zone') == zone]
if not zone_sensors:
return {"zone": zone, "error": "No sensors in zone"}
summary = {
"zone": zone,
"sensor_count": len(zone_sensors),
"by_type": {}
}
for sensor in zone_sensors:
recent = self.get_recent_readings(sensor.id, minutes=15)
if not recent:
continue
values = [r.value for r in recent]
sensor_type = sensor.sensor_type.value
if sensor_type not in summary["by_type"]:
summary["by_type"][sensor_type] = {
"current": values[-1] if values else None,
"avg": statistics.mean(values) if values else None,
"unit": sensor.unit,
"status": "normal"
}
# Check status
thresholds = sensor.thresholds
current = values[-1]
if 'critical' in thresholds and current >= thresholds['critical']:
summary["by_type"][sensor_type]["status"] = "critical"
elif 'warning' in thresholds and current >= thresholds['warning']:
summary["by_type"][sensor_type]["status"] = "warning"
return summary
def generate_report(self) -> str:
"""Generate sensor data report."""
lines = [
"# Sensor Data Report",
"",
f"**Site:** {self.site_name}",
f"**Report Date:** {datetime.now().strftime('%Y-%m-%d %H:%M')}",
"",
"## Sensor Inventory",
"",
f"| Sensor | Type | Location | Status |",
f"|--------|------|----------|--------|"
]
health = self.get_sensor_health()
for h in health:
status_icon = "✅" if h['status'] == 'healthy' else "⚠️" if h['status'] == 'degraded' else "🔴"
lines.append(
f"| {h['sensor_name']} | {h['type']} | - | {status_icon} {h['status']} |"
)
# Recent alerts
recent_alerts = [a for a in self.alerts
if a.timestamp > datetime.now() - timedelta(hours=24)]
if recent_alerts:
lines.extend([
"",
f"## Alerts (Last 24h) - {len(recent_alerts)} total",
"",
"| Time | Sensor | Severity | Value | Threshold |",
"|------|--------|----------|-------|-----------|"
])
for alert in sorted(recent_alerts, key=lambda x: x.timestamp, reverse=True)[:20]:
sev_icon = "🔴" if alert.severity == AlertSeverity.CRITICAL else "🟡"
lines.append(
f"| {alert.timestamp.strftime('%H:%M')} | {alert.sensor_id} | "
f"{sev_icon} {alert.severity.value} | {alert.value:.1f} | {alert.threshold} |"
)
# Current readings by type
lines.extend([
"",
"## Current Readings by Type",
""
])
for sensor_type in SensorType:
readings = self.get_readings_by_type(sensor_type)
if not readings:
continue
recent = [r for r in readings
if r.timestamp > datetime.now() - timedelta(minutes=15)]
if not recent:
continue
values = [r.value for r in recent]
lines.append(
f"**{sensor_type.value}**: "
f"Avg={statistics.mean(values):.1f}, "
f"Min={min(values):.1f}, "
f"Max={max(values):.1f}"
)
return "\n".join(lines)from datetime import datetime, timedelta
# Initialize aggregator
aggregator = SensorDataAggregator("Construction Site A")
# Register sensors
aggregator.register_sensor(
"TEMP-001", "Zone A Temperature",
SensorType.TEMPERATURE, "°C",
location={"zone": "A", "floor": 1, "x": 10, "y": 20},
thresholds={"warning": 32, "critical": 38, "min": -10, "max": 50}
)
aggregator.register_sensor(
"VIB-001", "Foundation Vibration",
SensorType.VIBRATION, "mm/s",
location={"zone": "Foundation", "floor": 0}
)
aggregator.register_sensor(
"DUST-001", "Dust Monitor",
SensorType.DUST, "mg/m³",
location={"zone": "A", "floor": 1}
)
# Register alert handler
def handle_alert(alert):
print(f"ALERT: {alert.severity.value} - {alert.message}")
aggregator.register_alert_handler(handle_alert)
# Ingest readings
aggregator.ingest_reading("TEMP-001", 28.5)
aggregator.ingest_reading("TEMP-001", 33.0) # Warning!
aggregator.ingest_reading("VIB-001", 5.2)
aggregator.ingest_reading("DUST-001", 2.1)
# Batch ingest
readings = [
{"sensor_id": "TEMP-001", "value": 29.0},
{"sensor_id": "VIB-001", "value": 4.8},
{"sensor_id": "DUST-001", "value": 2.5}
]
aggregator.ingest_batch(readings)
# Check sensor health
health = aggregator.get_sensor_health()
for h in health:
print(f"{h['sensor_name']}: {h['status']}")
# Get zone summary
summary = aggregator.get_zone_summary("A")
print(f"Zone A: {summary}")
# Detect anomalies
anomalies = aggregator.detect_anomalies("TEMP-001")
print(f"Anomalies found: {len(anomalies)}")
# Generate report
print(aggregator.generate_report())pip install (no external dependencies)© datadrivenconstruction, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 2 other files in 5_DDC_Innovative/sensor-data-aggregator of datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction.
Open the folder on GitHubat commit ce45bbf
Sensor Data Aggregator next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Sensor Data Aggregator this skilldatadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction | 344 | — | ~5k | Automated safety check: Pass | MIT | |
| TimesFM Forecastinggoogle-research/timesfm | 34k | — | ~4.7k | Automated safety check: Pass | Apache-2.0 | |
| Anomalib Adding A Modelopen-edge-platform/anomalib | 6.2k | — | ~1.9k | Automated safety check: Pass | Apache-2.0 | |
| Anomalib Tiled Ensembleopen-edge-platform/anomalib | 6.2k | — | ~1.4k | Automated safety check: Pass | Apache-2.0 | |
| Kqlmicrosoft/fabric-rti-mcp | 131 | — | ~6.2k | Automated safety check: Pass | MIT | |
| Time Series Analytics Useropen-edge-platform/edge-ai-libraries | 169 | — | ~3.1k | Automated safety check: Pass | Apache-2.0 |
google-research/timesfm
Forecasts any univariate time series zero-shot with Google's TimesFM model, returning point forecasts and calibrated prediction intervals without training.
open-edge-platform/anomalib
Adds a new anomaly-detection model to anomalib under src/anomalib/models/.
open-edge-platform/anomalib
Runs and configures the anomalib tiled-ensemble pipeline, which trains/evaluates one model per image tile and merges results (with optional seam smoothing) for high-resolution anomaly detection.
microsoft/fabric-rti-mcp
KQL language expertise for writing correct, efficient Kusto queries using the Fabric RTI MCP tools.
open-edge-platform/edge-ai-libraries
Build a new time-series analytics use case on top of the deployed Time Series Analytics microservice — bring it up with Docker Compose (from a repo clone, or by fetching the compose files from…
Dynatrace/dynatrace-for-ai
Analyze dashboards and notebooks using Davis analyzers — anomaly detection, novelty scoring, and correlation.
datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
Orchestrate multiple AI agents for construction workflows: estimator, scheduler, document, QA and safety agents coordinated by a supervisor agent, with human checkpoints.
datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
Estimate embodied carbon and produce ESG/climate reporting for construction: LCA per work item, material-based carbon factors, EU taxonomy and CSRD alignment.
datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
Material passports and circular construction: generate per-element material inventories from BOQ/BIM, mark reuse potential and recycled content, and prepare deconstruction data.
datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
Browse and search the OpenConstructionERP cost database: classification tree, SQL and semantic search, autocomplete, certainty badges, and the resource catalog.
datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
Create bills of quantities and estimates in OpenConstructionERP: search cost items, build BOQ sections, link BIM elements in bulk, validate the BOQ, and export GAEB/XLSX/JSON.
datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
Field operations in OpenConstructionERP: punch list, daily diary, HSE observations and task tracking on site.
Categories
Aggregate and analyze IoT sensor data from construction sites. Sensor Data Aggregator is an agent skill from datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction. Aggregate and analyze IoT sensor data from construction sites.
Sensor Data Aggregator fits situations like: alerts for safety and quality monitoring; tasks that involve Anomaly detection.
Run `npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a claude-code`. Or copy the skill folder (5_DDC_Innovative/sensor-data-aggregator in datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction) into .claude/skills/sensor-data-aggregator in your project. Claude Code loads it when a task matches its description.
Run `npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a codex`. Or copy the skill folder (5_DDC_Innovative/sensor-data-aggregator in datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction) into .agents/skills/sensor-data-aggregator in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill sensor-data-aggregator -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/sensor-data-aggregator, .gemini/skills/sensor-data-aggregator, .github/skills/sensor-data-aggregator and .opencode/skills/sensor-data-aggregator in your project.
Going by SKILL.md and its folder, Sensor Data Aggregator needs the command-line tools its instructions call (pip). Our summary lists: Python 3.
SKILL.md contains no URLs. Its commands use pip, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Sensor Data Aggregator is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5k tokens (SKILL.md is roughly 20k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Sensor Data Aggregator: TimesFM Forecasting (google-research/timesfm, 34k stars), Anomalib Adding A Model (open-edge-platform/anomalib, 6.2k stars), Anomalib Tiled Ensemble (open-edge-platform/anomalib, 6.2k stars) and Kql (microsoft/fabric-rti-mcp, 131 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
datadrivenconstruction (a GitHub user) maintains it in datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction, which has 344 GitHub stars. The repository holds 43 skills in this directory. The repository was last updated on August 22, 2026.
Source: datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.