# 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 ``" 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 ``") 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-agent` — **Show 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 `tools/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 [`tools/build-door-panel-iso.sh`](../../tools/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 ```sh sudo -E tools/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 ``" → 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.