Skip to content
Back to Projects
Personal project · spec sheet · my flat, 2024 → ongoing

Smart home on K3s

Self-hosted home automation, in my own flat

If the internet goes down, the lights still work. Everything below follows from that.

lights, plugs and sensors
20+
ports open to the internet
0
Orchestration
Bare-metal K3s, single nodecontrol plane and every workload, with room spare
Reconciliation
ArgoCDthe flat's desired state is a git repo
Automation
Home Assistant
Radio
Zigbee meshno device talks to a vendor cloud
Transport
MQTT
Monitoring
Prometheus + Grafanasame stack as work, smaller
Exposure
Tailscale onlyremote access is over the VPN or not at all

Why it all runs locally

Most smart-home setups end up as a pile of vendor apps tied together with cloud accounts. That works until a vendor goes away, or you realise your motion sensor is reporting to a server in another country.

I wanted the opposite: everything local, and every change to it in version control. It's the same stack I run at work, sized to a flat. Mostly because I already know how to debug it.

Everything runs on one Pi

A Raspberry Pi 5 (8GB) is the whole control plane. I run NVMe over USB because SD cards die under sustained writes, and a UPS on the power side because Home Assistant restarting at 3am after a tripped fuse isn't an experience I wanted twice. It's on wired ethernet. The Pi is the thing every light depends on, and I didn't want it depending on the router's Wi-Fi as well.

A SONOFF Zigbee USB coordinator handles the radio. Devices pair directly with Zigbee2MQTT, which talks to Home Assistant over MQTT. No bridges, no cloud round-trip.

I'm at twenty-plus endpoints today: Hue bulbs, Innr plugs on power-monitored circuits, temperature and humidity sensors, motion and contact sensors, and a solar-powered camera. One node covers all of it, and I've had no reason to add a second.

What happens when I press a light switch

nothing leaves the building
wall switch
Zigbee press
coordinator
SONOFF USB dongle
Zigbee2MQTT
pod on the Pi
Home Assistant
automation fires
bulb
on

Every hop is on hardware in the flat. The internet connection can drop and the lights still work, because nothing on this path needed it. Remote access is a separate concern, handled by Tailscale rather than by opening a port.

Figure 1 — the same press, with and without a cloud in the path.

The whole flat is a git repo

Everything on the Pi is a Kubernetes deployment, reconciled by ArgoCD from a git repo. Adding a new automation, tweaking a Grafana dashboard, bumping the Home Assistant version. All of it goes through a commit. The cluster pulls; nothing pushes.

That sounds like overkill for a home lab, and it would be if it were any other tool. ArgoCD on K3s is about 80MB of memory and a few CRDs. The payoff is a setup that survives me. If I blat the SD card tomorrow, a fresh install plus argocd app sync brings everything back.

Power draw and humidity, in Grafana

Prometheus scrapes metrics from Home Assistant's exporter and from node-exporter on the Pi itself. Innr smart plugs report real-time power draw on the kitchen heater and the hallway lamp. SONOFF LCD sensors report temperature and humidity per room.

Grafana sits on top, with dashboards for power draw and room-by-room temperature.

Remote access goes over Tailscale

Zero ports exposed to the internet. Remote access goes through Tailscale. Every device on my account joins a private overlay network and reaches the Pi by its tailnet IP. Nothing on the router needs opening.

The blast radius if Home Assistant is compromised is limited to the LAN, and the LAN is segmented so the IoT VLAN can't reach anything else.

Next

Smart TRV valves next, so heating schedules run per room rather than per flat. After that, presence detection good enough to retire the motion sensors. They're fine for "is someone in the hallway" and useless for "is anyone home".

Revision — 2024 → ongoing · amended as the flat changes