The Diagnostic Reports - TheThinkingHome/device_sentinel GitHub Wiki

The Diagnostic Reports

Device Sentinel writes three diagnostic files behind the scenes, tucked away in your config/device_sentinel/ folder.

Think of these files as the integration's scratchpad. You don't need to read them every day, and they won't throw alerts on your dashboard. They exist for one reason: when a device acts up, or when you want to know why the integration made a specific decision, the exact history is sitting right there in plain text.

(Looking for the human-readable summaries instead? Head over to The Daily Brief, The Battery Report, and The Signal Report.)

All three files are rewritten at startup, at midnight, at your scheduled brief time, and whenever you mash the Regenerate Reports button on the device page.

1. device_telemetry.md (The Learning Ledger)

This is where the integration keeps its homework. It contains one row per watched device, sorted alphabetically by name so you can quickly scan for the hardware you are troubleshooting.

  • The Math: You get the learned daily maxima, today's running maximum, the rhythm so far, and the signal floor. If you've ever stared at a freeze window and wondered, "How on earth did it decide on three hours?", the exact math is right here.
  • The Status: See at a glance whether a device is currently "Reported" normally, or "Muted" by a global or section-specific rule. The code in brackets names which rule: GLB for a global mute, or BAT, SIG and FRZ for the battery, signal and freeze screens.
  • The Faults: Up top, before the big chart, every active fault is listed by family (Freeze, Battery, Signal). It shows how long the fault has lasted and its standing on your Problem List: [○ open], [✓ acknowledged], or [✗ removed from list] if you deleted the item by hand while the fault was still live. (Acknowledged faults stay visible here on purpose. Checking a box silences your phone, it doesn't blind your diagnostics).

2. classification.md (The Audit View)

If a device isn't showing up where you expect it to, this table tells you why in a single glance.

It explicitly marks whether a device is watched or set aside. More importantly, instead of a cryptic checkmark, it tells you exactly why a device was set aside: was it a cloud service with no hardware? Did Home Assistant turn it off? Does it lack entities? Or did you explicitly exclude its integration?

It also audits your muting rules, telling you exactly which global rule caught a silenced device, and flags duplicate names shared across different registry devices. The line above the table counts the fleet: how many devices are watched, how many are set aside and for what reasons, and how many entities exist with no device behind them at all.

3. silence_episodes.md (The Forensic Record)

This is the detective file. It answers the one question the other files can't: When a device went dark for hours and then magically came back, did it choose to speak, or did a server reboot force it to wake up?

A row opens the moment a device's silence crosses half of its freeze limit, long before any judgment is passed. It logs when the silence started, how long it ran, and how it ended (whether it resumed on its own, or if an intervention like a system restart or bridge reconnect revived it).

The LAG Column (Finding Stuck Radios)

This column measures the time from an intervention (like a server reboot) to the device's very first report.

If you see the exact same devices popping up with a lag of a few "seconds" every single night, your server restart is what revived them. You have a stuck-radio problem, and widening your freeze windows would only sweep it under the rug. If the lag is measured in "hours," the device wasn't stuck at all; it just has a long reporting rhythm that your system restarts keep interrupting.

Did We Learn From It? (The LEARNED Column)

When a gap closes, the integration decides whether to use that gap to calculate the device's normal rhythm.

If the gap was a natural, clean cycle, it gets learned. But if the silence was caused by something else, a power outage, a reboot, you changing the battery, a pairing window, or a mesh failure, the gap is safely set aside. This column tells you exactly which gaps were discarded and why, proving that the system isn't learning that being broken or unplugged is "normal."

Here is what you will see in that column:

Reads Means
yes A clean, natural cycle. Learned in full.
yes (truncated) An intervention cut the silence short, so what was learned is a lower bound.
no (unavailable) / no (unknown) The device sat unreachable partway through, so the return may have been your hands rather than a real recovery.
no (bridge down) The silence overlapped a coordinator outage. The outage takes the blame.
no (unclean shutdown) A power loss or crash. Nothing was listening, so the gap measures the outage.
no (pairing) It came back during a Zigbee pairing window, so this was your re-pair.
no (handled) ZHA announced the device was re-paired, reconfigured or removed.
no (maintenance) It recovered inside an open Maintenance Mode window.
no (disabled) The device was switched off in Home Assistant for part of the silence.
capped (74m -> 15m) It was already flagged frozen when it spoke, and nobody knows what revived it, so the statistics learn its rhythm plus a modest allowance instead of the whole gap.