I haven’t really been written anything – at all – about Home Assistant, but I am indeed a lover of it. Been using it since.. well before the release versions had dates. 2015 maybe.
I have almost 8000 entities, and a lot of which I use for different tasks. And a lot I don’t, there just there. I had one issue, that I have been chasing for quite some time – network loss. Meaning I got notifications that different services went down – falsely. The services did not go down, but rather Home Assistant (HA) lost its connectivity.
This post is meant for others who might be in the same situation, or otherwise want to research symtoms in HA, or just want to learn something.
Disclosure: I’ve had some help with LLM:s going though my logs to speed things up. As well as summarize the steps taken.
Environment
Home Assistant OS as a VM under Proxmox, pfSense with VLANs, a mix of Wi-Fi, Zigbee, Z-Wave, Matter/Thread, BLE and USB/serial. ~7,000 entities.
The symptoms
Home Assistant logged services dropping and coming back, over and over. Services went down, my Minecraft servers was flapping. But what I noticed in the HA logs was:
The syncthing server 'https://192.168.XX.YY:20910' is back online
The syncthing server 'https://192.168.XX.YY:8384' is back online
397 occurrences in a few days. Same for Spotify, Last.fm, Uptime Kuma, 1-Wire and Frigate. It looked like a network problem. Maybe something about my VLANs, LACP, DNS (Adguard Home DNS), pfSense blocking something (Surricata/pfBlockerNG/Crowdsec?)
Why it wasn’t the network
Four observations however pointed away from the network:
- Syncthing is addressed by raw IP (192.168.xx.y) — no DNS involved. Yet it failed at the same moment as Spotify and Last.fm, which both require DNS.
- Uptime Kuma never alerted. ICMP to the HA host got through the entire time.
dmesgshowed no link flaps. Intel NICs (igb/e1000e), link up continuously for two weeks.- Frigate on another VLAN X was hit just as hard as Syncthing on VLAN Y. Completely different paths through the firewall.
When DNS-dependent and DNS-independent connections die simultaneously while ICMP stays clean, packets aren’t going missing. The event loop is stalling.
Finding the cause
Step 1: Extract the timestamps
Recent HA (2025.11+) no longer writes home-assistant.log on HAOS — logging goes through journald. Pull it to a file first:
ha core logs -n 20000 > /share/ha.log
grep "back online" /share/ha.log | grep -oE "[0-9]{2}:[0-9]{2}:[0-9]{2}" | sort
The timestamps clustered clearly: starting at xx:32–33, ending around xx:40–41. Once an hour, roughly 8 minutes long.
The fact that the window didn’t start on a round minute was the key — cron jobs fire on whole minutes. This behaved like a timer inside HA, anchored to when Core last started.
Step 2: Clear the noise
The log was effectively unreadable. Two major sources:
hass_nabucasa.google_report_statelogged a timeout every 55 seconds as normal keepalive behaviour- A runaway automation accounted for roughly 80% of all lines (fixed)
logger:
default: warning
logs:
hass_nabucasa.google_report_state: warning
homeassistant.components.automation: warning
Step 3: See who’s talking during the window
grep -oE "\[[a-z0-9_.]+\]" /share/window.log | sort | uniq -c | sort -rn | head -25
A broad spread across unrelated integrations — plus homeassistant.helpers.entity with 108 hits. That logger name means ”update took longer than the scheduled interval”, which is the signature of a saturated event loop, not packet loss.
Step 4: The proof
20:32:01 AOD analysis starts
20:32:09 Step 2: health_check_and_prune → 7,739 ms
20:32:11 last log line
...20 seconds of total silence...
20:32:31 syncthing "not available"
20:32:45 syncthing "back online"
Nothing is logged during those 20 seconds. Not a single line from any integration. That’s a blocked event loop.
The cause: Area Occupancy Detection ran health_check_and_prune on the MainThread every hour. The step took 7.7–11.4 seconds and blocked everything else while it ran.
Trials and errors
I also did have this reoccuring repair issues woth AOD. Stating the analysis took well over 500s rather than the limit of 180s. Let’s fix that another time, I thought. But here we were. As stated above, I have arount 7000+ entities in my HA instance. Pretty much everthing recording, beside some perticular stuff. Also I hade 6 days of retention days in the recorder settings. My DB was close to 6GB. Hence, I started to purge. Lowering the retention days. Going through the database, looking for clues for what entites had the post data rows – and perhaps connect them to AOD. And finally adding a lot of exluded entities and entity globs into the recorder settings.
I got my DB down to around 40% of previous size. But still the same hangup in HA, and the logs to prove it.
Top rows per entity:
# via root SSH on HAOS, port 22222
ssh -p 22222 root@<HA-IP> 'docker exec -i homeassistant python3' < query.py
import sqlite3
c = sqlite3.connect("file:/config/home-assistant_v2.db?mode=ro", uri=True)
q = """
SELECT m.entity_id, COUNT(*)
FROM states s
JOIN states_meta m ON s.metadata_id = m.metadata_id
GROUP BY 1 ORDER BY 2 DESC LIMIT 25
"""
for r in c.execute(q):
print(r[1], r[0])
15 of the top 25 were AOD entities — over 2.5 million rows. Another user reported the same thing in AOD #467: AOD accounted for 30–50% of his entire database.
What actually fixed it
Short version: the number of sensors configured in AOD, not the database size.
| Change | health_check_and_prune |
|---|---|
| Baseline | 7,739 ms |
| After recorder DB went from 5.8 → 3.6 GB | 7,748 ms (unchanged) |
| After pruning AOD sensors | 1,354 ms |
The cleanup in AOD
- Removed all numeric sensors (temperature, humidity, etc.) — they contributed marginally to occupancy detection
- Removed redundant sensors: LD2410 modules expose
still_target,moving_targetandpresence. Onlypresencewas kept, since it already derives from the other two.
That last one matters for a reason beyond performance: multiple overlapping observations of the same physical phenomenon skew the Bayesian result. When only moving is active, still pulls the probability down even though someone is clearly in the room.
Result: from ~9 minutes of flapping every hour to 7 timeouts per day, all recovering automatically within 10 seconds.
Pitfalls worth knowing
exclude only applies going forward. Excluding an entity stops new rows but deletes nothing that already exists.
repack deletes nothing. It only returns already-freed space to the disk. The order has to be:
recorder.purge_entitieswithkeep_days: 0recorder.purgewithrepack: true
Globs don’t match in the middle. sensor.*_decay_status misses sensor.x_decay_status_2. After reinstalling an integration, entities get a _2 suffix and slip straight through. End with a wildcard:
- sensor.*_occupancy_probability*
- sensor.*_decay_status*
- sensor.*_presence_confidence*
- sensor.*_evidence*
purge_entities doesn’t always finish in one pass. Run the call a couple of times and verify against the top-rows query.
Orphaned entities
A health check reported 1,215 ”zombies” out of 7,000 entities — 17%. Mostly old MQTT entities from integrations that had been removed.
MQTT discovery recreates those entities on every restart as long as retained messages sit on the broker. Deleting them in the HA UI doesn’t help.
Easiest with MQTT Explorer: connect to the broker, expand the tree, delete the branch recursively. From a terminal:
mosquitto_sub -h <broker> -u <user> -P <pass> -t 'homeassistant/#' \
--retained-only -F '%t' -W 5 | grep -i <integration> \
| while read -r t; do
mosquitto_pub -h <broker> -u <user> -P <pass> -t "$t" -r -n
done
An empty payload (-n) with the retained flag (-r) is what deletes it. Wildcards work when subscribing, never when publishing.
Takeaways
Silence in the log is the strongest clue. Nothing being logged for 20 seconds says more than any error message. Look for gaps between timestamps, not just for errors.
Timeouts that cluster in time aren’t network problems. If unrelated services on different VLANs, with and without DNS, all fail within the same second — it’s the process, not the network.
A window that doesn’t start on a round minute comes from inside HA. Cron fires at :00 and :30. A timer anchored to Core startup lands wherever it lands.
Clear the noise before analysing. INFO-level logging from automations and keepalives can bury everything of interest.
repack without purge_entities does nothing beyond compacting space that was already free.
Bli först att kommentera