Here’s the failure mode nobody plans for: Home Assistant is up, the dashboard loads, the logs look normal — and one integration has been dead for four days. The lights still respond because you can toggle them manually, so nobody in the house notices. Meanwhile the automation that was supposed to close the garage door when everyone leaves hasn’t fired since Tuesday, and you find out because you come home to an open garage.
Once you’re past about twenty devices, the question stops being “does my smart home work?” and becomes “how would I know if part of it stopped working?” For most setups the honest answer is: you wouldn’t, until something embarrassing happens.
This post is how I answer that question — with Uptime Kuma, a couple of dead-man’s switches, and one hard-earned lesson about who watches the watcher. I currently run 23 monitors covering Home Assistant, the network gear, the hubs, and the scheduled jobs that everything else quietly depends on.
Why “is it up?” is the wrong question
A smart home doesn’t usually fail loudly. It degrades. The Zigbee coordinator drops off USB and every battery sensor goes stale over the next few hours. A cloud integration’s token expires and one vendor’s devices freeze at their last known state. A container restarts and comes back without one of its dependencies.
The nasty part is that Home Assistant itself keeps running through all of this. The UI is up. The automation.turn_on services still return success. Stale entities keep their last value instead of screaming — a temperature sensor that died at 71°F reads 71°F forever, which is a very believable number.
So the monitoring problem splits into three layers:
- Is the service reachable? (HA, the hubs, the network path to them)
- Is the data fresh? (are entities actually updating)
- Did the scheduled thing actually run? (automations, backups, cron jobs)
Uptime Kuma handles layer 1 directly, layer 3 with its push monitors, and layer 2 partially — the rest of layer 2 belongs inside Home Assistant itself, and I’ll show where I draw that line.
Uptime Kuma in ten seconds
Uptime Kuma is a self-hosted uptime monitor — think “StatusCake you run yourself.” One Docker container, a SQLite database, a clean web UI. It does HTTP(S) checks, TCP port checks, ping, DNS, keyword matching, and push (heartbeat) monitors, with notification integrations for basically everything.
# docker-compose.yml
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
volumes:
- ./kuma-data:/app/data
ports:
- "3010:3001"
restart: unless-stopped
The one architectural decision that matters: run it on different hardware than the thing it’s watching. Mine runs on the NAS box, not on the Home Assistant machine. A monitor that shares a power supply, a switch port, and an OS with its target will die at exactly the same moment the target does, and you’ll get no alert — because the thing that sends alerts is also down. If you only have one server, a $15 used thin client running just Uptime Kuma is a legitimate purchase.
Watching Home Assistant properly (not just pinging it)
Pinging the HA box tells you the kernel is alive. That’s nearly useless — I’ve had HA wedged with a full recorder database while the host answered pings all day. What you want is an authenticated HTTP check against the actual API:
- Monitor type: HTTP(s)
- URL:
http://192.168.1.50:8123/api/ - Headers:
Authorization: Bearer <long-lived access token>(create one under your HA user profile → Security) - Interval: 60 seconds
- Retries: 2 before alerting
A healthy HA instance returns 200 with {"message": "API running."}. Add a keyword match on API running and you’ve verified the whole stack: network, web server, auth, and the API layer — not just a TCP socket that might belong to a half-booted container.
I run a second HTTP check against a specific entity endpoint:
http://192.168.1.50:8123/api/states/sensor.living_room_temperature
with a keyword match on "state". If the recorder or the state machine is jammed, this fails while the bare /api/ check can still pass. Two monitors, and I can tell “HA is down” apart from “HA is up but sick” — which changes what I do when the alert arrives.
Hubs, bridges, and the quiet single points of failure
Every protocol in the house funnels through some box that never gets looked at. Those get monitors too:
- Zigbee coordinator / Z-Wave stick host. If they’re on a networked device (I run Z-Wave through zwave-js-ui in Docker), that’s a TCP check against the websocket port and an HTTP check against the web UI. Interval 60s.
- The Hue bridge, if you kept one. HTTP check against
http://<bridge-ip>/api/config— it answers without auth and returns JSON with the bridge name. Keyword match on the name. - Network gear. Ping checks on the switch the IoT VLAN hangs off and the access point that carries the WiFi devices. When ten devices go unavailable at once, “the AP rebooted” and “HA broke” look identical from inside HA. The ping history tells you which it was in five seconds.
- DNS. A DNS monitor resolving a known external name through your local resolver. Half of “the cloud integration is down” incidents on my network were actually “the Pi running the DNS filter fell over.”
None of these alert often. That’s the point — when the Zigbee monitor does fire, it’s real, and it saves the forty minutes of “restart HA, no change, restart the container, no change” flailing before someone thinks to check whether the coordinator is even reachable.
The dead-man’s switch: monitoring things that are supposed to happen
Everything above is pull monitoring — Kuma reaches out and checks. But the failures that actually burned me weren’t services going down. They were scheduled things silently not happening. A nightly backup that stopped running is invisible to every HTTP check in the world, because there’s nothing to probe — the absence of an event has no endpoint.
The fix is Uptime Kuma’s Push monitor, which inverts the direction. Kuma gives you a unique URL, and the job is responsible for calling it every time it runs:
# Last line of my nightly backup script
curl -fsS "http://192.168.1.60:3010/api/push/Hxk29dkq2?status=up&msg=backup-ok" > /dev/null
You set the expected heartbeat interval (mine is 24 hours for the backup, with a 2-hour grace period). If the ping doesn’t arrive in the window, Kuma alerts. The job didn’t run, the script crashed before the last line, the machine was off — doesn’t matter. Silence itself is the alarm. That’s the dead-man’s switch.
I use push monitors on:
- The nightly database backup (24h interval). A backup script that fails for three weeks is a story every homelab person eventually tells. Mine is now a story about an alert instead.
- The hourly file mover on the NAS (2h window).
- A “did automations fire today” heartbeat from HA itself. A tiny automation that runs at noon and calls the push URL via a
rest_command. If HA’s scheduler is wedged — and it can be, while the UI works fine — this catches it:
rest_command:
kuma_heartbeat:
url: "http://192.168.1.60:3010/api/push/aBcD1234?status=up&msg=ha-scheduler-alive"
automation:
- alias: "Watchdog: noon heartbeat to Uptime Kuma"
trigger:
- platform: time
at: "12:00:00"
action:
- service: rest_command.kuma_heartbeat
That last one sounds paranoid. It is not, and here’s why.
The 14-hour silence
Last summer, a hardware fault on my server — a PCIe error that escalated into a kernel-level hiccup — left the machine running but wedged the scheduler that drives all my automation-adjacent jobs. Nothing crashed. Nothing restarted. Every process showed as alive in the process list. And for 14 hours, not one scheduled job actually executed.
No error, anywhere, because nothing had failed in the way logs understand failure. The jobs weren’t erroring — they weren’t being started. Every check I had at the time was of the form “is the service up?”, and the service was up. I found out the next morning when I noticed the overnight reports simply weren’t there.
Two changes came out of that incident:
First, every scheduler got a push monitor. Cron on the server, HA’s automation engine, the backup timers — each one has to affirmatively prove it ran, on a schedule, forever. “Up” is no longer something I infer from the absence of errors.
Second, I wrote a watchdog that checks the checker — a dead-simple script on a different machine that runs every ten minutes, verifies the scheduler process is actually executing jobs (by checking a timestamp file the jobs touch), and restarts it if the timestamp is stale. It has fired for real exactly twice since. Both times I got a push notification saying it had already fixed the problem before I knew there was one.
The general lesson: liveness has to be proven, not assumed. Anything that matters should emit a heartbeat, and something independent should notice when the heartbeat stops.
Who watches Uptime Kuma?
Which raises the obvious recursion: Kuma is now load-bearing, and it can die too. Mine has — a filesystem-full incident took it down for two days once, and I only noticed because things felt too quiet.
You don’t need infinite turtles. You need exactly one external check on the monitor itself. Options, in ascending order of effort:
- A free external uptime service (UptimeRobot, HetrixTools free tier) checking one endpoint — if you expose a status page, that; if not, a heartbeat from Kuma to them. This is what I do: Kuma itself has a push-style check with an external service, so if my Kuma goes silent, an email arrives from outside my network.
- A cron job on a second machine that curls Kuma’s
/api/status-page/heartbeatendpoint and sends a notification directly if it fails. - A second Kuma instance watching the first, if you already have a Pi doing nothing. Cute, but honestly overkill.
The external-service option costs nothing and covers the scenario the others can’t: your whole LAN or internet connection going down while you’re away.
Notification routing: alerts that actually reach a human
An alert that lands in a dashboard nobody has open is a log line with delusions of grandeur. Getting this part right matters more than monitor count.
My routing, which took embarrassingly long to settle on:
- Everything goes to phone push. I run my own push relay, but ntfy or Pushover get you the same result in ten minutes — Kuma has native integrations for both. Email is where alerts go to be discovered three days later.
- Two severity lanes, not five. Critical (HA down, Zigbee down, watchdog fired) uses a distinct notification sound and bypasses do-not-disturb. Informational (a cloud service flapping, the third notice about the same outage) arrives silently. When every alert has the same urgency, you learn to ignore all of them at exactly the speed you’d expect.
- Resolved notifications ON for critical, OFF for informational. “It’s back” matters when you were about to get out of bed to fix it. It’s noise for everything else.
- Ten-minute maintenance windows are one click. When I’m deliberately restarting things, I pause the monitors first. Every false alarm you send yourself is a small withdrawal from the account that makes you take real ones seriously.
What’s worth monitoring: the tier list
After a year of adding and — more importantly — deleting monitors, here’s where things landed.
Tier 1 — monitor these, alert loudly:
- Home Assistant API (authenticated, with keyword)
- Zigbee/Z-Wave coordinator hosts
- The router/AP the IoT devices hang off
- Local DNS
- Backup job (push/dead-man’s switch)
- Scheduler heartbeats (push) — HA automation engine and any cron that matters
- Uptime Kuma itself (external check)
Tier 2 — monitor, alert quietly:
- Individual add-ons/containers with a real job (recorder database, MQTT broker, NVR)
- Cloud integrations you genuinely depend on — an HTTP check against the vendor’s status endpoint tells you “it’s them, not you” before you start debugging
- Certificate expiry if you expose anything over HTTPS (Kuma checks this for free on HTTPS monitors)
Tier 3 — don’t monitor, you’ll regret it:
- Individual lights, plugs, and battery sensors. That’s what HA’s own
unavailablestate and a stale-entity automation are for — device-level health belongs in the layer that has device-level context. Twenty ping monitors for twenty smart plugs is how you turn Kuma into the boy who cried WiFi. - Anything that flaps by design (phones sleeping, laptops leaving, TVs powering off). I watch the infrastructure those devices depend on instead.
The stale-entity gap — layer 2 from the top of this post — I cover inside HA with a small automation that counts entities unavailable for more than 30 minutes and sends one summarized notification, rather than per-device alerts. Kuma tells me when systems die; HA tells me when data goes stale. Keeping those responsibilities separate keeps both alert streams trustworthy.
What I’d do differently
Starting over, I’d change three things.
I’d set up the dead-man’s switches first, not last. I did HTTP checks first because they’re satisfying and easy, but every failure that actually cost me something was a scheduled-thing-didn’t-run failure. Push monitors are the highest-value five minutes in this whole post.
I’d put Kuma on separate hardware from day one instead of migrating it after the co-location problem became obvious during an outage — the exact outage it existed to catch.
And I’d resist monitor sprawl earlier. I peaked around 40 monitors, half of which only ever produced noise. The 23 that remain have this property: every alert means I need to know right now. That’s the standard. A monitor that doesn’t meet it isn’t monitoring — it’s guilt with a webhook.
The whole setup is maybe two evenings of work: one for Kuma and the HTTP/ping checks, one for wiring heartbeats into your scheduled jobs and getting notifications to your phone. The payoff is a specific kind of calm — not because nothing breaks, but because you’ve stopped wondering what’s broken right now that you haven’t found yet. In a house with 200+ devices, that question used to have a real answer more often than I’d like to admit. Now the answer arrives as a push notification, usually before anyone else in the family notices a thing.
Related guides: My Home Assistant backup strategy · IoT VLAN segmentation with UniFi · How I deploy HA config changes