Five rules for home automation that won't ruin your day
Five rules any device should follow before it's allowed to flip a switch in your home. Lessons from an IoT automation that runs unattended for years.
A small device that lives next to your battery is allowed to turn off the water heater when the battery gets low. That sounds simple until you think about what can go wrong: a software bug that reads a stale voltage, a rule that fires because the time is wrong, a power blip that confuses the device into thinking the battery is empty when it isn’t. The customer doesn’t know any of that — they just know the water heater turned off at 2 PM on a Tuesday and now the kids can’t shower.
This post is about the five rules we wrote into the automation before any of it shipped to a customer’s home. None of them are smart. All of them are biased toward doing nothing.
What this gets you
- The master switch is off by default. You opt in to automation per install, not globally.
- Stale readings count as unknown. A rule that hasn’t seen a fresh battery frame in two minutes holds its last decision — it does not act on ghosts.
- Ties go to OFF. If two rules conflict, the device doesn’t pick a winner; it leaves the load alone.
- A human flipping the switch by hand pauses automation for that switch for half an hour. The device never fights the customer.
- Errors are swallowed. A failed network call, a malformed message, a transient Home Assistant outage — none of these are allowed to kill the device.
The constraint
A battery monitor that lives next to the inverter, talks to the battery over Bluetooth, and can also turn a smart plug off and on, is a small device with real-world consequences. A wrong action is a customer phone call. A wrong action that the customer can’t override is a service visit.
The standard software answer — “fail open” or “fail closed” — assumes a binary state the system can recover from. That doesn’t work when the wrong decision is a quiet one: turning a load off that shouldn’t have been turned off, or worse, not turning it off when it should have been.
So the rule isn’t “be careful”. The rule is: act as little as possible, and never act at all unless three conditions are simultaneously true.
The five invariants
1. The master switch is off by default
The device ships with automation disabled. It runs, it monitors the battery, it sends the data to the cloud, but it doesn’t touch any switch until a human turns automation on — for that install, with that battery, with that set of smart plugs.
This sounds small, but it inverts the failure model. When automation is off by default, “the device didn’t do anything” is the safe answer to “did anything go wrong?”. The customer has to actively decide to give the device permission to act. Until then, it’s a sensor, not a controller.
When you flip the master switch on, automation is per-device and per-install. There’s no global toggle in the cloud that turns on automation for every site at once.
2. Stale readings count as unknown
The battery sends a frame over Bluetooth about every second. The device listens, decodes the frame, and feeds it to the rule engine. What happens if the frames stop arriving — because the device lost the Bluetooth connection, because the battery was disconnected for a service window, because the radio is being noisy — and an old frame is still in memory?
Without a guard, the rule engine sees the same battery state for minutes. A rule that’s supposed to fire when state of charge drops below 30 % will look like it’s still waiting to fire. Worse: a rule that should turn a load back on when the battery recovers has nothing to recover from, because the “recovered” reading is just the last stale frame.
The invariant: if no fresh frame has arrived in two minutes, treat the reading as unknown. An unknown reading never satisfies a “must be below 30 %” rule. An unknown reading never satisfies a “must be above 60 %” rule either. Both rules hold. The load stays in whatever state it was in before. When the Bluetooth connection comes back, fresh readings resume and rules can act again.
This is the difference between “the device doesn’t know” and “the device thinks the battery is dead”. The first is safe. The second is a wrong action.
3. Ties go to OFF
The rule engine evaluates multiple rules per load: time-of-day, state of charge, presence of other loads, a manual override. Two rules can both want the same load to be on. Or one rule wants on and another wants off. Or both want off.
The naive design picks the highest-priority rule. The invariant design picks off when the result is a tie or an ambiguity.
Concretely: the engine computes, for each load, a set of {desired_on, rule_id} from all matching rules. If the set is non-empty, the rule with the highest priority wins, unless another matching rule is explicitly off. When in doubt, off.
A customer who set a manual schedule for “water heater on at 6 AM, off at 8 AM” gets exactly that. A second rule added later that says “off when battery is below 20 %” wins during a real battery emergency, but doesn’t override the morning schedule on a normal day because the morning rule wins priority. The two rules coexist. If the customer later deletes the morning rule, the off-on-battery rule still works on its own. The fallback is never a state the customer didn’t choose.
4. A human flip pauses automation for half an hour
If the customer walks past the smart plug and presses the button — turning the water heater back on after the device turned it off — the device does not immediately turn it off again. Automation is paused for that load for thirty minutes.
The reasoning is simple: the human had information the device didn’t. Maybe the battery recovered and the customer knows it. Maybe the customer is about to shower. Maybe the customer is testing the device. Whatever the reason, the human’s action wins for the next half hour. After that, automation resumes — if the rules still say off, the device turns it off again. If the rules now say on, the device leaves it alone.
This is the rule that prevents the most common complaint we hear from any home automation product: “the device keeps undoing what I’m doing”. It also gives the customer a way to override a bad rule without taking the device apart.
5. Errors are swallowed
The device runs as a single Python process. It depends on Bluetooth, on a Supabase HTTP call, on Home Assistant via MQTT, on the Tuya cloud API. Every one of those can fail in a way that’s not the device’s fault.
If the device crashes on a Supabase timeout, it doesn’t ship telemetry until it comes back. If the Home Assistant MQTT bridge fails on a malformed message, it logs the message and moves on. If a rule throws an exception because the rule data is malformed, the rule is skipped, not the entire engine.
The invariant: the device never dies because a dependency was momentarily unhappy. A rule that throws is logged and skipped for that evaluation cycle. A telemetry publish that fails is retried with exponential backoff. A Bluetooth error triggers a reconnect, not a process exit. A Home Assistant bridge that loses its broker reconnects on the next MQTT ping.
The device’s only acceptable steady state is: “I am running, I am monitoring, I am doing exactly what the rules say, and I am not going to die because of someone else’s bug.”
What this gets the customer
The customer doesn’t see these five rules. The customer sees: the water heater comes on at 6 AM and goes off at 8 AM every morning; when the battery is genuinely low, the heater goes off and comes back when the battery recovers; the customer can override any decision by pressing the button on the plug. When the customer’s internet goes down, the battery monitor still does its job. When the customer’s Home Assistant goes down, the battery monitor still does its job.
That’s the point. The five rules exist so the customer doesn’t have to think about the device. The device’s job is to be boring.
When this kind of discipline matters
A battery monitor is a low-stakes example. The same rules apply harder in:
- A device allowed to lock or unlock a door
- A device allowed to start or stop a medical device
- A device allowed to dispatch a service technician or call emergency services
- A device allowed to commit a financial transaction
In every one of those, the right default is the same: act as little as possible, and never act at all unless the system is sure. The five rules are not a battery-monitor pattern. They’re a pattern for any system that’s allowed to do things in someone else’s house.
Want a piece of hardware that runs unattended for years and stays boring? Book an intro call. We’ll tell you honestly whether we can help.