Personal
Tempestas
A multi-node greenhouse controller: sensors, relays and an automation loop driving lights, fans and a propane CO₂ generator.
- Role
- Sole developer
- When
- 2026 – present
- NestJS
- Angular 20
- PostgreSQL
- MQTT
- Python
- Raspberry Pi
- socket.io
Tempestas runs a working greenhouse. Its relays switch the grow lights, the exhaust fans and a propane CO₂ generator that doubles as the night heater — so a bug is not a broken page, it is a lost crop or a fire.
It replaces eight years of accumulated fixes on a single Raspberry Pi (Flask and Angular 16) with a multi-node design: a zone is an airspace and owns the rules, a node is a box of wiring, and a device is a relay on a node. Adding a sensor at the far end of the greenhouse becomes data, not code.
Engineering for something that can burn
- Safety rules are written down and enforced in code. Commands are never retained on the MQTT broker, so a reconnect cannot replay "burner on". A node that drops makes its pins unknown, not off. A missing CO₂ reading is treated as "unknown", never as zero.
- Publish first, persist on success. The old system logged a failed relay write and updated the database anyway, so the UI showed a heater running when it was not.
- Admission control. A new node is held as pending until approved; it cannot announce its way into controlling hardware.
- A closed-loop simulator. A fake hardware driver models temperature and CO₂ responding to the burner and fans, so the entire stack — rules included — is developed and tested with no Pi and no relays.
How it is built
An Nx monorepo: a NestJS API on PostgreSQL, an Angular dashboard with live updates over socket.io, a shared typed contract library, and a Python agent on each node talking MQTT. Decision logic is pure functions with time passed in, which is what makes the daylight-saving and cooldown boundaries testable to the second.