- .github/workflows/release.yml: a tag vX.Y.Z runs the tests, publishes daynivo-kiosk-os-X.Y.Z.tar.gz (+ .sha256) and install-online.sh as a Gitea release, then builds the SD image with pi-gen and attaches it. - install-online.sh: curl | sudo bash installer for the latest release. - voxip-kiosk-updater: checks the latest release, verifies and unpacks a newer one under /opt/daynivo-kiosk-os and runs its update.sh. A daily timer checks around 03:00 and installs when auto_update is on. - Web interface: Systeem -> Software-updates with the auto-update switch, check now and install now (helper verbs update-check / update-install). - CI checks out with plain git, so it runs on Gitea's act_runner too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
278 lines
13 KiB
Markdown
278 lines
13 KiB
Markdown
# Daynivo 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 **Daynivo 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. Download de nieuwste `*-daynivo-kiosk-os-*.img.xz` bij de
|
||
[releases](https://git.rothman.nl/rothman/daynivo-kiosk-os/releases),
|
||
of bouw hem zelf (zie hieronder).
|
||
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
|
||
curl -fsSL https://daynivo.nl/kiosk/install.sh | sudo bash -s -- \
|
||
--url "https://schermen-ijsselflat.voxip.nl" --name "IJsselflat" --hostname ijsselflat
|
||
```
|
||
|
||
`install-online.sh` (dat is wat daynivo.nl serveert, en het hangt ook bij
|
||
elke release) haalt de nieuwste release op, controleert de SHA-256, pakt hem
|
||
uit in `/opt/daynivo-kiosk-os/<versie>` en draait daar `install.sh`. Git is
|
||
niet nodig. Vanuit een clone kan het ook:
|
||
|
||
```bash
|
||
git clone https://git.rothman.nl/rothman/daynivo-kiosk-os.git
|
||
cd daynivo-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 Daynivo-kiosk (`raspberry-pi/install-kiosk.sh` uit
|
||
de Daynivo-repository)? Dan neemt `install.sh` de display-URL (inclusief
|
||
`?token=`) automatisch over en schakelt `display-kiosk.service` uit.
|
||
|
||
### Updaten
|
||
|
||
In de webinterface onder **Systeem → Software-updates**: *Nu controleren*,
|
||
*Bijwerken naar …*, en het vinkje **Automatisch bijwerken**. Elke nacht
|
||
tussen 03:00 en 05:00 (`voxip-kiosk-update.timer`) kijkt de kiosk of er een
|
||
nieuwe release is; met het vinkje aan installeert hij die meteen. Dat werkt
|
||
ook op een apparaat dat met de image of vanuit een clone is geïnstalleerd.
|
||
Vanaf de commandoregel:
|
||
|
||
```bash
|
||
sudo /usr/lib/voxip-kiosk/voxip-kiosk-updater --check # alleen kijken
|
||
sudo /usr/lib/voxip-kiosk/voxip-kiosk-updater --install # nieuwste release installeren
|
||
```
|
||
|
||
De updater installeert alleen een nieuwere versie met een kloppende
|
||
checksum, pakt hem uit in `/opt/daynivo-kiosk-os/<versie>` (de laatste twee
|
||
blijven bewaard) en draait daar `update.sh --no-pull`. Vanuit een clone kan
|
||
het ook met git:
|
||
|
||
```bash
|
||
cd daynivo-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>-daynivo-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` | `Daynivo 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.
|
||
|
||
## Releases
|
||
|
||
Een release maak je door `VERSION` te verhogen, te committen en een tag met
|
||
hetzelfde nummer te pushen:
|
||
|
||
```bash
|
||
echo 1.2.0 > VERSION && git commit -am "Release 1.2.0"
|
||
git tag v1.2.0 && git push && git push origin v1.2.0
|
||
```
|
||
|
||
Gitea Actions (`.github/workflows/release.yml`) draait dan de tests en maakt
|
||
een release met `daynivo-kiosk-os-<versie>.tar.gz` (+ `.sha256`) en
|
||
`install-online.sh`. Daarna bouwt dezelfde workflow het SD-image en hangt het
|
||
`.img.xz` (+ `.sha256`) aan dezelfde release; dat duurt 30 tot 90 minuten of
|
||
langer. Zodra de tar-bestanden er staan, zien de kiosks de nieuwe versie.
|
||
|
||
Vereist op de Gitea-server:
|
||
|
||
- een **act_runner** met het label `ubuntu-latest`;
|
||
- voor het image: `container.privileged: true` in de runnerconfiguratie
|
||
(pi-gen heeft loop-devices en binfmt_misc nodig) en genoeg schijfruimte
|
||
(± 15 GB tijdens het bouwen);
|
||
- de maximale bijlagegrootte (`[attachment] MAX_SIZE` in `app.ini`, in MB)
|
||
groter dan het image (± 1 GB);
|
||
- optioneel een repository-secret `RELEASE_TOKEN` (token met schrijfrecht op
|
||
de repository), als het standaardtoken van de workflow geen releases mag
|
||
maken.
|
||
|
||
## 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` | `Daynivo 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) |
|
||
| `auto_update` | `false` | elke nacht een nieuwe release installeren |
|
||
|
||
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`.
|
||
|
||
### Daynivo-schermen
|
||
|
||
Voor een Daynivo-display gebruik je als `url` de kiosk-URL van het scherm
|
||
uit Daynivo (*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. Daynivo 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. |
|