Automation suggestions from what your home actually does — not what it could do.
HA Insights mines the last 14 days of your event history and surfaces patterns worth automating: routines you keep doing manually, schedules that match real behaviour, anomalies that mean something just broke, and automations that have started silently failing.
Every suggestion is grounded in observed events, not a guess from your entity list. The 10+ deterministic detectors run locally with zero tokens spent. LLM is the fallback for polish — never the foundation.
| If your home shows... | HA Insights surfaces |
|---|---|
light.kitchen ON 11/14 days clustering at ~17:27 (±8 min spread) |
Streak: "Build automation? 11 days at ~17:27" — windowed match, not exact-minute |
| Door sensor that fired 38× its 14-day baseline today | Frequency anomaly: stuck loop, manual override, or genuine event burst |
3 entities in an automation are currently unavailable |
Audit: "automation will silently fail until X comes back" |
| Inverter switch ON ~10 hrs/day, 11/14 days | Long-tail: "Auto-off after 120 min?" |
| Tuya entity + ESPHome entity in one automation | Reliability: "cloud outage will fire local side silently" |
| Phone charging that never finishes before bedtime | Predictive: "you'll be at 9% by your usual bedtime" |
| Light schedule that drifts with sunset across the year | Seasonality: "tracks sunset within ~8 min" |
Detectors emit windowed matches, not exact-minute claims — a streak at "~17:27" means a cluster within a tolerance band, and the title shows the cluster spread on hover. The integration is honest about uncertainty.
- Local-first: every detector runs on-device. No internet required for the core experience.
- LLM is opt-in and optional: pick local (Ollama, HA Assist) or cloud (Anthropic, OpenAI). Off by default.
- "What gets sent?" modal: see the exact redacted payload before any cloud call. Entity IDs, area names, and your custom labels are redacted by default.
- Audit log viewer: every LLM call recorded with prompt + token cost + redacted payload. Reviewable in the panel any time.
- Entity-level blocklist: opt-out specific entities from any analysis.
- Three-tier maturity: STABLE / BETA / EXPERIMENTAL detectors; experimental gated off by default.
- Opt-in community analytics: off by default; aggregated detector performance only, never per-event data.
Two modes, both work without any LLM:
Reads every automation you've written and tells you what's wrong with it. Findings come from HA's own data — entity registry, automation execution traces, and 90 days of state history:
- Entity unavailable / missing — your automation references entities HA can't find anymore (renamed, removed, integration gone)
- Long-stay duration — light stays on 271 min on average; your
for: 60is too tight - Redundant target — action targets both
light.living_groupANDlight.living_lamp_1(member). Drop one - Trigger drift —
at: '07:00'but observed transition averages 07:08 across 14 days. Shift the trigger - Condition too strict — the automation triggered 184× but a condition blocked 142 of them. Maybe relax it
- Action errors — actions are throwing exceptions on N% of runs
- Dormant — hasn't fired in 60+ days; possibly broken or unneeded
- Seasonal patterns — only fires Nov-Mar (90-day rollup); add a
month:condition if trigger is time-based
Each finding either:
- Ships with a 📋 Preview button that shows the deterministic YAML fix in a side-by-side diff (no LLM, no tokens) — Apply commits it
- Ships with a 🤖 Suggest button when there's no algorithmic fix — the LLM is given an explicit AUTHORIZED EDITS list of what the findings actually justify
- Both: 🤖 Refine further with LLM layers LLM ideas on top of the deterministic stage
Eight built-in detectors watch state history and surface routines you might want to automate:
| Detector | What it finds |
|---|---|
| Schedule | "Every weekday at ~6:47 AM you turn on light.kitchen" |
| Seasonality | "Every Friday at ~7 PM, movie lights go on" (weekly cycles) |
| Cooccurrence | "Within 5s of the front door opening, the porch light turns on" |
| LaggedCorrelation | "Garage opens, driveway light follows ~3 min later" |
| LongTail | "Bathroom fan stayed on 4h, 12 times this fortnight" |
| Streak | "Light X turns on 3 days in a row at ~22:15" |
| OrphanDevice | "binary_sensor.front_door hasn't reported in 11 days" |
| FrequencyAnomaly | "Front door fired 50× today (~2/day baseline)" |
Cohort detection collapses 35 NVR cameras silent for 8 days into a single row, not 35 separate insights.
Click Apply and it writes a real automation: block to automations.yaml. Undo within 7 days reverses cleanly with drift detection.
A 36-day daily pattern at exactly 08:54:00.000 with zero variance is almost
certainly a device's internal timer — not a habit you'd want to "automate".
HA Insights demotes these so you don't see them at default confidence.
Four pure-math libraries each grade one signal; their multipliers compose into a single confidence demotion:
| Library | Signal | Device fingerprint |
|---|---|---|
lib/timing_likelihood.py |
stddev + range of fire times | sub-second precision on a daily pattern |
lib/cooccurrence_likelihood.py |
median nearby events in ±5 s | isolated (no other entities reacting) |
lib/persistence_likelihood.py |
CV of duration-in-state, both directions | FIXED_CYCLE (CV < 5 %) — e.g. 2-minute toothbrush |
lib/transition_entropy.py |
distinct preceding entities | NOVEL_CONTEXT — every fire follows a different lead-in |
Each is HA-core-adoptable (no HA imports, pure-Python, fully unit-tested),
bundled behind a HumanLikelihoodFeatures composite. Adding a fifth grader
is a ~10-line addition to the composite — detectors don't change. Threshold
tables are iot_class-aware (local push/polling tightens to < 2 s; cloud
push/polling relaxes to < 10 s).
The card pairs render a 🤖 device-managed or 🤖 tight-pattern pill with a tooltip explaining which signal demoted the row.
Captured on a 1000-entity HA install running v1.2.0.
┌─────────────────────────────────────────────────────────────────────────┐
│ HA Insights Pipeline │
└─────────────────────────────────────────────────────────────────────────┘
HA event bus + recorder + automation registry
│
▼
┌──────────────────────────────────────────────┐
│ Detectors run on a buffer snapshot │
│ • schedule, streak, cooccurrence, etc. │
│ • automation_audit (NEW — reads existing │
│ YAMLs + traces + rollups) │
│ Pure-Python; thread-safe; no I/O on loop │
└────────────────────┬─────────────────────────┘
│ Insight objects
▼
┌──────────────────────────────────────────────┐
│ SQLite store + display-time dedup (cohorts) │
│ + Repairs registry sync (dual-emit) │
└────────────────────┬─────────────────────────┘
│ ws_list / subscribe events
▼
┌──────────────────────────────────────────────┐
│ ha-insights-card (Lit element) │
│ • Panel + Lovelace card │
│ • Filter chips, group-by, expand cohorts │
│ • Side-by-side diff modal │
│ • Apply / Refine / Suggest buttons │
└──────────────────────────────────────────────┘
LLM only fires on user action — not in the scan loop.
When it fires, goes through:
Redactor (pseudonymize) → Conversation API → audit log
→ reverse-dereference → validator → apply pipeline
- OFF mode — zero outbound network. Pattern detection runs locally.
- LOCAL mode — pseudonymized data goes to a local Conversation agent (Ollama, Piper). Stays on your network.
- CLOUD mode — pseudonymized data goes to a cloud agent (Claude, GPT, Gemini). Real entity_ids never leave — they're replaced with stable pseudonyms (
light.entity_a3f1b2) before any LLM call. Reverse-mapped on response.
Per-entity opt-out blocks specific entities from EVER being sent (not even pseudonymized). Every outbound call is logged with bytes / agent / cost / success. The "What gets sent?" modal previews the exact payload before any LLM action.
Full details: docs/privacy.md.
- Four signal-grader libraries (v1.5.35–v1.5.40) classify events as
device- vs. human-driven from timing / co-occurrence / persistence /
transition-entropy. Pure-math, HA-core-adoptable, bundled via the
HumanLikelihoodFeaturescomposite — adding a fifth grader is a ~10-line extension, detectors don't change. - iot_class-aware thresholds — cloud-integrated devices add network
jitter, so the same algorithm uses different sub-second bands for
local_*vscloud_*integrations. - HA semantics filters (v1.5.x) — context.id batch correlator,
unavailable-transition filter, template-source pair drop, long-silence
filter — all pulled into
lib/event_filters.pyso they're liftable into HA core without integration scaffolding. - Cohort dedup hardening (v1.5.23) — entities with
device_id=Noneno longer get falsely absorbed into other cohorts. - iot_class deadlock fix (v1.5.22) —
_load_iot_classesnow reads the manifest cache off-loop. - HACS-path panel resolver (v1.5.32) — eliminates the post-update "hard-refresh required" loop for HACS users.
- Versioned cache-bust (v1.5.41) — panel URL now includes integration version so HACS updates always serve the new bundle.
Detector design draws on published work in habit detection, anomaly attribution, and human-vs-device routine classification. None of these papers is reimplemented verbatim — each maps to a concrete library plus a deliberate simplification suited to running on-device against HA's 14-day buffer:
- Houzé 2022 — Algorithmic Information Theory (AIT) memorability
for anomaly scoring.
transition_entropy.pyapproximates the AIT score via a 2nd-order Markov proxy (entropy of distinct preceding entities). Full AIT would require building a generative model of the house; the proxy needs O(N) over the cluster window and catches the same novelty signal in practice. - Gad 2026 — multimodal context features (co-occurrence, persistence) as device-vs-human signal. Direct inspiration for the second + third grader libraries.
- Fu 2021 (HAWatcher) — shadow-execution + correlation rules; 97 % precision claim. Queued for v1.15+: detect rules that should be firing but aren't, by maintaining a parallel state model and comparing against actuals.
- PELT (Killick 2012) — change-point detection. Shipped in v1.8.0
as
lib/changepoint_detection.py(ruptures backend + pure-Python fallback); used by FrequencyAnomalyDetector for changepoint-aware baselines and by StateShiftDetector for "your routine shifted on date X" findings. - Schreiber 2000 (Transfer entropy) — directional information
flow. Shipped in v1.9.0 as
lib/transfer_entropy.py; wired into LaggedCorrelationDetector in v1.9.1 to demote temporally-correlated pairs whose flow is reversed or symmetric (both directions = both driven by a third factor, not causal).
What we deliberately don't ship: vector embeddings of entity history
(memory cost grows with the install — see docs/ARCHITECTURE.md for
why the no-vector-DB decision was load-bearing); Cox proportional-hazards
survival models (researched, found to fail proportionality assumptions
on HA data — AFT models are the queued replacement).
- AutomationAuditDetector — audits every automation you've written. Eight kinds of findings, deterministic fixes available for half, LLM refinement for the rest.
- Side-by-side LCS diff modal — IDE-style aligned rows with red
-/ green+gutters. Phone-responsive (panes stack vertically below 720px). - Two-stage refinement — deterministic fix first (free, instant), then optionally layer LLM iteration on top with an extra user-feedback box.
- Repairs registry dual-emit — audit findings appear in HA's standard
Settings → Repairspage alongside HA's own issue notifications. Users discover the integration even when they forget the panel exists. - Concise vs In-depth toggle — top-of-panel switch trades LLM cost vs reasoning depth. Concise (~700 token prompts) is the default; In-depth (~1200 token prompts) for tricky automations.
- AUTHORIZED EDITS per-call — instead of universal rules the LLM must obey, each refine ships an explicit list of changes the findings or user request authorise. LLM can't invent removals the audit didn't justify.
- Token usage row — every refine modal shows approximate in/out token counts so you know exactly what each call cost.
- 24 unit tests covering dedup, audit packet builders, deterministic fix builders. Run via
pytest tests/test_lib_dedup.py tests/test_audit_packet.py tests/test_audit_fixes.py.
See docs/ARCHITECTURE.md for the full audit pipeline design.
- HACS → Integrations → ⋮ → Custom repositories
- Add
https://github.com/botts7/ha-insightsas type Integration - Click Install on "HA Insights"
- Restart Home Assistant
- Settings → Devices & Services → Add Integration → "HA Insights"
- Walk the wizard — pick the privacy mode that fits. Off works fully without an LLM; Local / Cloud light up Refine + Suggest + Explain.
The card repo is ha-insights-card — render insights as a Lovelace card AND mount the sidebar panel.
- HACS → Frontend → ⋮ → Custom repositories
- Add
https://github.com/botts7/ha-insights-cardas type Lovelace - Install
- The integration auto-registers a sidebar Insights panel at
/ha-insightsonce the card resource loads - For a dashboard tile too:
type: custom:ha-insights-card compact: true
Refine + Suggest + Explain need a Conversation integration. Pick from HA's standard options:
- Ollama (local, free)
- Anthropic Conversation (Claude — best output quality for YAML)
- OpenAI Conversation (GPT-4 / GPT-5)
- Google Generative AI Conversation (Gemini — make sure
max_output_tokensis set high enough; default 150 is too low) - Nabu Casa Cloud (Assist subscription)
The integration auto-picks the first installed LLM agent. Override per-call via the UI's preferred-agent dropdown.
- Every scan, the AutomationAuditDetector walks every automation it can find (
automations.yaml,configuration.yaml, packages, runtime registry). - For each automation, it builds an AuditPacket:
- Live state-machine snapshot (HA
states) — for entity_silent - 14-day event buffer aggregates — for long_on_duration, trigger_time_drift
- HA's own automation traces (last N runs) — for trace_dormant, trace_condition_blocks, trace_action_errors
- 90-day recorder rollups (day-of-week / day-of-month / month-of-year) — for seasonal patterns
- Cross-reference to other detector findings touching the same entities
- Live state-machine snapshot (HA
- Each observation feeds into a per-kind hint that gets shown alongside the finding.
- Findings that have a deterministic fix (redundant_target, long_on_duration, trigger_time_drift) ship with
payload_format="automation"+ a 📋 Preview button. No LLM tokens spent. - Findings without a deterministic fix (entity_silent, trace_, rollup_) ship as
payload_format="report"with a 🤖 Suggest button. - Clicking 🤖 sends through HA's Conversation API with: the YAML, the observations, and an
AUTHORIZED EDITS:block explicitly listing which changes the findings justify. - The card renders the LLM's refined YAML as a side-by-side aligned diff. Apply commits via the existing validator + writer.
For a typical 30-automation home with the v1.1 prompt:
| Action | Tokens (approx) | Notes |
|---|---|---|
| Scan + emit audit insights | 0 | Pure-Python detectors, no LLM |
| 📋 Preview deterministic fix | 0 | Algorithm runs offline |
| 🤖 Suggest, Concise depth | ~700 in / ~150-400 out | ~$0.0008-0.002 on Sonnet |
| 🤖 Suggest, In-depth | ~1200 in / ~150-400 out | 4× input for tricky automations |
| 🤖 Refine further (stage 2) | ~700 in / ~150-300 out | Concise enforced regardless of setting |
| Local LLM (Ollama, etc.) | n/a | $0; no budget gate fires |
A per-month USD budget can be set in OptionsFlow for cloud agents; the background batch suggest service stops queuing once the cap is hit.
docs/ARCHITECTURE.md— full architectural charterdocs/HA_EVENT_SEMANTICS.md— HA state-change event gotchas detector authors must knowdocs/privacy.md— what's stored / what isn't / how to wipedocs/conflict-scanner.md— how "🔁 already automated" matching works (and its limits)docs/ws-api.md— stable WebSocket API contractdocs/writing-a-detector.md— community detector contribution guide
Assist is reactive — user asks, LLM answers and can act. HA Insights is proactive — observes patterns + audits existing automations + surfaces actionable suggestions, optionally refined with the same LLM agent you've configured for Assist. Same agents, complementary surfaces.
"HA Insights" is a community project, not affiliated with or endorsed by Nabu Casa. "Home Assistant" is a Nabu Casa trademark; we follow the standard HACS-community pattern of ha- prefixed naming and don't use HA brand assets.
v1.9.1 — current release. What that means in practice:
| Area | Status |
|---|---|
| Integration core (detectors, audit, redactor, store, WS API) | Test-covered — full unit + smoke suite green on CI per release. Community use ramping. |
| Privacy controls (opt-in LLM, pseudonymization, audit log, "what gets sent?") | Test-covered — privacy contract is a hard rule, not a feature flag |
| Panel UI | Stabilized — v1.7.7 600 ms grace-then-force-mount addresses the upstream <ha-panel-custom>.update() deep-equal short-circuit. See docs/panel-troubleshooting.md for self-serve diagnostics. |
| Mobile push throttling, daily-digest cadence | Untested at scale — anti-spam logic exists; defaults will likely need tuning based on community feedback |
| Research-backed detector library (v1.8 changepoint, v1.9 transfer entropy) | Shipped + tested — used by FrequencyAnomalyDetector, StateShiftDetector, LaggedCorrelationDetector. Calibration thresholds will refine with field data. |
| Find My Device (identify + perturbation + BLE live-find) | v1.10–v1.12 roadmap — planned; not started. See docs/ARCHITECTURE.md "Future roadmap." |
| HAWatcher shadow-execution | v1.15+ research direction — contributors welcome |
Open a bug — the template asks for HA version, integration version, browser, repro steps, relevant homeassistant.log lines. Detailed reports get triaged same-day; "it broke" reports queue.
- Bugs: fork, branch off
main, add a test that reproduces (usetests/test_lib_*.pyfor pure logic ortests/_smoke_v1_4_x.pyfor integration-shape checks), open a PR. The PR template walks you through the surgical-diff conventions. - New detector: see
docs/writing-a-detector.md— the existing 10+ detectors follow a stable contract; your detector is one folder + one entry indetectors/__init__.py. - Discussion / ideas: GitHub Discussions for shape-of-the-feature talks; issues are for bugs and concrete proposals.
- Surgical diffs only — every changed line traces to the request, no drive-by refactors
- Yield in CPU loops over user-scale data (HA event loop is single-threaded)
- No hardcoded credentials, IPs, tokens
- Test-first when feasible; smoke tests catch architectural regressions cheaply
MIT — see LICENSE.




