SmartestHome/hosts/door-panel
Amir Alexander Abdelbaki bad217c369 Add identity registration system and Phase 18 door panel
identity/ (Phase 6, rewritten from the original Node-RED sketch): a
person <-> BLE-identifier registry built directly as a Python service.
Solves multi-phone (multiple identifiers per person), anti-spoofing
(only allowlisted IRK-resolved/fixed-tag entities are ever accepted as
registration candidates, never a raw or randomized MAC), device-less
people (a grandmother without a smartphone gets a no_device registration
plus a hand-operated home/away toggle, reported as "unknown" rather than
a false "away"), and anonymous guests (POST /register/guest, no name
needed). Every person gets an automatic profile picture from their most
recent registration photo. /presence also reports a best-effort room per
person as groundwork for an eventual floor-plan view (not built).
Registration is single-utterance voice ("register me as <name>") or a
touchscreen form; ambiguous/conflicting candidates never auto-commit.

hosts/door-panel/ (Phase 18, new host): structurally kitchen-display's
twin - one Sway workspace, one Chromium kiosk window - defaulting to
identity's weather+clothing/who's-home/groceries-running-low dashboard,
with voice registration as its actual purpose (mic on by default, unlike
every other host's opt-in).

hosts/kitchen-display/: adds opt-in voice satellite and a "Show
registration" screen pointed at identity's register.html, reusing the
same camera-equipped-endpoint registration flow.

pantry-vision/: adds GET /shopping-list (Grocy's own volatile/missing
products, reshaped) for the door panel's "running low" section.

setup-container-host.sh: wires ENABLE_IDENTITY (identity + identity-web,
published like pantry-vision since kiosk browsers call it directly, plus
a persistent SQLite/photos volume unlike pantry-vision's stateless
design) and fixes the HA_URL example to the host's real LAN IP (HA runs
network_mode: host, unreachable by container name - the same situation
Node-RED's own config already documents).

docs/: Phase 6 rewritten, Phase 18 added, hardware/software/guardrail/
open-decision entries throughout project-plan.md and README.md.
components.md gains RuView presence nodes (one per room), fixed BLE tags,
and 2 spare webcams, with the price estimate updated to match.

Nothing here has been run against real hardware, a real HA instance, or
real Private BLE Device entities - TRUSTED_ENTITY_PREFIXES above all
needs checking against a live instance before registration finds
anything. See identity/README.md and hosts/door-panel/README.md for the
itemized verification lists.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6CrKjW3yVptUnjG35HjC1
2026-07-30 13:40:04 +02:00
..
agent Add identity registration system and Phase 18 door panel 2026-07-30 13:40:04 +02:00
configs Add identity registration system and Phase 18 door panel 2026-07-30 13:40:04 +02:00
live-build/config Add identity registration system and Phase 18 door panel 2026-07-30 13:40:04 +02:00
scripts Add identity registration system and Phase 18 door panel 2026-07-30 13:40:04 +02:00
README.md Add identity registration system and Phase 18 door panel 2026-07-30 13:40:04 +02:00

README.md

Sway door panel

Phase 18 of docs/project-plan.md. Builds a Debian 12 live ISO for a wall panel by the door/wardrobe: weather and what to wear on the way out, who's home, groceries running low, and — the household's actual registration point — "register me as <name>" by voice.

Structurally this is ../kitchen-display/'s twin, not a new shape: one Sway workspace, one Chromium kiosk window, a thin agent that only ever switches which page is showing. The differences are what it shows by default (identity's dashboard.html instead of pantry-vision's scan/inventory/recipes) and that its microphone is expected to actually be used, not an edge-case opt-in.

The actual logic does not live in this directory../../identity/ owns person/presence data and the registration flow; ../../pantry-vision/ owns the "running low" data. This host is deliberately thin: Sway, one kiosk window, and door-panel-agent, which only controls which screen is showing — the same split every other kiosk host in this project already uses.

Compositor Sway, one workspace, one Chromium kiosk window
Autologin greetd, straight into /usr/local/bin/kiosk-session
Touch input Native Wayland wl_touch, same assumption as ../touch-panel//../kitchen-display/
Default screen identity's dashboard.html — weather + clothing suggestion, who's home, groceries running low
Registration identity's register.html — voice ("register me as <name>") or the touchscreen form
Voice wyoming-satellite + openWakeWord — opt-in like every other host's mic, but this device's actual purpose, so the build script defaults it to on
Remote control (HA/LLM) door-panel-agentShow home / Show registration buttons only
Remote control (human) SSH only — no wayvnc, same scope decision as ../touch-panel/

Hardware

No specific unit has been chosen. What's assumed: a touchscreen (native wl_touch, same caveat as every other touch host in this project) mounted by the door or wardrobe, with a microphone and speaker for voice registration/Assist playback. Unlike ../kitchen-display/, no camera is strictly required — the photo captured during registration (identity's profile-picture feature) is a nice- to-have audit artifact, not load-bearing, since identity resolution here is BLE/IRK- based, not camera-based. See docs/project-plan.md §1.16 for the (unverified, non-specific) hardware line item.

