Docs / Strand / tutorials/iot-alert-pipeline

Tutorial: IoT Alert Pipeline

Build an end-to-end pipeline that reads sensor data from an ESP32, sends it through Contact, analyzes it with AI in Strand, and delivers alerts to Slack.

code

ESP32 → Contact (MQTT) → Strand Workflow → AI Analysis → Slack Alert

Time: ~30 minutes Difficulty: Beginner You'll need: An ESP32 board, a Slack workspace, and an OpenAI or Anthropic API key

---

Step 1: Set Up Contact

Create a Service

In the Contact dashboard, go to Services and create a new service:

Create an Entity

Go to EntitiesCreate Entity:

After creation, click Connect to get the MQTT credentials. Save these: you'll need the broker URL, username, and password.

Create an API Key

Go to Access ControlAPI Keys and create a key for esp32-sensor with the entity:WriteMessages permission. You'll use this in Strand to link the two platforms.

---

Step 2: Program the ESP32

Flash the following MicroPython code to your ESP32. This reads a temperature sensor and publishes data to Contact every 30 seconds.

python

from umqtt.simple import MQTTClient

# Wi-Fi (connect before this runs)
# Replace with your Contact MQTT credentials
BROKER = "mqtt.tendrl.com"
PORT = 443
CLIENT_ID = "your-account-number:us-1:entity:esp32-sensor"  # your entity's resourcePath
USERNAME = "your-api-key-id"
PASSWORD = "your-api-key-secret"

# ADC pin for temperature sensor (adjust for your hardware)
adc = machine.ADC(machine.Pin(34))
adc.atten(machine.ADC.ATTN_11DB)

def read_temperature():
    """Convert ADC reading to Celsius (adjust for your sensor)."""
    raw = adc.read()
    voltage = raw * 3.3 / 4095
    return round(voltage * 100, 1)  # LM35 formula

client = MQTTClient(CLIENT_ID, BROKER, PORT, USERNAME, PASSWORD, ssl=True)
client.connect()
print("Connected to Contact MQTT broker")

while True:
    temp = read_temperature()
    payload = json.dumps({
        "temperature": temp,
        "unit": "celsius",
        "device": CLIENT_ID
    })
    client.publish("contact/messages", payload)
    print(f"Sent: {temp}°C")
    time.sleep(30)
Tip

Don't have an ESP32? You can simulate messages with curl:

bash

curl -X POST https://app.tendrl.com/api/entities/message \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "msg_type": "publish",
    "data": {
      "temperature": 28.5,
      "unit": "celsius",
      "device": "esp32-sensor"
    }
  }'

---

Step 3: Set Up Strand Connectors

You need three connectors. Go to the Strand Connectors page and create each one:

Slack Connector

Field Value
Type Slack
Name My Slack
Bot Token Your Slack bot token (starts with xoxb-)
Default Channel #sensor-alerts
Info

To get a Slack bot token: go to api.slack.com/apps, create an app, add chat:write and chat:write.public scopes under OAuth & Permissions, then install to your workspace. Copy the Bot User OAuth Token.

AI Connector (OpenAI or Anthropic)

Field Value
Type OpenAI (or Anthropic)
Name My AI
API Key Your OpenAI/Anthropic API key

Contact Message Connector

Field Value
Type Contact Entity Message
Name Contact Sensor
API Key The entity API key from Step 1

---

Step 4: Create the Strand Workflow

Go to FlowsNew Workflow and name it Sensor Alert Pipeline.

4a. Add the Trigger

Your workflow needs to receive events from Contact. Set up a Connector Subscription:

  1. Click Subscriptions in the workflow settings
  2. Add a subscription for your Contact Sensor connector
  3. This creates a trigger, so Contact will push messages to this workflow automatically

Alternatively, use the API trigger: call POST /trigger/{connector_id} with the sensor payload from any external system.

4b. Add a Python Snippet Node

Drag a Python Snippet node onto the canvas. This extracts the sensor data from Contact's message format:

python

# Sensor data from the Contact message
sensor_data = payload.get("data", {})

temperature = sensor_data.get("temperature", 0)
device = sensor_data.get("device", "unknown")

# Determine alert level
if temperature > 35:
    alert_level = "critical"
elif temperature > 30:
    alert_level = "warning"
else:
    alert_level = "normal"

result = {
    "temperature": temperature,
    "device": device,
    "alert_level": alert_level,
    "needs_analysis": alert_level != "normal"
}

4c. Add a Logic Node (Filter)

Add a Logic node set to Filter mode. Connect it to the Python Snippet.

Condition: {{ steps.python_snippet.output_payload.needs_analysis }} == true

This ensures we only analyze and alert on abnormal readings, saving AI API costs.

4d. Add an AI Connector Node

Drag a Connector node and select your AI connector. Connect it after the Logic node.

Operation: chat

System Prompt:

code

You are an IoT monitoring assistant. Analyze sensor readings and provide a brief assessment (2-3 sentences) including: what the reading means, potential causes, and recommended action.

User Message:

code

Device: {{ steps.python_snippet.output_payload.device }}
Temperature: {{ steps.python_snippet.output_payload.temperature }}°C
Alert Level: {{ steps.python_snippet.output_payload.alert_level }}

4e. Add a Slack Connector Node

Drag another Connector node and select your Slack connector. Connect it after the AI node.

Operation: send_message

Message Text:

code

🌡️ *Sensor Alert: {{ steps.python_snippet.output_payload.alert_level | upper }}*

*Device:* {{ steps.python_snippet.output_payload.device }}
*Temperature:* {{ steps.python_snippet.output_payload.temperature }}°C

*AI Analysis:*
{{ steps.ai_node.output_payload.response }}

Final Workflow

Your workflow should look like this:

code

[Contact Trigger] → [Python Snippet] → [Logic Filter] → [AI Analysis] → [Slack Alert]

Click Deploy to activate the workflow.

---

Step 5: Test It

Option A: Send a Test Message from Contact

bash

curl -X POST https://app.tendrl.com/api/entities/message \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "msg_type": "publish",
    "data": {
      "temperature": 36.2,
      "unit": "celsius",
      "device": "esp32-sensor"
    }
  }'

Option B: Trigger Strand Directly

bash

curl -X POST https://app.tendrl.com/strand-api/trigger/YOUR_CONNECTOR_ID \
  -H "Authorization: Bearer YOUR_STRAND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payload": {
      "data": {
        "data": {
          "temperature": 36.2,
          "unit": "celsius",
          "device": "esp32-sensor"
        }
      }
    }
  }'

Check your #sensor-alerts Slack channel; you should see an alert with AI analysis within a few seconds.

---

What's Happening

  1. ESP32 reads sensor data and publishes via MQTT to Contact
  2. Contact receives the message, validates it against the service rules, and forwards it to Strand via the connector subscription
  3. Strand runs the workflow:
  1. Slack delivers the alert to your team

The entire pipeline runs in seconds with zero custom backend code.

---

Next Steps