| name | aod-external-positioning |
| description | Use when writing or reviewing anything that positions Area Occupancy Detection (AOD) against the rest of the Home Assistant ecosystem — README claims, release notes, "how is this different from X" answers, comparisons to HA core's bayesian platform or Bermuda/ESPresense, or any statement that a feature is "novel", "state of the art", or "proven". Also load before approving a PR description or doc page that cites accuracy/precision numbers, or before answering "is adjacency validated on real homes yet". |
AOD External Positioning
What this covers
Where AOD actually sits in the HA ecosystem today (2026-07-06), which of its
mechanisms are genuinely novel vs. commodity, the house standard for what
evidence a claim needs before it goes in README/release notes, and the four
maintainer-stated "beyond SOTA" ambitions with what each would require to
claim externally. This is the skill for outward-facing claims — what you
may say about AOD to the world, and what you may not say yet.
When NOT to use this
For the actual open research questions (what to build/measure next on prior
and likelihood learning), use aod-research-frontier and
aod-learning-accuracy-campaign instead. For internal architecture facts
(how the sigmoid pipeline actually computes), use aod-architecture-contract
or bayesian-occupancy-reference. This skill is about positioning claims,
not implementation.
1. What AOD actually is (verified facts)
| Fact | Value | Verified |
|---|
| Distribution | HACS custom integration (not HA core) | hacs.json: render_readme, zip_release: true, filename: area_occupancy.zip |
| Stars | 308 | gh repo view Hankanman/Area-Occupancy-Detection --json stargazerCount |
| Min HA version declared | 2024.8.0 | hacs.json: "homeassistant": "2024.8.0" |
| HA version actually tested against | 2026.7.1 | pyproject.toml pins homeassistant==2026.7.1 (dependency refresh, PR #496, merged 2026-07-06) |
| Docs site | hankanman.github.io/Area-Occupancy-Detection/ | gh repo view homepageUrl |
| Release scheme | CalVer YYYY.M.N (not the SemVer CLAUDE.md's release section describes) | gh release list, e.g. 2026.5.17 |
Do not describe AOD as "part of Home Assistant" or "an HA core feature" — it
is a third-party custom component installed via HACS, competing/complementing
core's own primitives (see §2).
2. Ecosystem position: competitors and complements
| Project | Relationship | Key difference |
|---|
| Raw motion sensor + automation timeout | Commodity baseline AOD replaces | Binary on/off, no context, no learning; README's own comparison table (README.md lines 26-32) is the canonical framing to reuse |
HA core binary_sensor.bayesian platform | Same math family, different product | See §3 below — do not claim "we invented Bayesian occupancy in HA," core already ships it |
| Template sensors / Jinja groups | Commodity AOD replaces | README's "Replace Dozens of Templates and Groups" framing (README.md line ~19) |
Bermuda BLE trilateration (agittins/bermuda) | Complementary, active collaboration thread | Issue #25 (opened 2025-03-01, oldest open roadmap issue, labels on roadmap+enhancement). Bermuda's maintainer (agittins) posted directly on #25 (2025-10-24) that Bermuda plans to add per-area OCCUPANCY-device-class boolean entities so users can pick "use for occupancy" per tracked BLE device — once that ships, those entities are a natural additional binary input to AOD, not a replacement for it. As of 2026-07-06 this integration point does not exist yet on either side — do not describe BLE/Bermuda ingestion as shipped. AOD's own README "Planned Features" lists "Location Aware: Leveraging BLE, WiFi, GPS" (README.md line 104) as future work, unimplemented. |
| ESPresense-style room-presence (WiFi/BLE RSSI room inference) | Complementary, same category as Bermuda | Not yet integrated; same "future input signal" status as Bermuda |
House rule: when asked to compare AOD to Bermuda/ESPresense, say they are
complementary location/trilateration signal sources AOD does not yet consume,
not competitors to be dismissed — the maintainer has an open, friendly
upstream thread (#25), not a rivalry.
3. Novel vs. commodity, as of 2026-07-06
Commodity — already exists in HA core or elsewhere, don't oversell:
- Naive-Bayes sensor fusion itself. HA core's
bayesian binary_sensor
platform (home-assistant.io/integrations/bayesian/) already combines a
user-specified prior with per-observation prob_given_true/
prob_given_false via Bayes' rule to produce a posterior against a
threshold. AOD's core probability pipeline is a superset in mechanism,
not in kind: it uses a sigmoid/logit-space combination (sigmoid_probability
in utils.py), not the log-odds accumulator naive-Bayes core uses — but the
underlying idea ("combine sensor states probabilistically instead of
boolean AND/OR") is the same idea core already ships. The real differentiators
are what feeds the model (below), not the existence of Bayesian fusion.
Do not write "AOD brings Bayesian probability to Home Assistant" — core
already has that. Write "AOD's fusion model is learned and time-aware where
core's bayesian platform requires the user to hand-specify every prior and
likelihood statically in YAML with no history, no decay, and no per-sensor
auto-tuning."
Genuinely novel (as a combination; verify each claim's current merge state before citing) — the differentiators to lead with:
- Learned time-of-week priors from recorder history. 168 (day-of-week ×
hour-of-day) buckets per area, computed from actual
recorder history via
the hourly analysis pipeline, DST-safe (walks in UTC, buckets by local
wall-clock). Nothing hand-configured. This is on main today.
- Purpose-based decay semantics. Per-area "purpose" (bedroom, office,
kitchen, passageway, etc.) drives default half-life and floor/threshold
behavior automatically, including a sleep/wake half-life split for
bedrooms — a room-type-aware decay model, not a single global timeout.
On
main today (though see aod-failure-archaeology for the recurring
custom-vs-default-value bug class in this exact mechanism — #439/#440,
#481/#493).
- Wasp-in-Box. Virtual sensor purpose-built for single-entry/exit rooms
(bathrooms) where motion sensors can't see the whole space: door-close
with no motion still holds high occupancy. On
main today.
- Adjacency / transition learning (learned neighbor influence). Learns
room-to-room transition probabilities from observed history (not a
hand-tuned "if kitchen occupied, boost dining room by X%" static rule) and
applies both a Bayesian logit-space boost and a decay-half-life stretch to
neighboring areas. This is PR #454 — merged 2026-07-06, now on
main
(squash merge, main HEAD 17b71d2). It directly answers community
discussion #431 (a user request for exactly this feature, unanswered by
the requester's own suggested static-config approach — AOD's design
instead learns influence from data).
No-oversell rule for #4 specifically: every constant driving the
adjacency boost/decay-modifier math (ADJACENCY_BOOST_GAIN=0.5,
ADJACENCY_DECAY_MODIFIER_GAIN=0.75, ADJACENCY_DECAY_MODIFIER_MAX=1.75,
the four ADJACENCY_N_* smoothing-fallback minimum-observation thresholds)
carries the exact in-repo comment (const.py lines 190-191): "First-pass
values; tune from real data once Phase 3 is collecting transitions." There
is no real-household validation of these numbers anywhere in the repo — no
recorder-derived accuracy measurement exists for the adjacency feature at
all (the test suite uses synthetic/mocked entities only). Label adjacency
"candidate" / "unvalidated on real homes," not "proven" or "state of the
art," in any external-facing writing until the learning-accuracy campaign
(see aod-learning-accuracy-campaign) produces a real measurement.
4. The house standard for publishing a claim
Before README, release notes, or any external doc states a quantitative
claim, it must meet the bar set by PR #486 (the diagnostic-sensor-precision
fix) — this is the canonical "how we prove a change worked" example in this
project's own history:
Measured on a live 6-area installation (v2026.5.17, 57 AOD entities):
Afternoon (active) baseline 15,952 recorder rows/3h → Evening 7,058 rows/3h
(−55%) → Morning 3,323 rows/3h (−79%).
What made that claim publishable (verify against gh pr view 486 — do not
paraphrase from memory):
- Real installation, not synthetic fixture data — "live 6-area
installation," named HA version and entity count.
- Explicit method — what was measured (recorder row count), over what
window (3h), under what condition (time-of-day activity level), against
what baseline (precision=2, the pre-change default).
- Before/after with a stated delta, not just an after-number.
- A stated mechanism for why the effect is real, not coincidental (the
PR explains why precision-0 reduces rows: sub-decimal noise is quantized
away while genuine decay-driven whole-percent transitions still record).
Checklist for any new external claim:
If a claim doesn't clear this bar, it stays internal (research-frontier /
learning-accuracy-campaign territory) — do not promote it to README or
release notes yet.
5. Reproducibility bar for any published comparison
Any comparison of AOD's accuracy/behavior against a prior version, a
competitor, or a baseline (raw motion sensor, HA core bayesian) must specify,
at minimum:
- AOD version (the
manifest.json/pyproject.toml/const.py
DEVICE_SW_VERSION triplet — see aod-change-control for why these three
must move together).
- Data source: real recorder history from a named install (household
size/area count, like PR #486's "6-area installation, 57 entities") vs.
synthetic fixtures (
config/configuration.yaml's 5-room mock rig) —
never blur the two. A synthetic-fixture result is a sanity check, not an
accuracy claim.
- Sample size: this project's own internal bar for trusting a learned
correlation is
MIN_CORRELATION_SAMPLES = 50 (const.py:323 on main as of 2026-07-06; line drifts by branch — grep -n MIN_CORRELATION_SAMPLES custom_components/area_occupancy/const.py) — any
external accuracy comparison with fewer than 50 underlying observations
per area/sensor should be labeled preliminary, not a result.
- The exact metric (precision/recall on occupied-interval detection,
recorder-row count, false-repair rate, etc.) with its formula or query
spelled out well enough that a future session could recompute it from the
same DB (
config/.storage/area_occupancy.db) — see
aod-proof-and-analysis-toolkit for the actual measurement tools
(scripts/visualize_distributions.py, the run_analysis service +
simulator).
- What's held constant: same purpose/threshold/decay config across the
before/after, unless the config change itself is the thing being measured.
6. The four SOTA ambitions and what each needs externally
The maintainer named these four as what "beyond SOTA" means for this
project. None are claimable externally yet on today's evidence — each needs
a specific kind of proof first:
| Ambition | What it means | What must be true before you claim it publicly |
|---|
| Reliability king (primary) | AOD's occupancy calls are more trustworthy than raw motion/naive automations across real, messy households — this is the maintainer's stated #1 priority | A multi-household measured comparison (precision/recall or false-trigger rate) of AOD vs. a documented naive-motion-sensor baseline, using the PR #486-standard method (§4). No such measurement exists in the repo today — this is the single most important gap; see aod-learning-accuracy-campaign |
| Learned-model research | Priors/likelihoods/adjacency learned from data, not hand-tuned, is a research contribution worth publishing/citing | Needs a written methodology (sampling, validation split, real-household data) that survives scrutiny — not just "we learn from history" as a slogan. The current adjacency tunables are explicitly first-pass/unvalidated (§3) — this ambition is blocked on the same accuracy-measurement gap as reliability king |
| HA-core quality | Code quality, test coverage, config-migration discipline on par with what HA core requires of built-in integrations | Concretely measurable today: 85% coverage gate (pyproject.toml, enforced by scripts/test), full type annotations, Google-style docstrings, ruff-enforced style (see aod-build-and-env) — this ambition is the closest to already being true and is the easiest to defend externally with a number (current coverage %, run scripts/test to reverify) |
| Predictive occupancy | Not just detecting current occupancy but predicting near-future occupancy/transitions (the adjacency trajectory work is a first step toward this) | Needs an explicit prediction-vs-outcome evaluation (e.g., "predicted transition to area X within N minutes, did it happen") — no such evaluation exists yet; adjacency's trajectory tracking computes a boost signal, not a scored prediction, so today's code is an ingredient, not a demonstrated predictive-occupancy result |
None of these four should appear in README/release notes as accomplished
facts. They are legitimate direction statements (roadmap language is fine:
"working toward reliability across real households") but any "we are the
most reliable/most predictive" framing needs the measurement described in
§4-5 first.
Provenance and maintenance
Date-stamped 2026-07-06 (post-merge), integration version 2026.5.17
(pyproject.toml line 7 / manifest.json line 20 / const.py
DEVICE_SW_VERSION) — note the integration's tagged release version has
not moved past 2026.5.17 yet, so "shipped in release" language should still
say "merged to main, not yet in a tagged release."
PRs #454 (adjacent-areas), #491, #492, #493, #494 were merged 2026-07-06
(squash merges) — main HEAD is now 17b71d2. Re-verify merge state before
citing any of their content as shipped if working from an older checkout.
Re-verification commands, by volatile fact category:
- Star count / repo metadata:
gh repo view Hankanman/Area-Occupancy-Detection --json stargazerCount,description,homepageUrl
- Adjacent-areas / PR #454 merge state (merged 2026-07-06; reconfirm on an older checkout):
gh pr view 454 --json state,mergedAt
- Same-day bugfix PRs #491-494 merge state (all merged 2026-07-06):
gh pr view 491 492 493 494 --json state,mergedAt (run each individually; gh pr view takes one number at a time)
- Bermuda thread #25 latest status:
gh issue view 25 --json state,comments,labels
- Adjacency tunables / "first-pass" disclaimer still present:
grep -n "First-pass values" custom_components/area_occupancy/const.py
- PR #486 measured numbers (15,952/7,058/3,323 rows, −55%/−79%):
gh pr view 486 --json body
- HA core bayesian platform current behavior: fetch
https://www.home-assistant.io/integrations/bayesian/ (external, may change independent of this repo)
- Current release version / CalVer scheme:
gh release list --limit 5
- Coverage gate percentage:
grep -n "fail_under\|fail-under" pyproject.toml; confirm live number via scripts/test
- MIN_CORRELATION_SAMPLES threshold:
grep -n "MIN_CORRELATION_SAMPLES" custom_components/area_occupancy/const.py