commit 28055e6bc76cf8e8c2f2f5fc3b16cb94a1d333e8 Author: Przemysław Kiełkowski Date: Tue May 5 15:54:08 2026 +0200 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..4adb3fe --- /dev/null +++ b/README.md @@ -0,0 +1,168 @@ +# Kiosk Chromium — Debian 13 (trixie) — Dell OptiPlex 3040 + +Kiosk wyświetlający stronę `http://instrukcje.local` w Chromium na pełnym ekranie. Używa `sway` jako kompozytora Wayland oraz `swayidle` + `wlopm` do zarządzania energią monitora. + +--- + +## Wymagania + +- Dell OptiPlex 3040, monitor DP lub HDMI +- Debian 13 (trixie) netinst — instalacja minimalna bez środowiska graficznego + +--- + +## Instalacja krok po kroku + +### 1. Utwórz użytkownika kiosk + +```bash +useradd -m -r -s /usr/sbin/nologin kiosk +usermod -aG tty,input,video,dialout kiosk +``` + +### 2. Zainstaluj pakiety + +```bash +apt update && apt install -y \ + sway swayidle wlopm wlr-randr \ + chromium +``` + +> `cage` **nie** obsługuje protokołu `wlr-output-power-management-v1`, przez co `wlopm` z nim nie działa — ekran można wygasić, ale nie można go wybudzić. Dlatego używamy `sway`. + +### 3. Skopiuj pliki konfiguracyjne + +```bash +# Skrypt zarządzający kioskiem +cp kiosk-manager.sh /home/kiosk/kiosk-manager.sh +chmod +x /home/kiosk/kiosk-manager.sh + +# Strona oczekiwania na sieć +cp waiting.html /home/kiosk/waiting.html +chown kiosk:kiosk /home/kiosk/waiting.html + +# Konfiguracja sway +mkdir -p /home/kiosk/.config/sway +cp sway-config /home/kiosk/.config/sway/config +chown -R kiosk:kiosk /home/kiosk/.config + +# Jednostka systemd +cp kiosk.service /etc/systemd/system/kiosk.service +``` + +### 4. Włącz i uruchom serwis + +```bash +systemctl daemon-reload +systemctl enable kiosk.service +systemctl start kiosk.service +``` + +--- + +## Opis plików + +### `kiosk.service` + +Jednostka systemd uruchamiająca `sway` jako użytkownik `kiosk`. Ważne parametry: + +| Opcja | Wartość | Opis | +|---|---|---| +| `PAMName=login` | `login` | Dostęp do urządzeń przez logind (GPU, input) | +| `RuntimeDirectory=kiosk` | `kiosk` | Automatycznie tworzy `/run/kiosk` z prawami 0700 | +| `XDG_RUNTIME_DIR` | `/run/kiosk` | Wymagane przez sway / Wayland | +| `WLR_LIBSEAT_BACKEND` | `logind` | Dostęp do GPU bez uprawnień roota | +| `IDLE_TIME` | `120` | Czas bezczynności (sekundy) przed wygaszeniem ekranu | +| `ExecStart` | `/usr/bin/sway` | Kompozytor Wayland | +| `Restart=always` | — | Automatyczny restart po awarii / wyjściu Chromium | + +**Zmiana czasu wygaszania:** +```bash +# Edytuj /etc/systemd/system/kiosk.service +Environment=IDLE_TIME=300 # 5 minut + +systemctl daemon-reload +systemctl restart kiosk.service +``` + +--- + +### `sway-config` → `/home/kiosk/.config/sway/config` + +Minimalna konfiguracja sway: + +``` +output * bg #000000 solid_color # czarne tło +output * transform 90 # obrót monitora o 90° (usuń jeśli zbędne) +exec swayidle before-sleep "wlopm --off '*'" # wygaszenie przy sleep +exec /home/kiosk/kiosk-manager.sh # start kiosku +``` + +--- + +### `kiosk-manager.sh` → `/home/kiosk/kiosk-manager.sh` + +Uruchamiany przez sway przy starcie sesji. Kolejność działania: + +1. Uruchamia `swayidle` **bez flagi `-w`** — ignoruje idle inhibitory (Chromium ustawia inhibitor Wayland; `swayidle -w` respektuje go i nigdy nie wygasiłby ekranu) +2. `wlopm --off '*'` po IDLE_TIME sekundach — wysyła DPMS standby przez protokół `wlr-output-power-management-v1`; link DP/HDMI pozostaje aktywny, więc wybudzenie jest niezawodne +3. Chromium startuje **natychmiast** z lokalnym plikiem `waiting.html` (ekran oczekiwania) +4. Ping-loop czeka, aż `KIOSK_HOST` (192.168.40.126) odpowie +5. Po uzyskaniu sieci: Chromium jest zamykany i restartowany z docelowym `http://instrukcje.local` + +**Zmiana adresu IP serwera:** +```bash +# W kiosk-manager.sh zmień zmienną: +KIOSK_HOST="192.168.40.126" +``` + +### `waiting.html` → `/home/kiosk/waiting.html` + +Lokalna strona HTML wyświetlana przez Chromium w trakcie oczekiwania na sieć. Ciemne tło, animowany spinner i pulsujący napis „Oczekiwanie na sieć...". + +--- + +## Zarządzanie i diagnostyka + +### Logi + +```bash +# Ostatnie 100 linii logów serwisu +journalctl -u kiosk.service -b --no-pager -n 100 -o cat + +# Śledzenie na żywo +journalctl -u kiosk.service -f +``` + +### Restart / zatrzymanie + +```bash +systemctl restart kiosk.service +systemctl stop kiosk.service +``` + +### Sprawdzenie wyjść wideo + +```bash +WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/kiosk wlr-randr +``` + +### Ręczne wygaszenie / wybudzenie + +```bash +WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/kiosk wlopm --off '*' +WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/kiosk wlopm --on '*' +``` + +--- + +## Rozwiązywanie problemów + +| Objaw | Przyczyna | Rozwiązanie | +|---|---|---| +| Serwis natychmiast się kończy | Brak `/run/kiosk` | Sprawdź `RuntimeDirectory=kiosk` w pliku unit | +| `XDG_RUNTIME_DIR is not set` | Brak zmiennej środowiskowej | Upewnij się że `Environment=XDG_RUNTIME_DIR=/run/kiosk` jest w unit | +| Ekran się nie wygasza | Chromium blokuje idle | `swayidle` musi być uruchomiony **bez** flagi `-w` | +| Ekran gaśnie ale nie wraca | `wlr-randr --off` rozłącza link DRM | Używaj `wlopm` z `sway` (nie `wlr-randr --off`) | +| `wlopm: Wayland server does not support...` | Kompozytor bez protokołu power-management | Zamień `cage` na `sway` | +| Czarny ekran po restarcie | Chromium trzyma zablokowany profil | `rm -rf /home/kiosk/.cache/chromium && systemctl restart kiosk.service` | diff --git a/kiosk-manager.sh b/kiosk-manager.sh new file mode 100644 index 0000000..615d4c6 --- /dev/null +++ b/kiosk-manager.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +IDLE_TIME=${IDLE_TIME:-300} +KIOSK_HOST="192.168.40.126" +KIOSK_URL="http://instrukcje.local" +WAITING_PAGE="file:///home/kiosk/waiting.html" + +CHROMIUM_OPTS=( + --ozone-platform=wayland + --no-first-run + --noerrdialogs + --disable-infobars + --disable-gpu-suspend + --force-device-scale-factor=1 + --user-data-dir=/home/kiosk/.cache/chromium +) + +# wlopm działa z sway (obsługuje wlr-output-power-management-v1) +# swayidle bez -w: ignoruje idle inhibitory (np. z Chromium) +swayidle \ + timeout "$IDLE_TIME" "wlopm --off '*'" \ + resume "wlopm --on '*'" & + +# Uruchom Chromium od razu z lokalną stroną oczekiwania +chromium --kiosk --app="$WAITING_PAGE" "${CHROMIUM_OPTS[@]}" & +CHROMIUM_PID=$! + +# Czekaj na dostępność serwera kiosku +while ! ping -c 1 -W 1 "$KIOSK_HOST" > /dev/null 2>&1; do + sleep 1 +done + +# Sieć dostępna — zamknij Chromium i uruchom właściwy kiosk +kill "$CHROMIUM_PID" +wait "$CHROMIUM_PID" 2>/dev/null + +exec chromium --kiosk --app="$KIOSK_URL" "${CHROMIUM_OPTS[@]}" diff --git a/kiosk-wrapper.sh b/kiosk-wrapper.sh new file mode 100644 index 0000000..54fdaf9 --- /dev/null +++ b/kiosk-wrapper.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# kiosk-wrapper: uruchamiany jako root +set -e + +XDG_RUNTIME_DIR=/run/kiosk +WAYLAND_DISPLAY=${WAYLAND_DISPLAY:-wayland-0} +DPMS_PIPE=/run/kiosk-dpms +DPMS_FILE=$(find /sys/class/drm -maxdepth 2 -name "dpms" 2>/dev/null \ + | xargs grep -l "^On" 2>/dev/null | head -n1) + +mkdir -p "$XDG_RUNTIME_DIR" +chown kiosk:kiosk "$XDG_RUNTIME_DIR" || true +chmod 0700 "$XDG_RUNTIME_DIR" || true + +# Usuń stary pipe jeśli istnieje +rm -f "$DPMS_PIPE" +mkfifo -m 0666 "$DPMS_PIPE" + +# Demon DPMS (root) — czyta polecenia on/off z pipe i zapisuje do sysfs +# Działa w tle przez cały czas życia serwisu +( while true; do + if read -r cmd < "$DPMS_PIPE"; then + case "$cmd" in + off) echo -n "Off" > "$DPMS_FILE" 2>/dev/null ;; + on) echo -n "On" > "$DPMS_FILE" 2>/dev/null ;; + esac + fi +done ) & +DPMS_DAEMON_PID=$! + +export XDG_RUNTIME_DIR +export WAYLAND_DISPLAY +export DPMS_PIPE + +# Uruchom cage; po jego zakończeniu zabij demona +trap "kill $DPMS_DAEMON_PID 2>/dev/null; rm -f $DPMS_PIPE" EXIT +exec /usr/bin/cage -s -- /home/kiosk/kiosk-manager.sh diff --git a/kiosk.service b/kiosk.service new file mode 100644 index 0000000..3d5cded --- /dev/null +++ b/kiosk.service @@ -0,0 +1,35 @@ +[Unit] +Description=Instrukcje Kiosk +After=network-online.target systemd-user-sessions.service +Wants=network-online.target + +[Service] +User=kiosk +Group=kiosk +PAMName=login +Type=simple + +StandardOutput=journal +StandardError=journal + +RuntimeDirectory=kiosk +RuntimeDirectoryMode=0700 +Environment=XDG_RUNTIME_DIR=/run/kiosk +Environment=WLR_LIBSEAT_BACKEND=logind +Environment=WLR_RENDERER=gles2 + +Environment=IDLE_TIME=120 + +Environment=XDG_SESSION_TYPE=wayland +Environment=XDG_SESSION_CLASS=user + +CapabilityBoundingSet=CAP_SYS_TTY_CONFIG +AmbientCapabilities=CAP_SYS_TTY_CONFIG + +ExecStart=/usr/bin/sway + +Restart=always +RestartSec=3 + +[Install] +WantedBy=multi-user.target diff --git a/sway-config b/sway-config new file mode 100644 index 0000000..569e9fb --- /dev/null +++ b/sway-config @@ -0,0 +1,20 @@ +# Minimalny config sway dla kiosku +# Plik docelowy: /home/kiosk/.config/sway/config + +# Czarne tło zamiast domyślnego +output * bg #000000 solid_color + +# Obrót monitora o 270 stopni (DP/HDMI) +output * transform 270 + +# NumLock zawsze włączony (startup i wybudzanie) +input * xkb_numlock enabled + +# Ukryj kursor po 3 sekundach bezczynności +#seat * hide_cursor 3000 + +# Wyłącz wygaszacz ekranu sway (zarządzamy sami przez swayidle) +exec swayidle before-sleep "wlopm --off '*'" + +# Uruchom skrypt kiosku (swayidle + Chromium) +exec /home/kiosk/kiosk-manager.sh diff --git a/waiting.html b/waiting.html new file mode 100644 index 0000000..afe3a03 --- /dev/null +++ b/waiting.html @@ -0,0 +1,90 @@ + + + + + + Oczekiwanie na sieć + + + +
+
+
Oczekiwanie na sieć
+
+ +