CI / verify (pull_request) Successful in 1m28s
CI / infrastructure-smoke (pull_request) Successful in 40s
CI / package-release (pull_request) Successful in 47s
CI / image-build (pull_request) Successful in 59s
CI / migration-smoke (pull_request) Successful in 2m8s
CI / deploy-smoke (same-origin) (pull_request) Successful in 49s
CI / deploy-smoke (split) (pull_request) Successful in 2m38s
CI / package-publication (pull_request) Successful in 1m1s
ADR 0056 (Zayin/Ekklesia#94) replaces the fixed 180 days from pairing with 180 days from last use, renewed while the screen is in use; the guide no longer tells operators to track pairing dates. Co-Authored-By: Claude Opus 5.5 <[email protected]>
131 lines
6.6 KiB
Markdown
131 lines
6.6 KiB
Markdown
# Setting up a display kiosk
|
|
|
|
A display is a screen — a television with a small computer, or a mini PC on a wall — that opens one
|
|
module's display page full screen and keeps it open unattended. This guide sets one up so it starts
|
|
on boot, stays paired, recovers from network and server outages on its own, and never opens a second
|
|
copy of itself.
|
|
|
|
Pairing and display identity belong to the platform (ADR 0036). Today an administrator approves a
|
|
screen in the Dashboard sidebar's **Display devices** panel; a later release moves this to
|
|
**Settings → Displays**. Nothing below changes when that happens.
|
|
|
|
## What the screen needs
|
|
|
|
- Chromium or Google Chrome, current stable. The display page is tested against Chromium.
|
|
- A **dedicated, persistent browser profile directory**. The device credential is an HttpOnly cookie
|
|
in that profile; it is what keeps the screen paired across reboots. Never use a guest, incognito, or
|
|
"clear data on exit" profile, and never share the profile with a person's browsing.
|
|
- Network access to the installation's **API hostname** (the display page, its realtime stream, and
|
|
its module requests) and to the storage hostname that serves images.
|
|
- A clock that is roughly right. Playback follows the server's clock, but TLS does not tolerate a
|
|
wildly wrong one.
|
|
|
|
## The address
|
|
|
|
Every display-capable module has one display page on the API hostname:
|
|
|
|
```text
|
|
https://<api-hostname>/display/<module-id>
|
|
```
|
|
|
|
For Signage that is `https://<api-hostname>/display/signage`. The Signage **Displays** tab shows the
|
|
exact address under **Copy setup address**. Open it on the screen itself; opening it on an
|
|
administrator's own computer only previews the display (and that browser appears in the roster as a
|
|
*Signed-in browser*, which can be removed once it is offline).
|
|
|
|
## Launching the browser
|
|
|
|
Run exactly **one** launcher, and launch the page as an app window with a fixed profile:
|
|
|
|
```bash
|
|
chromium \
|
|
--user-data-dir=/var/lib/display-kiosk/profile \
|
|
--app=https://<api-hostname>/display/signage \
|
|
--kiosk \
|
|
--no-first-run \
|
|
--noerrdialogs \
|
|
--disable-session-crashed-bubble \
|
|
--hide-crash-restore-bubble \
|
|
--disable-features=Translate \
|
|
--autoplay-policy=no-user-gesture-required \
|
|
--check-for-update-interval=31536000
|
|
```
|
|
|
|
- `--app` opens the page with no tab strip and no address bar. `--kiosk` makes it full screen.
|
|
- `--user-data-dir` is the persistent profile that holds the pairing. Keep it on persistent storage
|
|
and back it up with nothing: if it is lost, the screen simply shows a new pairing code.
|
|
- Do **not** add `--restore-last-session`, and do not also start the browser from a desktop autostart
|
|
entry. Chromium allows one process per profile; a second launch hands its URL to the running
|
|
process, which opens a **second window or tab** of the display. That is the usual cause of
|
|
"duplicate" displays. One launcher, one profile, one window.
|
|
|
|
### Start on boot and restart on exit (systemd)
|
|
|
|
Run the browser as an unprivileged user in that user's graphical session, from a single user unit:
|
|
|
|
```ini
|
|
# ~/.config/systemd/user/display-kiosk.service
|
|
[Unit]
|
|
Description=Display kiosk
|
|
After=graphical-session.target network-online.target
|
|
Wants=network-online.target
|
|
PartOf=graphical-session.target
|
|
|
|
[Service]
|
|
ExecStart=/usr/bin/chromium --user-data-dir=%h/.local/share/display-kiosk --app=https://<api-hostname>/display/signage --kiosk --no-first-run --noerrdialogs --disable-session-crashed-bubble --hide-crash-restore-bubble --disable-features=Translate --autoplay-policy=no-user-gesture-required --check-for-update-interval=31536000
|
|
Restart=always
|
|
RestartSec=5
|
|
|
|
[Install]
|
|
WantedBy=graphical-session.target
|
|
```
|
|
|
|
```bash
|
|
systemctl --user daemon-reload
|
|
systemctl --user enable --now display-kiosk.service
|
|
loginctl enable-linger <kiosk-user> # with the desktop set to log this user in automatically
|
|
```
|
|
|
|
`systemctl --user stop display-kiosk` closes the browser cleanly, which is what keeps its profile —
|
|
and the pairing cookie — intact. Avoid cutting power to a running kiosk when you can: a clean shutdown
|
|
is always safer for a browser profile.
|
|
|
|
## Pairing
|
|
|
|
1. Start the kiosk. With no credential it shows a **six-digit pairing code**.
|
|
2. In the Dashboard, enter the code under **Display devices**, give the screen a name, and approve.
|
|
3. Within a few seconds the screen collects its credential and starts showing content.
|
|
4. In Signage → **Displays**, name the display and choose its group and audience.
|
|
|
|
A paired screen stays paired across browser restarts and reboots, and for as long as it is in use:
|
|
its credential is renewed each time it checks in, and only expires after **180 days without being
|
|
used** (ADR 0056). A screen that is switched off and stored for longer than that, or that is revoked,
|
|
returns to its pairing code and is paired again the same way.
|
|
|
|
## What happens when things go wrong
|
|
|
|
| Event | What the screen does |
|
|
| --- | --- |
|
|
| Network drops for seconds | Nothing visible. The display keeps running; the realtime stream reconnects. |
|
|
| Network or API down for longer | Keeps playing what it has cached, with a small corner note; recovers by itself when the server is back. No remount, no reload. |
|
|
| API restarted or upgraded | Reconnects by itself. A new module version is picked up within five minutes and swapped in. |
|
|
| Browser crashes or is restarted | systemd restarts it; the same profile is still paired. |
|
|
| Machine reboots | Starts on boot and resumes. If the server is not up yet, the screen retries on its own (every few seconds, backing off to once a minute) until it is. |
|
|
| Display revoked in the Dashboard | Stops showing content within seconds and returns to its pairing code. |
|
|
| Display moved to another group or audience | Switches content within about one heartbeat (≈12 s), no reload. |
|
|
|
|
**Offline cold start is not supported yet.** A screen that is already showing content survives an
|
|
outage. A screen that *boots* while the server is completely unreachable can load its cached page but
|
|
cannot mount the module until the server answers, because the authorization it needs is never cached
|
|
(ADR 0043, Signage ADR 0006). It shows a short message and retries on its own until the server is
|
|
reachable — nobody needs to touch it.
|
|
|
|
## Checklist for a new kiosk
|
|
|
|
- [ ] One systemd unit, no desktop autostart entry, no second launcher.
|
|
- [ ] `--user-data-dir` on persistent storage, not shared, not cleared on exit.
|
|
- [ ] Automatic login of the kiosk user, and screen blanking/power saving disabled.
|
|
- [ ] Paired and named; assigned in Signage.
|
|
- [ ] Unplug the network for a minute: content keeps playing, then the note clears on reconnect.
|
|
- [ ] Reboot: the screen comes back paired without anyone touching it.
|