A whole-house automation setup lives or dies on how it’s organized, not on how clever any single automation is. Mine runs on a few dozen YAML packages, a handful of custom blueprints, a calendar integration that turns schedules into routines, and a voice pipeline that speaks in every room. This page is the architecture: how the configuration is split, what the blueprints abstract, and where a strict deterministic core earns its boring reliability.
The through-line is a two-part discipline. Repeatable patterns become blueprints instead of copy-pasted automations, and every rule in the deterministic plane is written to fail safe. Those two choices are why the house keeps working while I’m not looking at it.
Configuration as packages
Everything lives in Home Assistant’s package system. Instead of one sprawling configuration file, each functional domain gets its own YAML file — lighting, climate, presence, sleep, and so on. A domain’s helpers, automations, and scripts live together in that one file, so changing how lighting behaves means opening one place, not grepping a monolith. When a room diverges enough from the defaults, it gets its own override file rather than a pile of conditionals bolted onto the shared one.
Blueprints over copy-paste
On top of packages sit blueprints — parameterized templates for the patterns that repeat across rooms. Presence-activated lighting, air-purifier control, HVAC management, alert state machines, reminders, person tracking: each is one blueprint, instantiated per room with a few inputs. Adding a room to the lighting system means supplying parameters, not copying and editing a fifty-line automation. The edge cases get solved once, in the blueprint, and every instance inherits the fix.
One guard rides on every state trigger, and it’s load-bearing. Each trigger excludes transitions from unknown and unavailable. Template reloads briefly push sensors through those non-values, and without the guard, every automation would fire spuriously on every reload. It’s a small rule that turns a jittery system into a quiet one.
Presence is the foundation
Room-level presence is what every targeted automation reads. It fuses three signals: GPS from phones for home-versus-away, a Bluetooth Low Energy layer for which room someone’s in, and the calendar for where a person is supposed to be. The BLE layer needs no dedicated beacon network — every phone is a beacon, and ordinary smart plugs, reflashed as receivers, do the sensing.
The calendar signal matters more than it sounds. A scheduled event during its hours can set a synthetic “away” state even when the BLE tracker still sees the phone nearby — useful when someone’s location and their obligation disagree. Each person exposes a single entity naming their current room. The voice system reads it to route announcements; the climate blueprints read it to drive per-room setpoints; the lighting reads it to decide whether to turn on at all. Presence also feeds the security system and decides where each notification lands.
Circadian lighting
Lighting is presence-activated and time-of-day-aware. One blueprint runs in every room, taking presence sensors, indoor and outdoor light levels, main and accent lights, and a brightness-and-color-temperature curve driven by the time of day. A single house-wide phase — morning, day, evening, wind-down, night — is tracked in one selector helper, and one automation manages the transitions through a priority cascade: sleep state wins, then wind-down, then evening once it’s both late enough and dark enough, then a post-wake morning window, then the default day phase.
Why time and sun, rather than sun alone? In winter the sun can set hours before the workday ends. Letting indoor light follow the sun would drop the house into “evening” while everyone’s still working — actively bad for mood and focus in the dark months. So indoor lighting holds in “day” until a configured evening time, while outdoor accents follow the sun. The phase is the dial that lets those two decouple. Because it’s a plain selector, any dashboard, voice command, or automation can override it, and the cascade picks the next natural transition back up.
Climate and air quality
Each room with a networked HVAC unit runs its own instance of an HVAC-manager blueprint. The blueprint weighs target temperature, humidity, window state, outdoor conditions, and occupancy. It also rate-limits itself: the units run small embedded web servers, and without a guard the system would flood them with requests and knock them offline periodically. The blueprint knows not to change a setpoint while someone’s asleep, and it lowers setpoints during extended absences — again reading the calendar.
Air quality gets its own logic. A basement radon monitor trips a critical alert at the standard action threshold and overrides ventilation to pull in fresh air. Bedroom CO2 sensors feed sleep-quality metrics and prompt a window-open suggestion when levels climb overnight. Particulate and VOC readings drive per-room air purifiers, which follow the same blueprint pattern — fan speed tracks the particulate reading and eases off during sleep hours.
Sleep orchestration
Sleep is a single master switch that flips the house into night mode, and the switch runs a sequenced routine. Shutters close a beat apart rather than all at once — the shutter transceiver is one-way, and firing them simultaneously collides on the radio. Lights go off, but filtered: reading lights and a few accent segments stay on so late reading isn’t interrupted. The house secures itself for the night, the next wake-up time is evaluated and announced, and a one-time prompt offers to warm the beds.
Any single room can trigger the routine on its own when one person heads up early. Do Not Disturb is composed, not hard-coded: each room combines a manual toggle with “asleep for at least a set delay,” so an accidental tap doesn’t instantly silence a room. The voice system and the climate blueprints both read those Do Not Disturb sensors — quiet means no announcements and no setpoint changes that might wake someone.
The alert stack
The house runs a purpose-built alert system for anything that needs a human’s attention. It’s one blueprint, instantiated dozens of times, and each instance runs a three-state machine: active fires notifications on a repeat interval, acknowledged silences them but keeps the alert open, and resolved sends a single all-clear. A companion blueprint turns a numeric reading into a binary alert with hysteresis, so a value hovering at its threshold doesn’t flap the alert on and off.
What makes the stack trustworthy is that it watches itself. An alert can name the sensors it depends on, and if one of them goes unavailable, the blueprint raises a separate health warning — a dead battery or a dropped sensor is never silent. And because each alert’s state lives in a helper entity rather than in memory, the whole stack survives a restart with its acknowledgments intact.
Calendar as configuration
Calendar events are data, but they’re also a configuration surface. A bespoke integration owns the pipeline from an event to a leave time: it reads the calendar, parses hashtags out of the event text, and computes when to depart. The hashtags are a small language written right into the event — travel mode, routing preferences, an arrival buffer, an explicit wake-up time, a packing list read aloud in the reminder. Per-person defaults fill in the gaps, so an untagged event still produces a sensible route.
The same surface drives the morning alarm. When a bedroom enters sleep mode, a script queries tomorrow’s events across every calendar and, for each timed morning event, works backward from the start time — subtracting a travel estimate and a prep buffer — to a wake time. It takes the earliest across all qualifying events, and a tagged wake-up time overrides the computation. Nothing on the calendar means no alarm — there’s no weekday heuristic to get wrong — and because the evaluation reruns each night, there’s no stale alarm state to manage.
The voice pipeline
The house talks, and it does it through two layers. The first is a conversational announcement flow built on Home Assistant’s voice assistant. You say something like “announce dinner’s ready to everyone” or “tell the kitchen the laundry’s done.” A resolver script parses the target — a person, a room, a floor, or everyone — into concrete speakers. A generation step rewrites the raw request into a friendly, tone-appropriate line. The system speaks it back to you and waits: confirm and it goes out, cancel and it’s dropped, ask again and it retries, and a timeout auto-cancels so a forgotten confirmation never leaves an announcement hanging.
Underneath sits a bespoke text-to-speech engine that replaced a generic wrapper to fix three concrete problems. It streams audio from a generative TTS model with a per-chunk timeout instead of one monolithic deadline, so a slow long message doesn’t time out as long as data keeps arriving. It skips lossy re-encoding entirely — the speakers take the native audio format directly. And it caches by a deterministic hash of the message, voice, and model, with a time-to-live cleanup, so one-off announcements expire while stable phrases persist and replay instantly.
Delivery is person-aware and quiet-aware. Hand the engine a person and it resolves their current room through the presence layer, then plays to the right speaker; anyone away or asleep is skipped, and Do Not Disturb is checked before a single word plays. It also waits for a natural gap between tracks when music’s already playing, rather than ducking mid-song — a small courtesy that makes the whole thing feel less like a PA system and more like part of the house.
Design philosophy
Two principles hold all of this together.
Blueprints over copy-paste. Any pattern that shows up in more than a couple of rooms becomes a blueprint. The blueprint absorbs the edge cases once; the instances just supply parameters. Copy-paste automations rot independently — blueprints get fixed in one place.
Bespoke at the edges, open source at the core. Home Assistant itself, the speaker drivers, the presence layer, the alarm, the database — all of that stays firmly open source. The purpose-built pieces are the thin glue at the edges: the announcement engine, the calendar-to-leave-time integration, the lighting blueprint, the alert state machine. When a bespoke integration is a weekend’s work, the glue at the edges becomes disposable — cheap to write, cheap to replace, and shaped for exactly one house.
The reliability isn’t in any one of these pieces. It’s in the discipline that every one of them fails safe.