← All work

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.