← All work

Case study

Evidence-driven home automation

A deterministic climate controller with the governance visible: profile-based control with interlocks and fail-safes, a power-verified air-quality loop, and a joined sleep/environment analysis that declines to overclaim.Home heating and cooling run by fixed, predictable rules rather than by an AI guessing: different settings for day and night, safety cut-outs, and a fan that is checked by the electricity it draws rather than trusted to have obeyed. Afterwards I measured whether it actually improved my sleep, and published the honest answer.

Maturity: Operational
MaturityOperational
TopicsDeterministic automation · Time-series analytics · Verification
TechnologiesHome Assistant · Airthings telemetry · PostgreSQL analytics
Reading levelSame figures at both levels.

Problem

Home climate control fails in quiet, compounding ways. A thermostat controls to its own location, so a bedroom two and a half degrees warmer than the hallway stays warm all night with the system reporting success. Heating and cooling run while a window stands open. Night needs different behaviour than day, and air quality — CO2 and VOC — needs a response path of its own.

Home heating and cooling goes wrong quietly. A thermostat only measures the spot it is mounted on, so a bedroom two and a half degrees warmer than the hallway stays too warm all night while the system happily reports success. The heating runs with a window open. Night needs to behave differently from day. And air quality — stuffiness and household fumes — needs its own way of being dealt with entirely.

Underneath sits a harder question: after building the automation, did it actually help? Answering that honestly means joining data from two independent systems — wearable sleep records and bedroom telemetry — without letting enthusiasm write the conclusion.

Underneath all that sits a harder question: once it was built, did it actually help me? Answering that honestly meant lining up two completely separate sources of data — what my watch recorded about my sleep, and what the bedroom sensors recorded about the room — and not letting my own enthusiasm decide the answer.

Constraints

In plain terms first: the part that actually commands the heating follows fixed rules I can read, not an AI’s judgement; only one thing is allowed to talk to the thermostat; and when the system is unsure it does nothing and says why, rather than guessing. The precise ground rules:

  • Deterministic logic only in the control loop. AI assists design and analysis; it does not command HVAC. Prediction-driven control stays in shadow mode until proven.
  • One writer to the thermostat, speaking only commands the device actually supports — logical intent maps through a capability adapter, never guessed service values.
  • When a required input is unavailable, the controller sends no command at all and logs why: fail-safe means doing nothing, loudly.
  • Actuation is verified by measurement, not assumed from a sent command.
  • Sleep measurements on this page appear as directions only — this page publishes no exact physiology values. Environmental aggregates and pipeline counts appear exactly.

Architecture

The climate controller runs profile-based decisions — day, sleep, and deep sleep, each with its own target and deadband:

The controller works from three named modes — day, sleep, and deep sleep — each with its own target temperature and its own tolerance before it acts:

  • Controls to the bedroom’s own temperature at night, compensating for the thermostat’s location bias.
  • Bounded compensation — half the room error, capped at a configurable maximum, step-limited per command, rate-limited by a command-interval timer.
  • Window interlock — HVAC forced off two minutes after a window opens; resumes five minutes after it closes.
  • Independent guardrail — caps the humidifier and shuts it off after sustained high indoor humidity.

The air-quality loop is separate by design:

Air quality is handled by a completely separate mechanism, on purpose:

  • Trigger — sustained CO2 or VOC elevation, five minutes over threshold.
  • Power-verified actuation — turn on the smart plug, check wattage, send the fan’s IR command only if power stays low, confirm again.
  • OFF path — both metrics below their clear thresholds, re-checked on a 15-minute heartbeat, with a hard-fallback plug cutoff for a fan that ignores its IR command.
  • Context — fourteen-day same-clock-hour baselines, recomputed hourly from recorder statistics.
Two deterministic control loops with shared telemetry and analysis Sensors and context feed a profile decision engine with deadbands, bounded compensation, a window interlock, and a fail-safe. It commands the thermostat through a capability adapter. A separate air-quality loop takes sustained CO2 and VOC triggers through a power-verified actuator sequence to the fan. Both loops write to a decision log and dashboard, and a nightly joined analysis feeds evidence back into target tuning. Sensors & context room temps · occupancy · windows Profile decision engine deadbands · bounded bias · interlock · fail-safe Capability adapter single writer → thermostat CO2 / VOC triggers sustained 5 min · hourly baselines Power-verified actuation plug + IR · wattage checks · hard fallback Bedroom fan both-clear OFF · heartbeat Decision log · dashboard · nightly joined analysis every decision explained · evidence feeds tuning evidence-driven tuning
Recreated diagram. Device and entity names are withheld.

The hardware doing the work here is deliberately unimpressive, and that is the interesting part — the intelligence is in the arrangement, not the devices:

The air-quality actuator is deliberately humble hardware, arranged carefully. The fan is a Dyson AM05, and it is not a smart device in any sense: no Wi-Fi, no app, no cloud account, no API. It takes input two ways only — the buttons on the unit, or its infrared remote — and it reports nothing back through either. Automating it means starting from an appliance that cannot be asked a single question. The infrared is replayed by a universal IR remote, and infrared is fire-and-forget: nothing ever confirms the fan heard a command. So the loop closes electrically instead. The fan draws mains power through a power-monitoring plug, and wattage is the evidence — roughly 18 W means running, near zero means not — checked before an IR command is sent and confirmed after. The same plug is the hard fallback: a fan that ignores its remote gets its power cut. An Airthings monitor supplies the CO2 and VOC readings that drive the loop.

