VoxIP Kiosk OS 1.0.0: Raspberry Pi kiosk with web management
CI / test-bookworm (push) Failing after 11s
CI / test-latest (push) Successful in 1m27s

Chromium kiosk without a desktop for the Raspberry Pi 3, a Flask web
interface on port 8080 (kiosk, system and network management), a
restricted root helper, network changes with automatic rollback, a
healthcheck timer, install/update/uninstall scripts and a pi-gen image
build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rothmanandClaude Opus 5.5 committed 2026-11-04 21:38:49 +01:00
commit a33c4822bf
96 files changed
+7535

No files matched your search

+221
View File
@@ -0,0 +1,221 @@
# VoxIP Kiosk OS
Lichte, onderhoudbare kioskdistributie voor de Raspberry Pi 3 (Model B/B+)
op basis van Raspberry Pi OS Lite 32-bit (Bookworm of Trixie). Na het
opstarten toont Chromium fullscreen één HTTPS-pagina. Beheer gaat via de
webinterface **VoxIP Kiosk Manager** op `http://kiosk.local:8080`.
- Geen desktopomgeving: alleen een minimale X-server plus Chromium.
- Herstelt zichzelf: browsercrashes, een vastgelopen pagina, netwerkuitval
en stroomuitval.
- Geen standaardwachtwoorden: de eerste beheerder claimt het apparaat met
een setupcode die op het scherm staat.
- Netwerkwijzigingen met automatische rollback.
- Geen klantspecifieke code: alles per klant staat in
`/etc/voxip-kiosk/config.json` en kan bij uitrol via de bootpartitie
worden meegegeven.
De architectuur en de veiligheidskeuzes staan in
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md). De testprocedure op echte
hardware staat in [`docs/HARDWARE-TEST.md`](docs/HARDWARE-TEST.md).
## Snel aan de slag
### Optie A — kant-en-klare image
1. Bouw de image (zie hieronder) of gebruik een uitgebrachte
`*-voxip-kiosk-os-*.img.xz`.
2. Schrijf hem met **Raspberry Pi Imager** (*Eigen image gebruiken*) of
**balenaEtcher** naar een microSD-kaart van 16 GB of groter.
3. Optioneel, in Raspberry Pi Imager → *OS-aanpassingen*: wifi, gebruiker
met wachtwoord en/of SSH-sleutel, tijdzone. Zonder aanpassingen heeft de
image **geen** bruikbaar wachtwoord en staat SSH uit.
4. Optioneel: zet een `voxip-config.json` op de bootpartitie (zie
[Uitrol bij meerdere klanten](#uitrol-bij-meerdere-klanten)).
5. Start de Pi. Bij de eerste boot wordt de rootpartitie automatisch
vergroot tot de hele SD-kaart. Daarna verschijnt een setupscherm met de
setupcode en het adres van de beheerinterface.
6. Open `http://kiosk.local:8080` (of het getoonde IP-adres), voer de
setupcode in en kies een uniek beheerderswachtwoord.
### Optie B — installeren op een bestaande Raspberry Pi OS Lite
Vereist: Raspberry Pi OS Lite Bookworm of Trixie met NetworkManager (de
standaard sinds Bookworm).
```bash
sudo apt-get install -y git
git clone <url-van-deze-repository> voxip-kiosk-os
cd voxip-kiosk-os
sudo ./install.sh --url "https://schermen-ijsselflat.voxip.nl" --name "IJsselflat" --hostname ijsselflat
```
Alle opties zijn optioneel. Het script installeert de benodigde pakketten,
maakt de gebruikers `kiosk` en `voxip` aan, installeert de services en
start de kiosk. Aan het eind toont het de setupcode.
Draaide hier eerder de InfoFlow-kiosk (`raspberry-pi/install-kiosk.sh` uit
de InfoFlow-repository)? Dan neemt `install.sh` de display-URL (inclusief
`?token=`) automatisch over en schakelt `display-kiosk.service` uit.
### Updaten
```bash
cd voxip-kiosk-os
sudo ./update.sh # git pull --ff-only + back-up van /etc/voxip-kiosk + install.sh --upgrade
```
Een update overschrijft nooit bestaande configuratie of het
beheerderswachtwoord. Back-ups staan in `/var/backups/voxip-kiosk-*.tar.gz`
(de laatste vijf). Op een apparaat met de image staat de broncode in
`/usr/src/voxip-kiosk`. Clone de repository voor updates naar een eigen map,
of pak een release uit en draai daar `sudo ./update.sh --no-pull`.
### Verwijderen
```bash
sudo ./uninstall.sh # programma's en services weg, configuratie blijft
sudo ./uninstall.sh --purge # ook configuratie, status, logs, netwerkprofielen en gebruikers
```
## Image bouwen
Het image wordt gebouwd met [pi-gen](https://github.com/RPi-Distro/pi-gen),
de officiële bouwtool van Raspberry Pi OS. De extra stage
`image/stage-voxip` voert hetzelfde `install.sh` uit als een handmatige
installatie.
Vereist: een Linux-buildmachine (x86_64 of arm64) met Docker en git. Op
x86_64 is ook `binfmt`/qemu nodig voor ARM-emulatie:
```bash
sudo apt-get install -y qemu-user-static binfmt-support # alleen op x86_64
./image/build.sh # bouwt in Docker
# of zonder Docker, op Debian/Ubuntu met de pi-gen-afhankelijkheden:
sudo ./image/build.sh --native
```
Resultaat: `image/deploy/<datum>-voxip-kiosk-os-<versie>.img.xz` plus een
`.sha256` en `BUILD-INFO-<versie>.txt`.
Instelbaar via omgevingsvariabelen:
| Variabele | Standaard | Betekenis |
|---|---|---|
| `PI_GEN_REF` | `2024-11-19-raspios-bookworm-armhf` | pi-gen-tag (32-bit) |
| `RELEASE` | `bookworm` | `bookworm` of `trixie` (moet bij `PI_GEN_REF` passen) |
| `VOXIP_DEFAULT_URL` | `https://schermen-ijsselflat.voxip.nl` | standaard kiosk-URL |
| `VOXIP_DEVICE_NAME` | `VoxIP Kiosk` | standaard apparaatnaam |
| `TARGET_HOSTNAME` | `kiosk` | hostname (`http://<hostname>.local:8080`) |
| `ALLOW_DIRTY` | `0` | `1` = bouw de werkmap in plaats van de laatste commit |
**Reproduceerbaarheid.** pi-gen staat vast op een tag en de broncode
gaat via `git archive` van één commit mee. Beide staan in `BUILD-INFO`
(ook in de image: `/usr/share/voxip-kiosk/BUILD-INFO`). De Debian- en
Raspberry Pi-pakketten komen uit de archieven zoals die op het moment van
bouwen zijn. Er bestaat geen snapshot-archief voor Raspberry Pi OS, dus
twee builds op verschillende dagen kunnen nieuwere pakketversies bevatten.
Bewaar voor een uitrol daarom de gebouwde `.img.xz` zelf.
## Beheer
### Webinterface — `http://<hostname>.local:8080`
| Pagina | Functies |
|---|---|
| **Dashboard** | Chromium-status, kiosk-URL, uptime, CPU, temperatuur, voeding (onderspanning), RAM, SD-kaart, IP-adressen, verbinding, versie. Grote knoppen voor *Pagina herladen*, *Chromium herstarten* en *Raspberry Pi herstarten*. |
| **Kiosk** | URL (alleen HTTPS), apparaatnaam, automatisch verversen, browserprofiel, herstart na crash, screenshot van het scherm, laatste meldingen. |
| **Systeem** | Herstarten, veilig uitschakelen, hostname, rotatie, resolutie, zoom, screensaver/DPMS, poort/HTTPS van de beheerinterface. |
| **Netwerk** | Status van ethernet en wifi, wifi scannen, wifi instellen, DHCP of statisch IP, DNS, wifi-land. Iedere wijziging moet binnen 3 minuten bevestigd worden, anders volgt een rollback. |
| **Logboek** | Logs per onderdeel (kiosk, Chromium, agent, healthcheck, beheer, netwerk, systeem). |
*Pagina herladen* gebruikt het Chrome DevTools Protocol op localhost: de
browser blijft draaien. *Chromium herstarten* herstart alleen de browser.
*Raspberry Pi herstarten* herstart het hele systeem.
### Commandoregel (via SSH)
```bash
sudo voxip-kiosk-ctl status # overzicht
sudo voxip-kiosk-ctl setup-code # setupcode voor de eerste configuratie
sudo voxip-kiosk-ctl reset-password # wachtwoord vergeten: nieuwe setupcode
sudo voxip-kiosk-ctl set-url https://… # URL wijzigen
sudo voxip-kiosk-ctl reload # pagina herladen
sudo voxip-kiosk-ctl restart-browser # Chromium herstarten
sudo voxip-kiosk-ctl health # healthcheck-rapport
sudo voxip-kiosk-ctl maintenance on|off # healthcheck tijdelijk niets laten herstellen
journalctl -u voxip-kiosk-browser -u voxip-kiosk-agent -f
```
### Configuratie — `/etc/voxip-kiosk/config.json`
| Sleutel | Standaard | Betekenis |
|---|---|---|
| `device_name` | `VoxIP Kiosk` | naam in beheer en op de offlinepagina |
| `url` | `https://schermen-ijsselflat.voxip.nl` | kiosk-URL, alleen HTTPS |
| `refresh_interval` | `0` | 0 = uit, anders 30–86400 seconden |
| `screen_always_on` | `true` | geen screensaver/DPMS |
| `screen_off_minutes` | `10` | scherm uit na N minuten (als `screen_always_on` uit staat) |
| `rotation` | `0` | 0, 90, 180, 270 |
| `resolution` | `auto` | `auto` of bijv. `1920x1080` / `1280x720@60` |
| `zoom` | `1.0` | 0,25–4, schaalt de pagina (grote tv's) |
| `browser_restart` | `true` | Chromium automatisch herstarten na een crash |
| `browser_profile` | `persistent` | `persistent` = cookies en offline-cache blijven bewaard, `ephemeral` = alleen in RAM |
| `admin_port` | `8080` | poort van de beheerinterface |
| `admin_https` | `false` | HTTPS met zelfondertekend certificaat |
| `admin_allow_public` | `false` | ook toegang vanaf publieke IP-adressen (afgeraden) |
Wijzigingen via de webinterface of `voxip-kiosk-ctl` worden atomair
opgeslagen, met een `.bak` van de vorige versie. Een URL-wijziging gaat in
zonder dat Chromium herstart. Scherminstellingen gelden na een herstart van
Chromium (een vinkje in de webinterface doet dat direct).
## Uitrol bij meerdere klanten
Eén image voor alle klanten. Per apparaat zet je na het flashen op de
bootpartitie (`bootfs`, zichtbaar op Windows en macOS):
- **`voxip-config.json`**: instellingen voor deze kiosk, plus optioneel
`hostname` en `wifi_country`. Een voorbeeld staat als
`voxip-config.example.json` op de bootpartitie.
- **`voxip-authorized_keys`**: openbare SSH-sleutels. SSH gaat dan aan, alleen
met sleutel-login.
- Wifi en een eigen gebruiker stel je in via Raspberry Pi Imager.
De bestanden worden bij het opstarten verwerkt en hernoemd naar
`*.applied`, of naar `*.rejected` met de reden in `voxip-config.error.txt`.
### InfoFlow-schermen
Voor een InfoFlow-display gebruik je als `url` de kiosk-URL van het scherm
uit InfoFlow (*Schermen* → scherm → kiosk-URL, inclusief `?token=`). Het
token wordt in de webinterface, de CLI en de logs afgeschermd
(`?token=…ab12`). De kiosk laat een lopende pagina staan als het netwerk
wegvalt. InfoFlow toont dan zijn eigen laatst bekende inhoud, en
automatisch verversen wordt overgeslagen zolang de server niet bereikbaar
is.
## Ontwikkelen en testen
```bash
python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest # unit- en webtests
make lint # shellcheck (indien geïnstalleerd)
make test-bookworm # dezelfde tests in Debian Bookworm met de apt-pakketten van de Pi (Docker)
```
Lokaal draaien van de webinterface (zonder Pi; systeemacties falen netjes):
```bash
make dev # http://127.0.0.1:8080 met tijdelijke mappen in .dev/
```
## Probleemoplossing
| Symptoom | Oplossing |
|---|---|
| Zwart scherm na opstarten | `sudo voxip-kiosk-ctl status`. Kijk in de journal van `voxip-kiosk-x`/`voxip-kiosk-browser`. Staat de monitor aan vóór de Pi? |
| Beheerinterface onbereikbaar na netwerkwijziging | Wacht 3 minuten (automatische rollback) of zet `voxip-network-reset` op de bootpartitie en herstart. |
| Wachtwoord vergeten | `sudo voxip-kiosk-ctl reset-password` via SSH, of verwijder `/etc/voxip-kiosk/admin.json` met de SD-kaart in een Linux-pc. |
| `kiosk.local` werkt niet | Gebruik het IP-adres (staat op het setupscherm en in je router). Windows heeft soms Bonjour/mDNS nodig. Geef iedere kiosk een unieke hostname. |
| Onderspanning in het dashboard | Gebruik de officiële 5,1 V/2,5 A-voeding. Onderspanning veroorzaakt crashes en SD-kaartcorruptie. |