Step 6: Alerts & Production Notes
Let’s add alert rules and discuss what you’d need for production.
Add Alert Rules
We’ll add two alerts:
- Battery Low: When battery < 20%
- Temperature High: When temperature > 30°C
Alert Flow in Node-RED
1. Add Switch Node (Route by Condition)
After the Function node, add a switch node:
- Property:
metrics.batteryPct - Condition 1:
< 20→ Output 1 (battery low) - Condition 2:
>= 20→ Output 2 (normal)
2. Add Another Switch for Temperature
Add another switch node:
- Property:
metrics.temperatureC - Condition 1:
> 30→ Output 1 (temp high) - Condition 2:
<= 30→ Output 2 (normal)
3. Add Rate Limiter (Prevent Spam)
Add a delay node before alerts:
- Action: Rate limit
- Rate: 1 message per 60 seconds
- This prevents alert spam if condition stays true
4. Add Alert Notification
Add a function node for alert messages:
// Create alert message
const alert = {
deviceId: msg.deviceId,
timestamp: msg.ts,
type: msg.alertType, // "battery_low" or "temperature_high"
severity: "warning",
message: msg.alertMessage,
metrics: msg.metrics
};
// Publish to alert topic
return {
topic: `iot/alerts/${msg.deviceId}`,
payload: JSON.stringify(alert)
};
5. Add MQTT Out Node
- Connect to alert function
- Topic:
iot/alerts/{{deviceId}} - QoS: 1
- Retain: false
Complete Alert Flow
Alert Function Code
Here’s the complete alert function:
// Determine alert type and message
let alertType, alertMessage;
if (msg.metrics.batteryPct < 20) {
alertType = "battery_low";
alertMessage = `Battery low: ${msg.metrics.batteryPct}%`;
} else if (msg.metrics.temperatureC > 30) {
alertType = "temperature_high";
alertMessage = `Temperature high: ${msg.metrics.temperatureC}°C`;
} else {
return null; // No alert
}
// Create alert payload
const alert = {
deviceId: msg.deviceId,
timestamp: msg.ts,
type: alertType,
severity: "warning",
message: alertMessage,
metrics: msg.metrics
};
// Add alert metadata
msg.alertType = alertType;
msg.alertMessage = alertMessage;
msg.payload = JSON.stringify(alert);
return msg;
Test Alerts
- Battery Low: Wait for battery to drop below 20% (or modify simulator to start at 15%)
- Temperature High: Modify simulator to generate high temperatures
Subscribe to alerts:
mosquitto_sub -h localhost -p 1883 -t iot/alerts/+
Production Considerations
Here’s what you’d need for a real deployment:
1. Security
❌ Current (Dev Only):
- Anonymous access allowed
- No encryption
- No authentication
✅ Production:
- Username/password authentication
- TLS/SSL encryption (port 8883)
- Access Control Lists (ACLs) for topic permissions
- Certificate-based authentication for devices
Example Mosquitto config:
# Require authentication
allow_anonymous false
password_file /mosquitto/config/passwd
# TLS/SSL
listener 8883
cafile /mosquitto/config/ca.crt
certfile /mosquitto/config/server.crt
keyfile /mosquitto/config/server.key
2. Quality of Service (QoS)
When to use each:
- QoS 0: Sensor readings, non-critical data (fastest)
- QoS 1: Commands, alerts (guaranteed delivery)
- QoS 2: Critical state changes (exactly once, slower)
Current: We use QoS 1 for telemetry (good balance)
3. Retained Messages
Use for:
- Device state (last known value)
- Configuration
- Status updates
Don’t use for:
- High-frequency telemetry (wastes storage)
- Commands (shouldn’t be retained)
4. Last Will and Testament
Set a “last will” message when device connects:
client.will_set(
topic=f"iot/devices/{DEVICE_ID}/status",
payload='{"status":"offline"}',
qos=1,
retain=True
)
If device disconnects unexpectedly, broker publishes this message.
5. Message Persistence
For critical data:
- Use a database (InfluxDB, TimescaleDB)
- Store in Node-RED context (limited)
- Use MQTT broker persistence (limited)
6. Scalability
Current setup: Single broker, localhost
Production options:
- MQTT Broker Clusters: Multiple brokers
- Load Balancing: Distribute devices
- Cloud Services: AWS IoT Core, Azure IoT Hub, Google Cloud IoT
7. Monitoring
Monitor:
- Broker connections
- Message throughput
- Error rates
- Device connectivity
- Alert frequency
Troubleshooting
“Subscriber prints nothing”
- Check broker is running:
docker-compose ps - Check topic matches: Use
mosquitto_sub -vto see topics - Check simulator is publishing: Look for “Published message” logs
“Docker ports conflict”
- Change ports in
docker-compose.yml - Check what’s using ports:
lsof -i :1883
“Node-RED can’t connect to broker”
- Use
mosquittoas hostname (Docker network) - Or use
localhostif Node-RED runs outside Docker - Check broker logs:
docker-compose logs mosquitto
“JSON parse errors”
- Verify message format matches schema
- Check for extra characters
- Use
mosquitto_sub -vto see raw messages
“High CPU due to publish interval”
- Increase
PUBLISH_INTERVAL(e.g., 5 seconds) - Use QoS 0 for non-critical data
- Reduce message size
Next Steps
Now that you have a working system, here are ideas to extend it:
1. Replace Simulator with Real Hardware
- Use ESP32 or Raspberry Pi
- Connect real sensors (DHT22, BME280)
- Same MQTT code, different sensor reading
2. Store Telemetry in Database
- Add InfluxDB to Docker Compose
- Store all messages
- Query historical data
3. Add REST API
- Query latest device state
- Get historical data
- Trigger commands
4. Multi-Device Dashboard
- Show multiple devices
- Device selector dropdown
- Aggregate statistics
5. Advanced Alerts
- Email notifications
- Slack integration
- SMS alerts
Knowledge Check
Test your understanding:
Congratulations! 🎉
You’ve built a complete IoT digital twin system:
- ✅ MQTT broker running in Docker
- ✅ Python device simulator publishing telemetry
- ✅ Node-RED flow processing and validating data
- ✅ Real-time dashboard with gauges and charts
- ✅ Alert rules for battery and temperature
You now understand:
- How MQTT works
- How to design topics
- How to process IoT data
- How to build dashboards
- Production considerations
Wrap-up
This tutorial showed you a real IoT pattern used in production. The same concepts apply whether you’re using:
- AWS IoT Core
- Azure IoT Hub
- Google Cloud IoT
- Your own MQTT broker
The principles are the same: devices publish, brokers route, applications subscribe and process.
Keep experimenting, and happy building! 🚀