Files
home/reference/kiosk.md
T
Donavan Fritz aae54442e5 kiosk: document per-house config via ?zip= / ?name= query params
Location + house name are now KIOSK_URL query params (zip geocoded to
coords + place + timezone). Drop the hardcoded 55331/America/Chicago
language; record the defaults and how to point a screen at another house.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:44:37 -05:00

79 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kiosks (wall displays)
<what>Full-screen web kiosks on the two Nest compute nodes, each driving its attached display (DP/HDMI) via Chromium. Run as Kubernetes pods on the msp001 cluster (the Nest site). Infra/build/troubleshooting: see fritzlab skill `msp001.md` <kiosk> + the `fritzlab/kiosk` repo.</what>
<screens>
| Node | Pod (ns `kiosk`) | Output | Showing |
|---|---|---|---|
| host101 | `kiosk-host101` | card0-DP-1 (4K) | kiosk.vino.network |
| host102 | `kiosk-host102` | card0-DP-1 (4K) | kiosk.vino.network |
Each node drives one screen; multi-screen would need host100's GT 730 (see KIOSK-DESIGN.md).
</screens>
<resolution>
Design target = **3840×2160 (4K UHD), devicePixelRatio 1, 24-bit color,
landscape-primary**. Both displays render at native 4K; the Chromium kiosk
has no toolbar/taskbar, so viewport == screen == avail.screen == 3840×2160
(no CSS px scaling — 1 CSS px = 1 device px). Layout for the kiosk page should
look right at full 4K landscape. (Confirmed on-screen 2026-06-01.)
</resolution>
<the-kiosk-page>
The default page both screens show is `https://kiosk.vino.network` — an
editorial wall-art homepage: a **live iOS-Weather-style animated sky** +
live local-time clock + current weather from `api.open-meteo.com`. The
sky is driven by the Open-Meteo `weather_code` (+ `wind_speed`) +
`sunrise`/`sunset`: sun (clear/partly days) and moon (clear/partly nights)
**arc across the sky by real time-of-day**, with a warm dawn/dusk horizon
glow. Conditions rendered: clear, partly, cloudy, fog, drizzle, rain,
**sleet/freezing-rain (ice)**, snow (**blizzard/blowing-snow when wind
≥24 mph**), thunderstorm (**hail on codes 96/99**), plus stars on clear
nights and lightning in storms. The **moon mirrors its
actual phase** (lit fraction + waxing/waning terminator, computed locally
from the date — NOT an extra API call). Weather fetches on load then every
10m, with **fast retry-with-backoff (15s→5m) while failing** so a fetch that
fails at pod start doesn't sit on "Weather unavailable" for the full 10m
(fixed 2026-06-04; live weather scene 2026-06-04). A frozen clock/stale weather on one screen =
that node's Chromium (or the whole node) is wedged, NOT a page bug — the
display holds the last-good frame; recover by graceful pod restart (and see
fritzlab `msp001.md` <kiosk> if the node itself is unreachable).
Source repo: `websites/kiosk.vino.network` (clone at `~/code/git/code.fritzlab.net/websites/kiosk.vino.network/`),
content in `html/`, served from Garage S3 via the standard site-publish flow
(fritzlab `gitops.md` <static-sites>).
<per-house-config>Location + house name are **query params on `KIOSK_URL`**, so
one page serves any household: `?zip=<us-zip>&name=<House%20Name>`. `name` sets
the eyebrow + tab title; `zip` is geocoded once at load (Zippopotam.us) → lat/lon
+ "City, State" place line, and Open-Meteo runs `timezone=auto` so the clock
follows that zip's timezone. No params → Hawks Nest / Minnetrista 55331 /
`America/Chicago` defaults (bad zip falls back to these too). To point a screen
at a different house, set `KIOSK_URL=https://kiosk.vino.network/?zip=...&name=...`
per pod via GitOps (see <change-page> for the apps-repo edit + hard-refresh).</per-house-config>
**"Update the kiosk page" = edit the page content**, NOT the KIOSK_URL: edit
`html/index.html` (or `404.html`) in that repo, commit + push to main → the
`Publish` Gitea Action (site-publish) syncs to the bucket in ~30s. Verify with
`curl -s https://kiosk.vino.network/`.
**How screens actually pick up a new deploy:** the Chromium kiosk fetches the
URL ONCE at pod start and never re-polls on its own (`entrypoint.sh` only
re-fetches if cage/chromium exits or the pod restarts) — `Cache-Control:
must-revalidate` alone does NOT update a running screen. So the PAGE must
self-reload. `index.html` polls its own ETag every 5m and `location.reload()`s
only when it changes (no periodic flashing). Any new kiosk page MUST carry that
ETag-poll snippet, else the screens stay on the old content until a pod restart.
</the-kiosk-page>
<change-page>
This changes WHICH URL a screen loads (different site), distinct from updating
the kiosk page content above. The displayed URL is the `KIOSK_URL` env per pod.
**GitOps (only reliable way):** edit `KIOSK_URL` in `fritzlab/apps/msp001/kiosk/kiosk/manifests/deployments.yaml` (block `kiosk-host101` or `kiosk-host102`), commit + push to `apps` main, then force the sync now instead of waiting ~3min for the poll: `kubectl --context msp001 -n argocd annotate application kiosk --overwrite argocd.argoproj.io/refresh=hard`. Pod recreates on the new page.
**Do NOT use `kubectl set env` for this:** ArgoCD selfHeal reverts it to the *stale* git target (the value from the last commit it polled, not your new one) within seconds — the pod recreates but on the old URL. Push to git + hard-refresh instead. (Verified 2026-06-01.)
</change-page>
<verify>`kubectl --context msp001 get pods -n kiosk` (want 1/1 Running). On-screen page check needs a screenshot via Chromium CDP (localhost-only) — see fritzlab `msp001.md` <kiosk>. Blank-screen causes: (1) cage logs `Swapchain for output ... failed test` on repeat → dirty DRM/GBM state from an UNCLEAN prior exit; (2) `getty@tty1` re-took DRM master (re-mask on the node); (3) page down (Chromium holds last-good frame).</verify>
<restart>**Restart kiosk pods GRACEFULLY — never `--force`/`--grace-period=0`.** A hard kill stops cage from dropping DRM master, leaving the next cage with a dirty swapchain → black. Use `kubectl --context msp001 delete pod -n kiosk -l node=host101` (or `rollout restart deploy -n kiosk`). The image self-heals a wedged swapchain in-pod (entrypoint kills+relaunches cage after 5 swapchain failures) and a `tcpSocket:9222` liveness probe restarts a dead Chromium — but a clean shutdown is still the first line of defense. Recovery for an already-black screen = one graceful delete. (Diagnosed + hardened 2026-06-01.)</restart>
<other-options>Want a dashboard, photo slideshow, or Home Assistant wall panel instead of a website — just point `KIOSK_URL` at it (e.g. `https://home.vino.network`). [[home-assistant]] for HA URLs.</other-options>