MQTT as the house's nervous system — one broker, every device
Works with Nest dying in the spring was the push. The plan it pushed me toward: make MQTT the primary nervous system of the house, not the side bus it's been since I stood up Mosquitto in 2018.
The thesis: if every device publishes to one broker I own, a vendor killing an API costs me one device's cloud features — not a tangle of cross-vendor automations.
The topic hierarchy
The single most important design decision in an MQTT house is the topic naming scheme. Get it right once; everything downstream gets easier. Mine, after a couple of false starts:
home/<area>/<device>/<property> → state (published by device) home/<area>/<device>/<property>/set → command (published by controller) home/kitchen/main_light/state on home/kitchen/main_light/state/set off home/livingroom/motion/occupancy detected home/frontdoor/contact/state open home/_presence/luke home home/_alarm/state disarmed
Rules I settled on:
<area>/<device>/<property>— readable, greppable, sorts sensibly.- State and command on separate topics (
/setsuffix). Never let a device's reported state and a command to change it collide on one topic — that way lies feedback loops. _-prefixed areas (_presence,_alarm) for virtual/house-level state that isn't tied to a physical room.
The bridge pattern
Not every device speaks MQTT natively. The job is to bridge each protocol island onto the bus:
| Source | Bridge | Result |
|---|---|---|
| Zigbee | deCONZ → MQTT bridge | Zigbee events on home/... |
| Z-Wave | Z-Wave → MQTT (zwave2mqtt) | Z-Wave events on home/... |
| Hue | Home Assistant → MQTT | Hue state mirrored to bus |
| Custom ESP sensors | native MQTT (they publish directly) | cheapest, cleanest path |
| Home Assistant | MQTT integration (two-way) | HA both publishes and subscribes |
Home Assistant sits on the bus like everything else — it subscribes for its dashboards and automations, and publishes commands. It's a participant, not the spine. If HA goes down for an upgrade, the bus keeps carrying messages and Node-RED keeps reacting.
The retained-message trick
The detail that made this feel solid: retained messages. Publish a device's state with the retain flag, and the broker holds the last value. Anything that subscribes later immediately gets the current state instead of waiting for the next change.
mosquitto_pub -t 'home/frontdoor/contact/state' -m 'closed' -r
So when Home Assistant restarts, it doesn't come up blind — it subscribes, and the broker immediately replays the retained state of every door, light, and sensor. The house's current state lives in the broker, durably, independent of any one application.
Why this is the day job in miniature
I keep noting this because it keeps being true: the architecture I'm building at home is the architecture I build at work for connected-device fleets. Devices publish telemetry to a broker. Services subscribe. Nobody's point-to-point wired. State is retained so a restarting consumer catches up instantly.
At work it's a managed broker, TLS mutual auth, a compliance auditor reading the topic ACLs. At home it's Mosquitto on a Pi. Same shape. The house is where I get to feel the architecture in my hands before I have to defend it in a design review.
Where the house stands now
- Logic: Home Assistant + Node-RED, local.
- Nervous system: MQTT, one broker, mine.
- Zigbee: deCONZ → bus. ✓
- Z-Wave: bridging onto the bus now — which finally gets it off the SmartThings hub as a side effect. ✓ (the migration I've deferred since 2017, done almost by accident).
- Cloud dependencies: shrinking to near-zero. A vendor API death is now a shrug, not a crisis.
What's next
Year-end review is due — and unlike the last two, 2019 ends with the local-first project essentially done. The closet runs the house. The cloud is optional. Now to write down how it held up, and whether the day job will finally let this journal speed back up in 2020.