overview

My room runs on Home Assistant, self-hosted in Docker on my Pi 5 homelab. It controls my desk and floor lamps, knows whether I'm home, shows where my phone has been, plays Spotify, and can turn my MacBook into a security camera. I use it three ways: a Galaxy tablet mounted on the wall as a kiosk, a phone dashboard, and without looking at a screen at all, through NFC tags and Siri.

features

tap to toggle: I have NFC tags wired to one script. Tap my iPhone on a tag and both lamps flip together, on or off.
local lights: Both lamps are on Athom smart plugs running ESPHome, so they're controlled on my own network with no vendor cloud in between. If the internet goes down, the lights still work.
Siri: The HomeKit Bridge integration exposes the lights to Apple Home, so "hey Siri, lights off" and the Control Center tiles work too.
presence and movement: The Home Assistant iPhone app reports my location, which drives home/away state and a map on the dashboards that traces where my phone has been.
battery levels: The iPhone, iPad and macOS companion apps report battery levels, so every device's charge is on the kiosk at a glance.
Spotify and weather: What's playing, next to the day's forecast.
CCTV: One switch turns my MacBook's webcam into a live camera feed on the dashboard. How that works is on its own page.

the kiosk

The wall tablet runs one dashboard, laid out on a roughly 42-column grid (layout-card's grid layout, not the default Sections view, which can't place cards this precisely). The live panel for the homelab takes the left third, the camera and Spotify sit in the middle, the weather takes the right, and the lights run along the bottom: desk, floor, then both.

kiosk-mode hides Home Assistant's header and sidebar, but only for the tablet. The tablet signs in as its own Home Assistant user and kiosk-mode targets that user, so my own account still gets the full interface everywhere else. I couldn't do it with a URL flag: the Home Assistant Android app ignores URL paths and always opens the signed-in user's default dashboard.

The tablet itself, and the 3D-printed mount that holds it, are on the wall mount page.

the phone dashboard

A single-column version for my phone. Two things fought me here. Setting cards to 100vh behaved differently in the app than in a browser, so every row has a fixed height instead. And the homelab panel sits in an iframe, which swallowed scrolling until the iframe was set to only claim vertical panning, with the scrolling moved inside the panel instead of the page body.

The raw YAML editor also kept mangling the CSS selectors I use for styling, so I edit this dashboard's stored JSON directly, with Home Assistant stopped, using a short Python script.

the location bug

For a while my location only updated while I was on home Wi-Fi. The iPhone app's most private location mode will only send updates to a server it can reach securely, and off my home network it had nowhere to send them. Giving Home Assistant a proper HTTPS address inside my tailnet, and telling it to trust the proxy in front of it, fixed it. It's still never reachable from the open internet.

construction

Home Assistant Docker ESPHome HomeKit Bridge HACS layout-card kiosk-mode card-mod NFC Tailscale

Home Assistant runs as a plain Docker container rather than Home Assistant OS, using the host's network so it can discover the ESPHome plugs and advertise the HomeKit bridge over mDNS. Its config lives on the Pi's SSD, so it's in the nightly backup, and every config change gets a syntax check before a restart.

architecture

NFC tag / Siri / dashboards → Home Assistant (Pi) → ESPHome plugs / MacBook camera / Spotify

Everything goes through Home Assistant on the Pi: the tags and Siri trigger the same scripts the dashboards do, so there's one place where a light's state lives.

Source? My config isn't public since it describes my home network. Happy to talk through any part of it though.