From 28055e6bc76cf8e8c2f2f5fc3b16cb94a1d333e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Przemys=C5=82aw=20Kie=C5=82kowski?=
Date: Tue, 5 May 2026 15:54:08 +0200
Subject: [PATCH] first commit
---
README.md | 168 +++++++++++++++++++++++++++++++++++++++++++++++
kiosk-manager.sh | 37 +++++++++++
kiosk-wrapper.sh | 37 +++++++++++
kiosk.service | 35 ++++++++++
sway-config | 20 ++++++
waiting.html | 90 +++++++++++++++++++++++++
6 files changed, 387 insertions(+)
create mode 100644 README.md
create mode 100644 kiosk-manager.sh
create mode 100644 kiosk-wrapper.sh
create mode 100644 kiosk.service
create mode 100644 sway-config
create mode 100644 waiting.html
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ć
+
+
+