Use Case
IoT Anomaly Detection with Validation
Catch anomalies that static thresholds miss. Sensor readings are validated at ingress by Contact, analyzed by AI with conversation memory that spots contextual patterns over time, and alerts are scanned by Surface before reaching your dashboard and devices.
The problem with IoT anomaly detection
Static thresholds either fire constantly or miss gradual drifts. A reading of 72 °C is fine for a motor under load but alarming at idle. Context matters.
Each sensor reading is analyzed in isolation. The system can't tell whether a pattern has been developing over the last 50 readings or if this is a one-off spike.
A sensor glitch sends −999 and your pipeline generates a critical alert. Without ingress validation, garbage in means garbage alerts out.
Alerts go to Slack or email, but the dashboard entity isn't updated, the device doesn't know, and there's no audit trail of what was sent or why.
How Tendrl solves it
Validate at the edge, detect with context, deliver with confidence.
Sensor publishes via Contact
The sensor publishes readings with tags: ["sensor-reading"]. Each message contains temperature, humidity, and a device identifier.
client.publish(
data={
"temperature": 74.2,
"humidity": 45,
"device_id": "hvac-unit-12"
},
tags=["sensor-reading"]
) DynamicActions validate at ingress
Contact runs DynamicActions on every message. RequiredFields ensures temperature, humidity, and device_id are present. Rules use the between operator to enforce physical ranges: temperature between −40 and 150, humidity between 0 and 100. Validation is passive: messages always store. Failed readings get error tags injected and trigger a separate maintenance workflow.
{
"name": "range_check",
"requiredFields": ["temperature", "humidity", "device_id"],
"rules": [
{"field": "temperature", "operator": "between", "value": [-40, 150]},
{"field": "humidity", "operator": "between", "value": [0, 100]}
],
"tags": ["reading-valid"]
} AI analyzes with conversation memory
The Strand workflow's AI node uses conversation memory configured with a 2-hour TTL and space for 50 messages. On every run, the model loads its history of recent readings for this node, a rolling window that captures trends, drift, and baseline behavior.
The context_md system prompt defines the AI as an HVAC anomaly detector. The prompt uses Jinja2 to inject the latest reading. Because the model remembers prior readings, it can detect that temperature has been climbing 0.5 degrees per reading for the last hour, something a static threshold would miss until it's too late.
You are an HVAC anomaly detector. You receive sensor
readings over time and maintain memory of recent history.
Analyze the latest reading in context of recent readings.
Flag anomalies: sudden spikes, gradual drifts, unusual
correlations between temperature and humidity.
Return JSON:
{"is_anomaly": bool, "confidence": 0-1,
"severity": "info|warning|critical",
"explanation": "..."} Device: {{ payload.device_id }}
Temperature: {{ payload.temperature }}°C
Humidity: {{ payload.humidity }}% If anomalous, Surface scans the outbound alert
An if/else node checks the AI's is_anomaly field. If true, the alert payload (including the AI's explanation) is scanned by Surface before it leaves the system. This prevents the AI from inadvertently including sensitive infrastructure details, internal IPs, or credentials in alert messages destined for external dashboards.
Contact delivers the alert and updates state
A Contact connector with operation message sends the alert to a dashboard entity. A second Contact connector with operation update_state patches the sensor's state table with last_anomaly_time, anomaly_severity, and status: "anomaly_detected". Non-anomalous readings update state silently with status: "healthy".
When validation fails: the maintenance path
Bad data isn't dropped; it triggers its own workflow.
Failed validation injects error tags
When a sensor sends −999 for temperature or omits a required field, Contact stores the message, sets validation_status: "failed", and injects the DynamicAction's failure tags into the message context. Those tags match a separate maintenance workflow in Strand.
Notify the ops team
A Contact connector sends a message to the ops dashboard entity with the full ActionResult: which field failed, the actual value, the expected value, and the rule that caught it.
Update device state
A Contact connector with operation update_state sets the sensor's state to needs_maintenance with the validation error details. The state table becomes the source of truth for device health.
Send a tagged diagnostic message back
A Contact connector sends a message back to the sensor device with tag diagnostic. The device routes it with @client.on(tag="diagnostic") to run self-diagnostics and report back.
@client.on(tag="diagnostic")
def run_diagnostics(msg):
report = self_test(msg.get("data", {}))
client.publish(report, tags=["diagnostic-result"]) Intelligent monitoring, not just thresholds
AI with conversation memory spots patterns across 50+ readings that static rules miss entirely.
The between operator catches sensor glitches at ingress. −999 never reaches your AI pipeline.
Failed validation doesn't drop the message. It stores, tags, and routes, giving you an audit trail of bad data.
Surface checks outbound alerts for accidental data leaks before they reach external dashboards.
Each device's state table tracks last anomaly, severity, and maintenance status, all queryable via the Contact API.
Validation failures trigger automatic ops notification, state updates, and tagged diagnostic messages back to the device.
TTL and max messages let you tune the AI's context window. 2-hour TTL for fast equipment, 7-day TTL for slow environmental drift.
Pass and fail paths are different tag sets matching different Strand workflows. No if/else needed at the Contact level.
Example: HVAC anomaly detection
Sensor to alert to device state, with two paths for valid and invalid data.
Contact checks temperature is between −40 and 150, humidity between 0 and 100, and all required fields are present. Pass triggers the anomaly detection workflow. Fail triggers the maintenance workflow: ops notified, device state set to needs_maintenance, diagnostic command sent.
Claude analyzes the reading in context of the last 50 messages (2-hour TTL). It can spot that temperature has been climbing 0.5 degrees per reading for the last hour, something a threshold would miss until it's too late.
Anomaly alerts are scanned by Surface, then delivered via Contact to the dashboard entity and written to the sensor's state table. Non-anomalous readings update state silently.
Smarter monitoring starts here
Free tier includes 5 entities, 10 workflows, and 550 runs/month. No credit card required.
Tendrl