The air-quality device chain: sensing, infrared command, electrical verification An Airthings monitor supplies CO2 and VOC readings to the air-quality loop. The loop commands a universal IR remote, which replays fire-and-forget infrared pulses at a Dyson AM05 fan, which has no smart features at all — no Wi-Fi, no app, no API — and accepts input only from its remote or its own buttons. The fan draws mains power through a power-monitoring plug; the plug's wattage feeds back to the loop as evidence that the fan actually runs, and the plug doubles as the hard cutoff. Airthings monitor CO2 · VOC readings Air-quality loop trigger · decision Universal IR remote fire-and-forget pulses Dyson AM05 fan no Wi-Fi/app/API — IR + buttons Power-monitoring plug ~18 W = running · hard cutoff mains wattage evidence
Recreated diagram. The fan is verified by what it draws, not by what it was told.
Bedroom view of the live climate dashboard: air-quality overview tiles, the infrared command pad for the fan, power-monitor tiles reporting live wattage, and a 24-hour electrical-draw chart showing a sustained overnight run
The same chain on the live dashboard, captured 12 August 2026: the readings that trigger the loop, the IR command pad, and the wattage evidence — the dashboard's own notes state the ~18 W verification rule, and the 24-hour draw chart shows a real overnight run ending near zero.

AI and agent workflow

AI sits deliberately outside the control loop and does two other jobs:

AI is deliberately kept outside the part that commands the heating. It does two other jobs instead:

  • Analysis — agent sessions built the exploratory joined profile of sleep and bedroom environment, then converted it into a durable two-layer artifact: a frozen interpretation layer plus nightly-refreshed features from version-pinned SQL views, so a metric’s definition cannot drift silently under the narrative written about it.
  • Evidence-driven iteration — the analysis showed CO2 never reached its trigger during sleep windows, and the trigger was subsequently lowered from 1,000 to 900 ppm, recorded as an intervention boundary so future comparisons stay clean.

The one place AI could command hardware — prediction-driven cooling from wearable sleep staging — is explicitly held in shadow mode. Real-time sleep prediction is not yet reliable enough for a closed loop, and the system says so rather than pretending otherwise.

There is one place AI could plausibly take the controls — cooling the room based on predicting what stage of sleep I am in — and it is deliberately left switched off, running only as a silent rehearsal. Predicting sleep in real time is not yet reliable enough to trust with the hardware, and the system admits that rather than pretending otherwise.

Human governance

Where I stay in control, and how the system stays answerable to me:

  • Operator-set, not hard-coded — targets, deadbands, compensation limits, and sleep windows all come from the dashboard.
  • Every decision explains itself — a human-readable reason and the active profile go to the log; the system can always answer “why did you do that?” from its own records.
  • Governed cutover — the new controller ran in shadow mode first, logging what it would have done, and the legacy controller was disabled at ownership flip so two automations could never fight over the thermostat.
  • Manual hold honoured — corrections suspend until the hold expires or a profile transition clears it.
  • Honest records — when the fan stuck on for 41 hours, the episode was documented and the analysis re-run without it. The evidence was kept, not deleted.

Evidence

The joined analysis is quantified end to end:

The analysis that lined up sleep records against room readings is counted and stated in full, not summarised:

  • Scale — 1,806 canonical sleep episodes reaching back to 2017, 684,580 raw heart-rate points, 4,857 materialized sleep-window buckets; source reconciliation between the two upstream systems is quantified, not assumed.
  • Joins — bedroom hourly statistics join each sleep window weighted by overlap.
  • Disciplined comparison — equal-length adjacent windows around each automation’s start, a device-lineage cutover rule (the fan’s power monitor previously metered a different appliance, so earlier readings are excluded), and an anomaly-sensitivity re-run.

Sleep physiology appears on this page as directions only; this page shows directions, not values, by design. Environmental aggregates and coverage counts are exact.

Outcome

  • The bedroom measurably changed: matched nights were about 1.05 °C cooler after the climate controller took over — a large standardized effect — and VOC fell materially (mean −132 ppb, peaks −401 ppb). CO2 never reached the 1,000 ppm trigger during any aligned sleep window (highest hourly maximum: 962 ppm).
  • The sleep response is honestly mixed: a small efficiency gain and a moderate reduction in awake minutes, but deep-sleep share stayed flat and the heart-rate signal did not survive the anomaly-sensitivity re-run. The published verdict: a sleep benefit is plausible, but not proven — the two automations started one day apart and cannot be separated yet.
  • The controller and air-quality loop have run as the operational owners of their domains since cutover, with the interlock, fail-safe, and guardrail paths exercised in live operation.
  • One evidence-driven tuning change has already landed, with its boundary recorded for clean future comparison.

Lessons

What I would carry into the next system of this kind:

  • Put determinism in the loop and intelligence around it: the controller is boring on purpose, and the analysis is where the sophistication lives.
  • Verify actuation by measurement — a sent command is a hope, a wattage reading is a fact.
  • Fail-safe means doing nothing, loudly: refusing to act on missing inputs and logging why beats guessing.
  • An honest “plausible, but not proven” is worth more than an impressive claim that would not survive its own sensitivity analysis.