Before you build

Deploy identity/identity-web first (ENABLE_IDENTITY in hosts/container-host/scripts/setup-container-host.sh) — this image builds and boots fine without it, but the dashboard will show connection errors until it exists. pantry-vision is optional (only "Running low" needs it). Then edit the # CONFIGURATION block at the top of scripts/build-door-panel-iso.sh:

Variable What to put in it
MQTT_BROKER_HOST LAN IP of the container host running Mosquitto
IDENTITY_WEB_URL / IDENTITY_URL / IDENTITY_TOKEN identity's static-serving and API URLs; token must match identity/identity.env's own
PANTRY_VISION_URL / PANTRY_VISION_TOKEN Optional — only "Running low" needs these; must match pantry-vision/pantry-vision.env's own token
ENABLE_VOICE_SATELLITE Defaults to true here (unlike every other host's identical flag) — this device's whole point is voice registration, but it still needs a real mic on the specific unit before flashing it
KIOSK_USERNAME / IMAGE_HOSTNAME / DOOR_PANEL_NAME Per-device identity
SSH_AUTHORIZED_KEY Optional — password auth is disabled and there is no wayvnc

Build

sudo ./scripts/build-door-panel-iso.sh

Same directory-split convention as every other host: configs/ and agent/ are human-edited and git-tracked; live-build/config/includes.chroot/ is generated, gitignored, never hand-edited.

Why one workspace, two kiosk destinations, not three

../touch-panel/ juggles three real apps (Spotify, Home Assistant, a browser) and needs a persistent touch dock to switch between them. This device only ever shows one of two pages — the everyday dashboard, or the registration form — and switches between them rarely (on an MQTT command or a voice trigger), so a dock would be overhead with nothing to navigate day-to-day. configs/sway/home-kiosk and configs/sway/identity-kiosk are separate scripts on separate Chromium profiles, same shape as ../kitchen-display/'s pantry-kiosk/identity-kiosk pair — see that host's README for why both scripts kill any Chromium instance before launching (this device also has only one workspace).

Home Assistant entities

door-panel-agent publishes two buttons on connect: Show home, Show registration — each kills and relaunches the kiosk Chromium window at the corresponding page. That's the entire MQTT surface. Reading presence/weather/ groceries, or registering a person, is a separate path — Home Assistant/the LLM calling identity's or pantry-vision's own published APIs directly, not through this agent. Voice registration in particular never touches this agent at all — see ../../identity/README.md's worked HA intent-script example.

Security boundary

Same shape and reasoning as every other host's agent in this project: door_panel_agent/mqtt_discovery.py is the entire inbound MQTT control surface of this machine — LLM tool call → HA service call → MQTT → this agent, no HTTP listener, no websocket, no exposed Sway IPC socket, no VNC. identity and pantry-vision are separate, deliberately published services with their own bearer-token boundaries — see their own READMEs' "A real network listener, unlike admin-canvas" sections for why that trust model is different on purpose.

Manual verification still outstanding

None of this has been run on hardware. In rough order — on top of everything already flagged as unverified in ../../identity/README.md (TRUSTED_ENTITY_PREFIXES above all):

  1. The ISO builds at all.
  2. greetd lands in Sway with no login prompt.
  3. Touch input as native wl_touch — same open item as every other touch host.
  4. door-panel-agent connects to Mosquitto and the device appears in HA.
  5. Register via the touchscreen form (Show registration) first, before trying voice — this exercises the whole identity path without needing HA's intent-script wiring set up. See identity/README.md's worked example for that next step.
  6. Voice registration end-to-end: wake word → "register me as <name>" → a spoken confirmation. This is the number of moving pieces (wyoming-satellite, HA's Assist pipeline, the custom sentence/intent script, identity's /register) that has the most to go wrong and the least individual testing so far.
  7. The dashboard's clothing suggestion (identity/frontend/dashboard.js's clothingSuggestion()) is a plain lookup table, untuned against real weather payloads or real household clothing preferences — reasonable starting thresholds, not measured.
  8. Switching between home-kiosk and identity-kiosk actually replaces the window rather than leaving two Chromium instances up — same untested assumption as ../kitchen-display/'s identical pair.
  9. Idle-blank timeout (20 minutes, configs/sway/config) and touch-resume — untested.