Apple Homesurface
Siri and the Home app — the household's everyday surface.
project deep-dive
A Home Assistant platform on a Raspberry Pi 5 — 50+ devices across Matter, Thread, Zigbee, HomeKit and a dozen APIs. Segmented behind a zone-based firewall, backed up on and off the box, and driven by a language model that never leaves the LAN. Self-hosted, local-first, network-segmented.
A working home-automation platform — not a demo. Designed, built & maintained by Casey Fontneau.
Most "smart homes" are a drawer full of vendor apps, each phoning a different cloud, each one outage away from a dark hallway. This one is built the other way around: a single self-hosted brain owns the automations and the data, every device is reachable locally, and the network is designed so a fifteen-dollar bulb can't see anything that matters. It's the discipline of a small production system — segmentation, backups, least privilege, reversible changes — pointed at the problem of living somewhere.
Home Assistant sits in a restricted zone as the automation brain. Devices are isolated on their own VLAN; the few things that must talk across the boundary do so through narrow, explicit rules — not by flattening the network.
Siri and the Home app — the household's everyday surface.
Natural-language control via HA Assist, with tool-calling.
Dashboards and push notifications on iOS and CarPlay.
Home Assistant runs as the automation brain inside a restricted zone: automations, the HomeKit bridge, the Matter controller and the Assist API all live here. Control surfaces reach in from above; every device zone hangs off it below, through the firewall.
| Data path | Protocol |
|---|---|
| Core → Lighting · plugs | Wi-Fi · API |
| Core → Climate · water | MQTT |
| Core → Thread · Zigbee hubs | Matter · Thread · Zigbee |
| Core → Media · AV | HomeKit · HAP |
A selection of the decisions and incidents that actually took thought — the kind of thing that doesn't show up in a device count.
Problem — The household already lives in Apple Home: Siri, the Home app, muscle memory. Centralizing on HA by ripping that out would be an upgrade for me and a downgrade for everyone else. Approach — HA owns the integrations and automations, then re-exposes a curated device set back into Apple Home through its HomeKit bridge. Matter devices run multi-admin — native in both fabrics at once, no translation layer. Result — One automation engine, zero lost convenience. The people I live with never had to learn a new app.
Problem — Cheap smart devices are the soft underbelly of any network. But Matter, HomeKit and AirPlay all lean on multicast discovery — exactly what VLAN segmentation is supposed to kill. Approach — Devices sit on an isolated IoT VLAN behind a default-deny, zone-based firewall; the controller runs in a DMZ zone via a per-client override; the handful of cross-zone flows are opened by intent rules, not hand-edited exceptions. Internal IPv6 was stood up on the LAN purely to satisfy Matter, with scoped mDNS reflection and IGMP snooping so discovery survives the walls. (AirPlay's PTP timing proved genuinely un-routable across VLANs — so speakers were placed deliberately, once I'd proven why.) Result — A compromised bulb can't see the laptops, a decoy address on the IoT VLAN trips on anything that goes looking, and the whole thing still shares a rack with a separate, fully isolated segment.
Problem — An overnight vendor firmware push silently disabled the local API on a set of Wi-Fi plugs. Cloud still worked; local didn't. Re-authentication was useless — the endpoint was simply gone. Approach — Rather than wait for a vendor fix, I re-commissioned every one of them onto Matter, a firmware-stable, vendor-independent control path, reusing their existing identifiers so nothing downstream broke. The Matter controller itself later took a major-version upgrade, done with a full backup and a one-command rollback staged first. Result — Local control restored, and a whole device class moved off proprietary protocols for good.
Bug 1 — The network hallucinated a switch that didn't exist: phantom devices connecting and dropping every couple of minutes, for weeks. Root cause — An upstream device on the isolated segment stamped its discovery frames with a chassis-level MAC, so the controller kept "seeing" one address on two ports and churned its topology forever. Found by careful elimination; killed by silencing that one protocol at exactly the right layer. Bug 2 — Then every Matter device refused to pair, instantly, across three different phones and tablets, before anything even hit the network. Root cause — The iPhone's Personal Hotspot, merely enabled, reshapes the Bluetooth stack and breaks the BLE handshake Matter uses to bootstrap a device. Toggle it off, reboot, done. Neither bug lived in the thing that looked broken.
Problem — I wanted natural-language control. Pointing my house at a cloud LLM, and handing it the keys to the locks and cameras, was a non-starter. Approach — Wired HA's Assist to a 35-billion-parameter model hosted locally on a GPU box, reached over the LAN (not even the VPN), with tool-calling enabled. Then enforced an allowlist: everyday lights, climate and media are exposed; locks, alarm, cameras and network controls explicitly are not — closing HA's permissive-by-default exposure. Result — "Turn off the desk lamp" runs entirely inside the house. The model literally cannot reach the front door.
Problem — Automation that fights you is worse than none. A house that cools a room on its own, then argues when you override it, just makes everyone want the robot gone. Approach — The climate logic runs as a small state machine: it only ever acts on a room it started, tracks that ownership with a per-room flag, and the moment someone touches the thermostat by hand it releases and backs off. When the away-from-home prompt to arm an auto-off timer broke over the VPN, I ditched the fragile in-dashboard popup and rebuilt it as a native actionable notification that works locked, on the road, anywhere. Result — The system is helpful without being bossy — it never countermands a person, and its controls reach you wherever you are.
Problem — The people depending on this don't file tickets. They just get annoyed when the lights don't answer — which makes reliability a household-diplomacy problem, not only a technical one. Approach — Moved the OS off an SD card onto NVMe for write endurance; a UPS triggers a graceful shutdown on power loss; the internet itself fails over from cable to cellular in under ten seconds, on health-checks tuned not to false-alarm; backups run weekly, on the box and pulled off it; remote access is a private mesh VPN with zero forwarded ports. Result — Reversible changes, recoverable state, nothing exposed to the open internet.
| Layer | Components |
|---|---|
| Core | Home Assistant OS · Raspberry Pi 5 · NVMe boot · HACS |
| Network | UniFi · Zone-based firewall · Dual-WAN failover · mDNS reflection · Mesh VPN · IPv6 ULA (Matter) |
| Defense-in-depth | Default-deny zones · DMZ placement · IPS (block mode) · IoT honeypot · Encrypted DNS · MAC allowlist · LLM allowlist |
| Protocols | Matter · Thread · Zigbee · Wi-Fi · HomeKit / HAP · MQTT · REST + WebSocket |
| Intelligence | Local 35B LLM · llama.cpp · HA Assist · tool-calling |
| Resilience | UPS + NUT · Automated backups · Off-device copies · Graceful shutdown |
| Surfaces | Apple Home · Mushroom dashboards · Custom Lovelace cards · iOS / CarPlay · Actionable push |
Local-first
Core control never depends on someone else's servers. Clouds are a convenience, never a dependency.
Least privilege
The network — and the language model — reach only what they must. Everything else is denied by default.
Reversible
A verified backup before anything destructive. Every change traces to an intent, and backs out cleanly.
Verified live
Trust the running system, not the docs or the dashboard. If it wasn't observed, it isn't done.
Own the data
Nothing internet-exposed. A LAN and a private VPN, full stop — the house answers to no one's API.
Designed, built & maintained by Casey Fontneau. A working home-automation platform — not a demo. Happy to go deep on any layer of it.