Files
houseplan-card/docs/RADAR.md
Claude 4bc3e9baa6 docs(hygiene): ARCHITECTURE.md — карта, а не хроника (#680)
Волна 3 эпика #674. ARCHITECTURE.md 2330 → 653 строки: система координат
прототипа 1489×1053, разделы Hidden Isometric Stage 2/4 (текущее — ISOMETRIC.md,
история — ADR 122/570), хроники «Additions v1.28–v1.41» и «Audit follow-ups»
сняты; подсистемы — короткое описание со ссылкой на канонический документ.
Устаревшее исправлено по коду: дерево Layout (store.py, frontend_registration,
весь список модулей), хранилища (config, layout, virtual_lights, trails),
ленивые локали de и fr, таблица WS API (31 + 3 команды, #256-проекция,
space/delete, files/cleanup без keep, контент через /api/houseplan/content),
DevItem без несуществующих полей, отказ help/feedback по support_api.

Всё ещё верное и не записанное в другом месте перенесено в канонические
документы: DEVICE-PRESENTATION (заметки реализации, Action authority, черновик
диалога), RADAR (карта реализации), VACUUM (владение кодом), CANVAS (icon_size,
--hp-cell-visual-scale, барьер записи координат), FILTERING (#44, каталог),
DECOR-EDITOR §7 (инварианты бэкенда ассетов), WALL-THICKNESS (§1 идентичность
и нулевые стены, §2 кэши, §4 hover/туннели/острова, §6 удаление комнаты,
§9 failed-core, §11 завершение цепочки и комната по грани), ISOMETRIC
(isoPlaneMatrix, iso-overlays, створки, служебные атрибуты), LIGHT (Glow над
заливкой #55, формула и screen-смешение), CONFIG-COMPATIBILITY (манифест схемы
#33, Masonry-слоты #561, квадратный холст v1.48, устаревшие URL контента,
layout/set #356), SCOPE (таблица владельцев при сборке файлов), WARM-REMOUNT
§5 (холодная загрузка и визуальная непрерывность), UX-MODES (порядок
стартового пространства), PDF-EXPORT (граница реализации), FURNITURE (adopt,
BOOT_MAX_MS). Раздел TESTING «Backend quality gates (#42)» и строка
DEVELOPMENT о bundle-freshness — из того же разбора, в предыдущем коммите.

Issue: #680
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-27 22:33:04 +03:00

8.2 KiB

Presence radars

Stage 1 of #485 projects current Home Assistant radar observations onto one House Plan room. It is intentionally a visualization and setup feature: House Plan does not identify people, record tracks, configure hardware zones or create derived Home Assistant entities at this stage.

What appears on the plan

  • Cartesian or polar coordinates become small live target dots.
  • A distance-only source becomes an arc or full range circle. It is not presented as an exact person position.
  • Known zone states may be presented as occupied/clear state; unknown geometry is never invented.
  • Presence-only sources report presence and health but do not fabricate a dot.
  • Coordinates, arcs and known zone geometry are clipped to the selected room's real polygon, including concave rooms. A missing room is an error and never falls back to another room or to its bounding box.

The layer is pointer-transparent. Small verified jumps may transition smoothly; large jumps, source gaps, slot changes, calibration changes and non-convex room contours never animate through an unverified path. Reduced-motion mode disables target motion. The diagnostic trail is limited to eight seconds and exists only inside the current browser session.

Supported input profiles

Profile Required source data Result
ESPHome LD2450 One to three exact X/Y sensor pairs, millimetres Target dots; x=0,y=0 together means an absent target, while one zero axis is a valid coordinate
Cartesian One to eight exact X/Y pairs, explicit unit, axis order and directions Target dots
Polar One to eight exact distance/angle pairs, explicit length/angle units and angle convention Target dots
Distance only One or two exact distances, explicit unit and known/entered direction/FOV Honest range arcs
Zone states Exact occupancy/count entities Read-only states; outlines only when geometry is actually known
Presence only Exact binary presence entity Presence and health without a position

An optional global availability entity and per-target/range presence gates may make absence explicit. Numeric zero remains data unless the selected adapter defines an exact pair rule such as LD2450's (0,0). Empty strings, unknown, unavailable, NaN and infinity are never converted to zero.

Configure a radar

  1. Add or open the real device marker in the Device editor.
  2. For a recognized radar, open Presence on the plan. For custom hardware, use Additional actions → This is a presence radar.
  3. Enable the radar, choose the room and verify every exact source. For generic profiles, specify units and coordinate conventions explicitly.
  4. Use Check live data before calibration. Correct unavailable, stale, partial or contradictory values in Home Assistant or the source mapping.
  5. Enter the physical mounting point, heading, range and field of view manually, or use Configure on plan. The latter records the mount and a point straight ahead. Coordinate profiles then measure two separated reference positions.
  6. Optionally check a third position. Its error is diagnostic and does not alter the solved transform.
  7. Apply the setup, then use the ordinary marker Save. Until that final Save, Cancel, Escape, page hide or a config revision conflict discards the draft.

The physical mount is not the decorative icon position. Moving the icon later does not move or recalibrate the radar. Changing the radar source/profile, coordinate convention, room or physical installation invalidates an accepted calibration; display-only switches do not.

Use a desktop browser for calibration. Touch View/kiosk remains fully supported, but precise editor setup on touch is best effort.

Health meanings

Status Meaning
Current data received Complete, fresh source data was normalized
No targets detected An explicit absence was reported
Some coordinate data is out of date One or more paired values exceeded the freshness/skew contract
Presence reported; current position unavailable Presence is true but no honest current coordinate is available
Sensor data unavailable A required source or availability gate is unavailable
Installation needs setup Sources exist but physical mapping is incomplete
Sources report conflicting values Fresh sources contradict each other, for example a zero target count with current target coordinates

Coordinate/range reports have short server leases and disappear when they are not refreshed. Reopening a tab, reconnecting or changing a source/calibration starts a new ordering epoch; an old frame cannot resurrect a target.

Privacy, permissions and storage

House Plan subscribes only to the exact configured entity IDs. Read delivery is filtered through the current Home Assistant user's entity permissions; setup requires House Plan write permission. Payload sizes, subscriptions and update rates are bounded.

Saved configuration contains source entity IDs, selected room, physical mount, orientation, units and calibration — not observations. Raw source values, measurement samples, live targets, trails and health frames are runtime memory only. They do not enter plan export/import, support diagnostics, uploaded files, browser storage or Home Assistant history through House Plan. Home Assistant and the source integration may independently keep their normal entity history.

Virtualized plan imports intentionally drop hardware-specific radar bindings. Unknown future radar versions remain preserved but inert until supported.

Implementation map

  • Persistence: marker.radar is saved only by the ordinary revisioned config transaction. radar_validation.py validates only a changed known version; untouched future versions stay inert. settings.radar.show_live is a display preference and never authorizes discovery, recording or hardware writes.
  • Backend: one RadarCoordinator (radar.py) per integration entry owns exact HA source listeners, report-time freshness, independent-pair skew, source/calibration epochs, projection, real-room clipping and bounded public frames; it reconciles on config revision and closes all listeners/timers on unload. The explicit profile/source-role inventory (occupancy_entity, count_entity, availability_entity; Cartesian x_entity/y_entity; polar distance_entity/angle_entity; range/zone entity_id; slot/range presence_entity) is the single authority for live listeners, setup listeners and per-entity read ACLs; unknown future fields never become sources by naming convention. Only the backend interprets raw HA states.
  • Eager View: radar-model.ts (frame validation/ordering/leasing), radar-live.ts (one active-space subscription and lifecycle), radar-render.ts (pointer-transparent SVG below ordinary device markers). Range segments arrive already clipped; an empty list is authoritative and never falls back to an unclipped arc. Transition eligibility is a server fact: only a current same-slot step of at most 100 cm in a convex room may animate.
  • Lazy editor: radar-editor.ts (recognition/draft round-trip), editors/radar-section.ts (marker dialog), radar-setup.ts (session-only on-plan wizard). A two-reference result changes only the open draft; the ordinary marker Save is the only write.

Troubleshooting

  • The section is absent: only positively recognized hardware or an already saved radar gets the main section. Use the manual action for a custom real device. Virtual markers cannot own a radar binding.
  • The source list is incomplete: ensure the entity is enabled and readable by the current Home Assistant user. Manual mapping can use exact entities from different devices.
  • Targets are missing: inspect health first. Verify units, axis signs, room, mount and heading. For LD2450, do not treat x=0 or y=0 alone as absence.
  • A target stops at the room boundary: this is the intended safety clip.
  • Calibration is noisy: repeat with one stationary person, separated references and no second reported target.

The normative engineering contract is docs/specs/485-radar-presence-stage1.md.