Blog / Build Your Own IoT Backend: IoTFlow, a Self-Hosted Platform with a Python SDK
Build Your Own IoT Backend: IoTFlow, a Self-Hosted Platform with a Python SDK
Short version: we built and open-sourced IoTFlow, a self-hosted IoT platform you can run on your own machine with one docker compose command. It gives you a managed MQTT broker, an HTTP telemetry endpoint, a real-time dashboard with charts and gauges, Blynk-style virtual pins for two-way device control, threshold alerts, and drag-and-drop automation via n8n. There is a pip install-able Python SDK, so a Raspberry Pi can be streaming sensor data in three lines of code. It is free, there is no device cap, and your data never leaves your infrastructure.
This post walks through why we built it, how the pieces fit together, a genuine end-to-end quickstart with the Python SDK, and where it fits if you are learning IoT properly rather than following a one-off tutorial.
Why self-hosted, and why now
Anyone who has taught an IoT class knows the pattern. The hardware side goes fine — a DHT22 on an ESP32 is a solved problem. Then you reach the cloud, and the friction starts: free tiers that cap you at a handful of devices, dashboards you cannot customise, data retention measured in days, and a platform that quietly changes its pricing between one cohort and the next. Learners end up debugging a vendor's onboarding wizard instead of learning IoT.
There is a second, more serious problem. In a lot of real deployments — a factory floor, a clinic, a building-management system — telemetry simply cannot be shipped to someone else's cloud. The question "where does this data physically live?" has a compliance answer, not a convenience answer. Once you have made that call, the useful skill is not "can you use vendor X's console", it is "can you stand up and operate an IoT backend yourself".
So we built the thing we wanted for teaching and for prototyping:
- Self-hosted and free. Docker and Coolify-ready. No vendor lock-in, no device cap, no per-message billing.
- Low-code where it should be. A dashboard you build by adding widgets, and automations you draw in n8n rather than write from scratch.
- Real code where it matters. A proper Python SDK and an Arduino/ESP library, so the device side is honest engineering rather than a drag-and-drop illusion.
- Two-way from the start. Sending sensor readings up is the easy half. Controlling a relay from your phone, reliably, is where most hobby projects fall over.
How IoTFlow is put together
The architecture is deliberately conventional — every layer is something you would meet again in a production system:
- Frontend — Next.js 16 with React 19 and TypeScript, styled with Tailwind. This is the dashboard, the device manager and the admin panel.
- Backend — Node.js API routes handling telemetry ingestion, device commands and automation triggers.
- Database — PostgreSQL through Prisma. Devices, telemetry history, users, projects and alert rules all live here.
- MQTT broker — Eclipse Mosquitto, the same broker used in production IoT estates worldwide.
- Ingestion worker — a separate Node service subscribed to device topics, so a burst of MQTT traffic never blocks the web UI.
- Automation engine — n8n webhooks, so an event on a device can fan out into email, a Telegram message, an HTTP call or an AI step without you writing glue code.
- Mobile — a native iOS app plus an installable PWA, because "check the sensor from my phone" is the first thing everyone asks for.
Two protocols are supported side by side, and the choice matters. HTTP is the simplest thing that works: a POST with a bearer token, no persistent connection, fine for a reading every 30 seconds and forgiving of flaky networks. MQTT is publish/subscribe over a long-lived connection — far lighter per message, much lower latency, and the only sane choice when you want a device to react to a command immediately rather than on its next poll. IoTFlow lets you start on HTTP and move to MQTT without changing your dashboard.
Quickstart: platform up in one command
The whole stack runs from a single compose file. On any machine with Docker installed:
git clone https://github.com/alfredang/iotplatform.git cd iotplatform docker compose up -d --build
That brings up the web app on http://localhost:3000 and the MQTT broker on port 1883. Seed the demo data so you have an account to log in with:
docker compose exec web npm run db:seed
The seed creates an admin login (admin@demo.io / password123) and a normal user (user@demo.io / password123). Change both before you expose the instance to anything. If you would rather point at a managed PostgreSQL — which is what we would recommend for anything long-lived — there is a plain Dockerfile path for that too, and migrations run automatically on startup either way. You can also try the hosted showcase at iot.tertiaryinfotech.com before installing anything.
Once you are in, create a project, add a device, and copy the device token it gives you. That token is what authenticates everything below.
The Python SDK
The SDK is the part we are most pleased with, because it collapses the boring parts of IoT into almost nothing. Install it with pip:
pip install iotflow # HTTP only — zero dependencies pip install "iotflow[mqtt]" # adds real-time MQTT (paho-mqtt)
The HTTP-only install has no dependencies at all, which matters more than it sounds on a Raspberry Pi Zero or a locked-down lab machine. If you cannot use pip, drop the single iotflow.py file next to your script and it works identically.
Sending telemetry
Three lines to get a reading into the dashboard:
from iotflow import IoTFlow
iot = IoTFlow("https://your-host", "dev_XXXX", "rpi-weather")
iot.send(temperature=22.5, humidity=60) Any keyword argument becomes a telemetry field, and the dashboard picks up new fields automatically — you do not declare a schema up front. To write a single named value, for example to drive one specific widget:
iot.virtual_write("temperature", 22.5) Switching to MQTT
Same object, different constructor arguments. Point it at the broker instead of the HTTP host:
iot = IoTFlow(token="dev_XXXX", device_id="rpi-weather",
mqtt_host="your-broker", mqtt_port=1883)
iot.connect()
iot.mqtt_publish(temperature=28.5, humidity=65) Under the hood that publishes JSON to devices/<deviceId>/telemetry. Nothing about your dashboard changes — the ingestion worker normalises both paths into the same telemetry store.
Receiving commands (the half everyone skips)
Virtual pins are the Blynk-style idea that makes two-way control simple: a dashboard widget writes to a named pin, the platform persists it and pushes it down to the device on devices/<deviceId>/down. On the Python side you register a handler:
@iot.on_command
def handle(pin, value, text):
if pin == "pump":
print("pump ->", value)
iot.run(interval=3) # HTTP: poll for commands every 3s
# or iot.loop_forever() # MQTT: real-time, no polling Add a button widget bound to the pin pump in the dashboard, press it on your phone, and the handler fires on the Pi. That is the entire control loop — no webhook server on the device, no port forwarding, no static IP.
Talking to it without the SDK
The SDK is a convenience, not a requirement — everything is a plain HTTP or MQTT call, which is worth knowing when you are debugging or working from a language with no SDK. Post a reading with curl:
curl -X POST https://your-host/api/telemetry
-H "Authorization: Bearer <DEVICE_TOKEN>"
-H "Content-Type: application/json"
-d '{"temperature": 28.5, "humidity": 65}' Or publish over MQTT straight from the command line:
mosquitto_pub -h localhost -t "devices/my-device/telemetry"
-m '{"token":"dev_xxx","temperature":28.5}' And drive a device from a server-side script or another system using an API key:
curl -X POST https://your-host/api/devices/<id>/command
-H "Authorization: Bearer iot_API_KEY"
-d '{"pin":"relay","value":1}' A build you can finish in an afternoon
Here is the project we use to tie the pieces together — a room monitor that also controls something. Every step maps onto a skill you would use again in a real deployment:
- Wire the sensor. A DHT22 (temperature and humidity) on an ESP32 or a Raspberry Pi. Confirm you can read it locally and print values before any network code exists — debugging sensor wiring and cloud connectivity at the same time is how afternoons disappear.
- Stream it up. Install the SDK, paste in your device token, and call
iot.send()in a loop. Watch the readings land in the dashboard live. - Build the dashboard. Add a number card for the current temperature, a chart for the last few hours, and a gauge for humidity. This is drag-and-drop; the point is choosing the right visualisation for each signal.
- Add control. Wire a relay to a fan or a lamp, register an
@iot.on_commandhandler for afanpin, and add a button widget. You now have two-way IoT. - Set an alert. Create a threshold rule — temperature above 30°C — and a device-offline rule so you find out when the Pi drops off the wifi rather than assuming the room is a steady 24°C forever.
- Automate the response. Draw an n8n flow triggered by the alert: send a Telegram message, log the event to a sheet, and switch the fan pin on automatically. This is the step that turns a monitoring project into an actual system.
- Put it on your phone. Install the PWA and check that the button still controls the relay from mobile data rather than your home wifi.
Finish that and you have touched sensors, wireless protocols, cloud ingestion, time-series storage, visualisation, alerting, two-way control and workflow automation — which is, not coincidentally, close to the full syllabus of an introductory IoT course.
Where the platform stops and the fundamentals start
A platform removes the tedious parts of IoT. It does not answer the questions that decide whether a deployment works:
- Which sensor, and how do you trust its readings? Accuracy, drift, calibration and sampling rate are engineering decisions no dashboard makes for you.
- Which wireless technology? Wi-Fi, BLE, LoRa, NB-IoT and Zigbee trade range against power against bandwidth. Pick wrong and you are changing batteries in ceiling sensors every three weeks.
- MQTT or REST, and why? Understanding QoS levels, retained messages, last-will and topic design is what separates a demo from something that survives a flaky network.
- How do you secure it? Device tokens, TLS, network segmentation, and what happens when a device is stolen. IoT security is the part that gets skipped and the part that ends up in the news.
- What does the data actually tell you? Storing telemetry is easy; turning it into a threshold that means something, or a trend worth acting on, is analysis.
That gap is exactly what a structured course is for — and it is why we point learners at the fundamentals rather than just handing them the platform.
Learn IoT properly — with funding
If this post made you want to build the thing rather than read about it, the direct route is WSQ Internet of Things (IoT) Fundamental for Beginners. It covers the same arc as the project above, with a trainer beside you when the sensor reads nan:
- Overview of IoT — what IoT actually is, sensors and actuators, the wireless technologies and how to choose between them, and real applications.
- Collect and post data to the cloud — cloud computing for IoT, collecting readings from sensors, transmitting with an ESP8266, and posting via MQTT or REST API.
- Read data and control devices remotely — reading back over MQTT or REST, and driving actuators from the cloud.
- IoT data analytics and visualisation — analysing and visualising telemetry, plus IoT security.
Because it is a WSQ course, the funding is substantial for eligible learners:
- Full fee $750 before GST.
- $442.50 nett for Singapore Citizens and PRs aged 21 and above (50% funded).
- $292.50 nett for Singapore Citizens aged 40 and above under MCES, and for eligible SMEs (70% funded).
- SkillsFuture Credit, PSEA and UTAP can offset the fee payable after funding, and employers can tap SFEC and claim Absentee Payroll.
Want a different entry point? WSQ Mastering Raspberry Pi if you want to go deep on the Pi itself, WSQ Hands-On Guide to IoT Development with Microcontrollers for the embedded side, WSQ Agentic AI Automation with n8n for the automation layer IoTFlow uses, or Agentic AI for IoT to put an AI agent on top of your telemetry. Browse the full WSQ IoT & Robotics courses and the IoT training listing for every option and the next available dates.
The platform itself is on GitHub at github.com/alfredang/iotplatform — clone it, break it, open an issue. It is genuinely free and it is genuinely ours, which means when something does not work in class we can fix it rather than file a support ticket.
Frequently asked questions
Is IoTFlow really free, and is there a device limit?
Yes on both counts. It is open-source and entirely self-hosted, so there are no paid tiers, no per-device charges and no per-message billing — your only cost is whatever you run it on, which can be a spare laptop or a small VPS. Because you own the deployment, the practical device limit is your own hardware rather than a plan.
Do I need to know Docker to run it?
Barely. If Docker is installed, docker compose up -d --build brings up the whole stack — web app, database, MQTT broker and ingestion worker — and database migrations run automatically on startup. Knowing Docker helps when you want to deploy it properly with an external PostgreSQL or put it behind a domain, but it is not needed to get to a working dashboard.
Should I use MQTT or HTTP for my project?
Start with HTTP if you are sending a reading every few seconds and can tolerate commands arriving on the next poll — it is simpler, needs no persistent connection and the Python SDK install has zero dependencies. Move to MQTT when you need low latency, real-time downlink control, or you are running on battery, since publish/subscribe over a long-lived connection uses far less power and bandwidth per message. The dashboard is identical either way, so switching later costs you a few lines.
What hardware do I need to follow along?
An ESP32 or ESP8266 board, or a Raspberry Pi, plus one sensor — a DHT22 for temperature and humidity is the usual starting point — and a relay module if you want to try the control half. That is well under S$50 of parts. The WSQ course supplies the hardware, so you can confirm you enjoy it before buying anything.
Do I need programming experience to take the WSQ IoT course?
No — it is a beginner-level course and starts from what IoT is, what sensors and actuators do, and how devices talk to a cloud. You should be comfortable using a computer and bring a laptop. If you have never written code at all, the Python and Arduino snippets in class are short and given to you rather than written from scratch.
How much will the WSQ IoT course cost me after funding?
The full fee is $750 before GST. Singapore Citizens and PRs aged 21 and above pay $442.50 nett after 50% funding, and Singapore Citizens aged 40 and above pay $292.50 nett under MCES (70% funding), as do eligible SMEs. You can then use SkillsFuture Credit, PSEA or UTAP to offset the amount payable, and employers can claim Absentee Payroll. Note that promo codes cannot be applied to WSQ courses.
View WSQ Internet of Things (IoT) Fundamental for Beginners — dates, funding and registration →