IoT Monitoring System

Build an IoT monitoring system with a Raspberry Pi. Collect sensor data, visualize it on a dashboard, and set up alerts.

Andreas · April 12, 2026 · 9 min read

Introduction

An MQTT-based IoT monitoring system is the scalable way to aggregate sensor data from multiple Raspberry Pis or devices. MQTT brokers are lightweight, support pub/sub messaging, and integrate seamlessly with InfluxDB and Grafana. This architecture handles single sensors to hundreds of devices.

Architecture Overview

Sensors publish to a Mosquitto MQTT broker. The broker distributes messages. Telegraf subscribes to topics and writes to InfluxDB. Grafana queries InfluxDB and displays dashboards. You can add alerts, webhooks, and automation at any layer.

Temp Sensor (Pi 1) \
Humidity Sensor (Pi 2) --[Mosquitto MQTT]--[Telegraf]--[InfluxDB]--[Grafana]
Light Sensor (Pi 3) /

Prerequisites

  • Raspberry Pi 4/5 with 2GB+ RAM
  • Docker and Docker Compose
  • Python 3.9+
  • pip install paho-mqtt
  • Optional: additional Pis with sensors (DHT22, BMP280, light sensors)

Step 1 — Deploy MQTT Broker (Mosquitto) with Docker Compose

Create docker-compose.yml:

version: "3.8"
services:
  mosquitto:
    image: eclipse-mosquitto:latest
    container_name: mosquitto
    ports:
      - "1883:1883"
      - "9001:9001"
    volumes:
      - ./mosquitto.conf:/mosquitto/config/mosquitto.conf
      - mosquitto_data:/mosquitto/data
      - mosquitto_logs:/mosquitto/log
    restart: unless-stopped

  influxdb:
    image: influxdb:2.7-alpine
    container_name: influxdb
    ports:
      - "8086:8086"
    environment:
      INFLUXDB_DB: iot
      INFLUXDB_ADMIN_USER: admin
      INFLUXDB_ADMIN_PASSWORD: homelab123
    volumes:
      - influxdb_data:/var/lib/influxdb2
    restart: unless-stopped

  telegraf:
    image: telegraf:latest
    container_name: telegraf
    volumes:
      - ./telegraf.conf:/etc/telegraf/telegraf.conf
    depends_on:
      - mosquitto
      - influxdb
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin
    volumes:
      - grafana_data:/var/lib/grafana
    depends_on:
      - influxdb
    restart: unless-stopped

volumes:
  mosquitto_data:
  mosquitto_logs:
  influxdb_data:
  grafana_data:

Create mosquitto.conf:

listener 1883
protocol mqtt
allow_anonymous true

listener 9001
protocol websockets
allow_anonymous true

Start the stack:

docker-compose up -d

Verify MQTT is running:

docker exec mosquitto mosquitto_sub -t '$SYS/#' | head -5

Step 2 — Create Telegraf MQTT Subscriber Config

Create telegraf.conf:

[global_tags]
  environment = "homelab"

[agent]
  interval = "10s"
  round_interval = true
  flush_interval = "10s"

[[inputs.mqtt_consumer]]
  servers = ["tcp://mosquitto:1883"]
  topics = [
    "sensors/temperature/#",
    "sensors/humidity/#",
    "sensors/light/#"
  ]
  data_format = "json"
  name_override = "sensor_reading"

[[outputs.influxdb_v2]]
  urls = ["http://influxdb:8086"]
  token = "admin"
  organization = "homelab"
  bucket = "iot"

Step 3 — Python MQTT Publisher for Sensors

Create mqtt_publisher.py to send sensor data:

import paho.mqtt.client as mqtt
import json
import time
import random
from datetime import datetime

# MQTT broker
broker = "localhost"
port = 1883
client = mqtt.Client()

def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("Connected to MQTT broker")
    else:
        print(f"Failed to connect, return code {rc}")

client.on_connect = on_connect
client.connect(broker, port, keepalive=60)
client.loop_start()

def publish_sensor(location, sensor_type, value):
    topic = f"sensors/{sensor_type}/{location}"
    payload = json.dumps({
        "timestamp": datetime.now().isoformat(),
        "value": value,
        "unit": "celsius" if sensor_type == "temperature" else "percent" if sensor_type == "humidity" else "lux"
    })
    client.publish(topic, payload)
    print(f"Published to {topic}: {value}")

try:
    while True:
        # Simulate multiple sensors from different locations
        locations = ["living_room", "bedroom", "kitchen", "garage"]
        
        for location in locations:
            # Temperature: 15-28°C with noise
            temp = 20 + random.gauss(0, 2)
            publish_sensor(location, "temperature", round(temp, 1))
            
            # Humidity: 30-70% with noise
            humidity = 50 + random.gauss(0, 5)
            publish_sensor(location, "humidity", max(0, min(100, round(humidity, 1))))
            
            # Light: 0-1000 lux
            light = random.uniform(0, 1000)
            publish_sensor(location, "light", round(light, 0))
        
        time.sleep(60)  # Publish every minute

except KeyboardInterrupt:
    print("\nShutdown")
    client.loop_stop()
    client.disconnect()

Install the MQTT client:

pip3 install paho-mqtt

Run it:

python3 mqtt_publisher.py

You should see messages published every 60 seconds.

Step 4 — Verify Data Flow

Check that data is flowing to InfluxDB:

curl -G http://localhost:8086/api/v2/query \
  -H "Authorization: Token admin" \
  -d "db=iot" | jq .

Or use the InfluxDB UI at http://localhost:8086.

Step 5 — Create Grafana Dashboards

Open http://localhost:3000 (login: admin/admin).

Add InfluxDB data source:

  • URL: http://influxdb:8086
  • Organization: homelab
  • Token: admin
  • Bucket: iot

Create panels:

  1. Temperature by Location — Line graph, group by location
  2. Humidity Gauge — Gauge panel showing current humidity
  3. Light Levels — Bar chart of lux by location
  4. All Metrics Table — Table showing latest values

Example Flux query for temperature:

from(bucket: "iot")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "sensor_reading" and r._field == "value")
  |> filter(fn: (r) => contains(value: r.topic, str: "temperature"))
  |> group(columns: ["location"])

Step 6 — Add Alerting Rules

In Grafana:

  1. Create an alert rule on the temperature panel
  2. Set threshold: temp > 28°C
  3. For: 5 minutes (avoid false triggers)
  4. Notify via email or webhook

Configure webhook to call a Lambda, call Home Assistant, or send a Slack message.

Troubleshooting

Data not appearing in InfluxDB — Check Telegraf logs: docker logs telegraf. Verify MQTT broker connectivity with mosquitto_sub -h localhost -t 'sensors/#'.

Connection refused on port 1883 — Ensure Mosquitto container is running: docker ps | grep mosquitto. Check firewall: sudo ufw allow 1883 if using UFW.

Telegraf crashing with auth error — The InfluxDB token and org must match. In telegraf.conf, use token = "admin" for v2 API. If using InfluxDB v1, switch the output plugin to [[outputs.influxdb]] instead.

Duplicate data — Each sensor should publish to unique topic like sensors/temperature/location1, sensors/temperature/location2. Avoid publishing to the same topic from multiple sources without unique identifiers.

Summary

An MQTT-based system scales easily. Start with one Pi publishing temperature and humidity. Add light sensors, motion detectors, or door sensors as separate publishers. The broker and Telegraf handle the aggregation. Grafana provides real-time visibility and alerting. From here, integrate with Home Assistant, automate based on sensor thresholds, or archive data to long-term storage.

Comments