Project: an IoT monitoring system end to end
In short: This project joins sensors, networking, security and data into one working system. ESP32 boards measure temperature and humidity, publish over encrypted MQTT, and the readings land in InfluxDB and a Grafana dashboard that raises alerts, all on an isolated IoT network.
Goal and requirements
The goal is an end-to-end system you could deploy in a small server room, greenhouse or classroom: it collects readings every minute, stores them, shows trends and warns someone when a value goes out of range.
- Hardware: two or three ESP32 boards with DHT22 or BME280 sensors; a Raspberry Pi 4/5 or a small VM as the server.
- Software: Mosquitto, Telegraf or Node-RED, InfluxDB, Grafana, run with Docker Compose.
- Security: MQTT over TLS on port 8883 with a username and password per device, topic access control, IoT devices on their own VLAN.
- Reliability: devices reconnect after Wi-Fi or broker restarts; the dashboard shows when a sensor goes silent.
Design
Use a clear topic structure such as site/room/device/measurement, for example lab/server-room/esp32-01/temperature. Each device may only publish to its own branch; the ingest service may only subscribe. Put sensors on an IoT VLAN that can reach the broker on TCP 8883 and nothing else, following the IoT VLAN lab.
| Service | Port | Reachable from |
|---|---|---|
| Mosquitto (TLS) | 8883 | IoT VLAN, ingest service |
| InfluxDB | 8086 | Ingest and Grafana only (container network) |
| Grafana | 3000 (HTTPS via reverse proxy) | Admin VLAN only |
Build plan
- Bring up the broker with TLS and per-device users, following the MQTT TLS lab.
- Flash one ESP32 with code that reads the sensor and publishes JSON every 60 seconds, with the broker CA certificate embedded and Wi-Fi and MQTT credentials kept out of the public repository.
- Start InfluxDB, Grafana and Telegraf (MQTT consumer input, InfluxDB output) with Docker Compose.
- Build the dashboard: current values, 24-hour trends, and a "last seen" panel.
- Add alert rules, for example temperature above 27 degrees C for 5 minutes or no data for 10 minutes, sent by email or a chat webhook.
- Test failure cases: unplug a sensor, restart the broker, try a wrong password.
docker compose up -d
docker compose ps
mosquitto_sub -h broker.lab.example.com -p 8883 --cafile ca.crt -u ingest -P '<ingest-password>' -t 'lab/#' -v
mosquitto_pub -h broker.lab.example.com -p 8883 --cafile ca.crt -u esp32-01 -P '<device-password>' -t 'lab/server-room/esp32-01/temperature' -m '{"c": 23.4}'
mosquitto_pub -h broker.lab.example.com -p 1883 -t 'lab/test' -m 'plain'
docker compose logs -f telegraf
docker compose down
The plain-text publish on port 1883 should fail, proving that only TLS is accepted. A device that publishes to another device's topic should be refused by the access control list.
Deliverables and how to present it
- System diagram, topic map, port and VLAN table.
- Repository with Compose file, broker config (no real passwords), firmware source and a README.
- Screenshots of the dashboard and a fired alert, and a failure-test log.
- A short security review mapped to the OWASP IoT Top 10.
On a CV: "Built an end-to-end IoT monitoring system (ESP32, MQTT over TLS, InfluxDB, Grafana) with per-device authentication, topic ACLs and VLAN isolation." This project works well for final-year students because it is easy to demonstrate live and to evaluate with measurable results such as message delay and uptime.
Practice
Why give each sensor its own MQTT username?
How does the dashboard detect a dead sensor?
Why should InfluxDB not be reachable from the IoT VLAN?
Key takeaways
- Design the topic structure and access rules before writing code.
- Use MQTT over TLS with per-device credentials and ACLs.
- Isolate sensors on a VLAN that can reach only the broker.
- Alert on out-of-range values and on missing data.
- Test failures, then document results and security choices.
Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.