Why this exists
I have never liked switches. The specific complaint is harder than it sounds: switches are state you have to manage, and a house has too many of them for any human to keep in their head. You walk into a room and check whether the light is on. You leave and check whether you turned it off. Every switch in every room is a tiny cognitive tax, and they add up.
The real unlock isn't “smart lights.” It is that state should follow people and time, not the other way around. The thermostat should know I go to bed around 11 and wake up around 6. The lights should know which room I'm in. The robot vacuum should know I just left the house. The cats' litter box should log every use and warn me three days before the cartridge is actually full.
None of that requires AI. It requires a few dozen sensors, a message bus, and a rules engine that has opinions about what “home” means in any given moment.
How it works
The house runs on a three-layer mesh: a sensor layer that tells the system what is happening, a coordination layer that holds state and rules, and an actuator layer that makes things happen. Everything communicates over a local MQTT broker so nothing depends on a third-party cloud being up.
Rough topology. Arrows are MQTT topic flows; dotted arrows are local HTTP calls for stateful queries.
The coordination layer is Home Assistant running on a mini-PC in the utility closet. That one box holds integrations for every vendor protocol I touch — Zigbee (via a USB coordinator), Matter-over-Thread (via a border router), Wi-Fi devices that speak their own APIs, and a handful of cloud pollers that bridge Nest, Roborock, and the cats' Litter-Robot. The mini-PC is not special; it is an old Intel NUC with 16GB of RAM and an SSD. It doesn't work very hard.
The interesting part is the rules layer sitting on top of it. Most of the actual logic lives in Node-RED flows and a short list of Python scripts that subscribe to MQTT topics. Rules aren't “at 9pm turn off the lights” — they are small functions with named preconditions like house_is_empty(), someone_asleep(), cooking_detected(), and storm_incoming(). Every flow chains preconditions instead of hardcoding time windows.
The zones model
The single biggest upgrade over generic home automation was giving up on rooms. Rooms are a terrible unit of automation because rooms don't care whether anyone is in them. The house is modeled as zones, where a zone is a set of rooms plus a set of states that matter for those rooms at the same time.
morning_routinedeep_workwind_downhouse_asleephouse_emptyZones changed everything. A zone like morning_routineis “kitchen + hallway + bathroom, between 5:45am and 7:30am, when at least one adult is present.” The state of that zone determines what happens across three rooms in lockstep. No more writing separate automations per room that have to coordinate with each other through flags and timers.
Under the hood, zones are just pub/sub topics on the MQTT broker. A zone's state is whatever the last message on its topic said. Rules subscribe. Subscribers react. The whole system is a fraction of the code I'd need if I were chaining individual automations through Home Assistant's UI, and it's much easier to reason about because any zone's behavior is documented in a single file.
The cat-litter canary
The single most-loved feature in this house is not the lights or the thermostat. It's that I get a push notification three days before the cats' litter cartridge fills up, based on a sliding-window average of how often it has been cycling. The Litter-Robot exposes cycle count through its app, and the app has an undocumented local API if you sniff the traffic. A small Python daemon polls it every 15 minutes, writes the cycle-count delta to InfluxDB, and fires an MQTT event when the moving average crosses a threshold.
This one rule is responsible for a larger quality-of-life improvement than any other automation in the house. The observation underneath is the general one: if you can measure anything continuously, the interesting signal is usually not the value but the derivative. Cycles per day matters less than whether cycles per day is trending up. Thermostat temperature matters less than whether the thermostat is drifting faster than it should given the outside conditions (leak in the weatherseal, typically).
Presence detection without the creepy stuff
The ugliest part of most “smart homes” is the presence detection. Vendors want you to install cameras, carry beacons, or let their cloud track your phone's location continuously. I didn't want any of that.
What I do instead: a combination of three signal sources, all local, none of which care who you are individually — only whether someone is present.
- mmWave presence sensors (LD2410-based, about $15 each) in every main room. These detect chest movement and breathing and are significantly more accurate than PIR sensors — they hold presence state correctly even when you sit still on the couch reading for an hour.
- BLE room-level presence using ESPresense nodes. Phones and watches leak enough Bluetooth traffic that a mesh of cheap ESP32 boards can triangulate which room a device is in without ever identifying the device.
- Door sensors on every exterior door, cross-referenced with the two signals above. If the door opened and mmWave lost everyone inside, house becomes empty. If the door opened and mmWave gained a presence, house becomes occupied.
All three run on the LAN. None of them talk to a cloud. None of them store identity. The question the house asks is “is the kitchen occupied,” not “who is in the kitchen,” and that turns out to be enough for every rule I've ever wanted to write.
What I’d do differently
I spent about six months trying to make everything talk directly to everything. Zigbee devices were supposed to talk to the robot vacuum, which was supposed to talk to the thermostat, which was supposed to talk to the lights. It was a rat's nest. I rebuilt it all on a single MQTT broker with strict topic naming (home/<zone>/<device>/<metric>) and the system has been stable for two years.
The lesson generalizes: one message bus beats N² point-to-point integrations, every time. Whether you're wiring up a house or an enterprise architecture, the second you have more than five things that need to exchange state, pay the upfront cost of a proper bus and you will save yourself months.
What’s next
The next project is anomaly detectionon the two years of MQTT data I've accumulated. Every sensor reading, every actuator command, every zone transition is timestamped in InfluxDB. I want a small model that watches the river of events and fires when it sees a combination that doesn't match any pattern it's seen before — “dishwasher running at 3am when the house is empty” is a signal I want, even if I can't enumerate all the rules in advance.
That's the honest endgame of “home automation.” Not controlling things. Noticing things.