Home Automation
This page is a short honest summary of what it is and the key decisions, not a full case study. Source status: private system: only a high-level description is safe to publish. Withheld: It can actuate physical home systems, so the code, the credentials, and the schedules stay private as a safety boundary; the dry-run-first design and the honest current state of each part are described here.
Three planners for irrigation, climate, and home energy, each dry-run by default with actuation behind two separate human confirmations, plus a read-only monitor over the solar hardware that was never given a way to write.
Four systems now, in two shapes. Three of them are planners: read the relevant signal (a weather forecast, a thermostat schedule, energy prices), compute a recommendation, log it, on a morning timer. None of them moves a valve, a thermostat, or a battery unless a human turns that one run into a real one, which takes a flag and an environment variable set by hand in the same command. The core decision was treating “never act on its own” as the design constraint from day one rather than a safety review bolted on afterwards: the planner and the actuator are two different code paths, and only one of them ever runs unattended. Switching the house on or off grid is the single recommendation with no actuation path at all, because the function that would do it is written to refuse.
The irrigation planner stopped asking whether rain is coming and started keeping a rolling soil-water balance for each zone: evapotranspiration out, rain and the water the zone actually received back in. A forecast can only describe tomorrow. The balance is what knows the ground is still wet from last week, which is the version of the question that skips a run correctly.
The fourth system is the opposite shape, and it exists because of something the other three could never have caught. Two of four solar strings sat disconnected on a clear afternoon while the array went on producing a perfectly plausible number, and a planner reading that number would have recommended the same thing either way. The monitor that came out of it is read-only by construction: it polls the hardware on the house network, diffs per-string state and the gateway’s own alert list against the last healthy baseline, raises an event on any change, and refuses to treat an already-broken array as the normal baseline on a first run.
What is not finished, stated plainly: only the irrigation planner reads live data. The climate scheduler has no thermostat brand wired to it and the energy dispatcher has no vendor token, so both still plan against sample fixtures every morning, and each run prints which one it read directly above the recommendation it produced. A dry run against a fixture proves the shape of the code and nothing whatsoever about this house.
The two systems reading live data each have a small web dashboard, and both stay on the private network behind a shared credential; the irrigation one additionally refuses any actuating request that arrives without a separate confirmation header, so a browser that merely logged in still cannot water anything. That dashboard produced the most reusable bug of the four as well: it kept going stale, and opening it to find out why was what made it stale.