Status TV (Grafana wall screens)
Two wall-mounted TVs that show live Grafana dashboards from dash.aholadigital.com, driven by a single Raspberry Pi. Each screen plays its own Grafana playlist that rotates through six (CITY) or seven (ROAD) TV-sized dashboards, one every 2 minutes.
| Screen | Playlist | Dashboards |
|---|---|---|
| Left (CITY) | Status TV - CITY |
City 1–6: TMS overview → TMS services & WebSocket → Planner automations → Taxi grids → Production Vault → Security updates (stable) |
| Right (ROAD) | Status TV - ROAD |
Road 1–7: eazytms Cloud SQL & VM → eazytms services → Ahola Transport → Ahola Special & logs → Road Web Infra → Backendsrv-1 → Road Web Infra apps (supervisord) |
The TV dashboards are screen-sized copies of the team's dashboards, kept in the Grafana folder Status-TV and generated from the config repo. See Status TV Dashboards.
Playlist contents and the rotation interval are managed in Grafana (Dashboards → Playlists), not on the Pi. See Status TV Operations.
How it works
┌──────────────────────── Raspberry Pi 4 (status-tv, 10.10.75.9) ─────────────────────────┐
│ │
│ labwc (Wayland desktop, auto-login) │
│ ├─ kanshi ─────────── both HDMI outputs → 2560x1440@60, HDMI-A-1 left / HDMI-A-2 right│
│ ├─ Chromium kiosk "status-tv-left" ──► HDMI-A-1 (labwc window rule) │
│ └─ Chromium kiosk "status-tv-right" ──► HDMI-A-2 (labwc window rule) │
│ │ │
│ │ http://127.0.0.1:3000/playlists/play/<uid>?kiosk │
│ ▼ │
│ nginx (listens on 127.0.0.1:3000 only) │
│ adds "Authorization: Bearer <service-account token>" │
└──────────────┼──────────────────────────────────────────────────────────────────────────┘
│ HTTPS
▼
Grafana https://dash.aholadigital.com (Google SSO for people;
read-only service account for the TV)
Why a proxy? Grafana's login is Google SSO, which doesn't work on an unattended screen: sessions expire and Google asks for re-authentication or 2FA. A Grafana service account never expires, but its token only works as an HTTP header, and a browser can't send it by itself. The local nginx adds the header to every request, so Chromium is permanently "logged in" with a Viewer-only identity that can be revoked from Grafana with one click.
Key facts
| Hardware | Raspberry Pi 4 Model B, 4 GB RAM, 64 GB SD card |
| OS | Raspberry Pi OS (Debian 13 trixie, 64-bit), labwc desktop, auto-login as statusadmin |
| Address | 10.10.75.9 (wired, eth0), hostname status-tv |
| Screens | 2 × Samsung 4K TV, driven at 2560×1440 @ 60 Hz (a Pi 4 only does 4K at 30 Hz, and two 4K dashboards are too heavy for Chromium) |
| Grafana | self-hosted 12.4 at https://dash.aholadigital.com |
| Grafana identity (TV) | service account indola-status-tv (login sa-1-indola-status-tv), role Viewer, token never expires |
| Grafana identity (TV dashboard scripts) | service account ai-dashboard-editor (login sa-1-ai-dashboard-editor): Viewer everywhere, Editor only in the Status-TV folder. Not on the Pi |
| Time sync | internal NTP 172.31.0.20, 172.31.0.17 (public NTP is blocked on this network) |
| Secrets | Proton Pass: the statusadmin SSH/sudo password and the Grafana service-account token |
| Config repo | Attracs/devops-status-tv: every file on the Pi + the Ansible playbook that deploys it |
Quick reference
| Task | How |
|---|---|
| Change which dashboards rotate, or the interval | Grafana → Dashboards → Playlists → edit, then run ~/status-tv/restart.sh on the Pi |
| Change what a TV dashboard shows | Edit grafana/build.py in devops-status-tv, build, check a screenshot, push. See Status TV Dashboards |
| Change config on the Pi (scripts, nginx, screen layout…) | Edit it in devops-status-tv, then ./deploy.sh --check --diff and ./deploy.sh --diff |
| TVs on/off | Automatic over HDMI-CEC: on 07:00–18:00 Mon–Fri. By hand: ~/status-tv/tv-power.sh on, off or status on the Pi. See TV power schedule |
| Restart both screens | ssh statusadmin@10.10.75.9 '~/status-tv/restart.sh' |
| Show one fixed dashboard instead of a playlist | Edit ~/status-tv/urls.conf on the Pi, then run restart.sh |
| Cut the TV's access to Grafana | Grafana → Administration → Service accounts → indola-status-tv → Disable |
| See what the TVs are showing | Take a screenshot |
Security
- The token is Viewer only. It can read dashboards the Viewer role can see, but it can't edit, save or administer anything.
- nginx listens on
127.0.0.1only, so the token proxy isn't reachable from the network. The default nginx site on port 80 is disabled. - On the Pi, the token is stored in
/etc/nginx/grafana-token.conf(owner root, mode 600). The real token is kept in Proton Pass and never in documentation or git. - If the Pi is lost or stolen, disable or delete the
indola-status-tvservice account in Grafana. That's the only credential on the device that gives access to anything outside the Pi itself.