feat(station): Abschlussbild beim Herunterfahren und beim Neustart

E-Paper behaelt sein Bild dauerhaft, auch stromlos. Faehrt der Pi
herunter, wird der Anzeigedienst mit abgeraeumt und das zuletzt
gezeichnete Bild bleibt fuer immer stehen - bei der Abnahme stand dort
die Rueckfrage des Tastermenues, und der ausgeschaltete Pi sah aus, als
warte er noch auf eine Eingabe.

Zwei neue Units, ninlight-poweroff.service (WantedBy=poweroff.target)
und ninlight-reboot.service (WantedBy=reboot.target). Sie haengen am
System, nicht am Tasterdienst: so greifen sie bei jedem Herunterfahren -
Menue, "poweroff" per SSH, "reboot" - und nicht nur auf einem von drei
Wegen. Zwei Units statt einer Fallunterscheidung, weil systemd einem
ExecStart nicht sagt, wohin die Reise geht.

Die Texte unterscheiden sich: "AUSGESCHALTET / Strom kann getrennt
werden" gegen "NEUSTART / Strom NICHT trennen!" samt Hinweis auf die
rund zwei Minuten, die der Zero W bis zum Anzeigedienst braucht. An
diesem Pi hat ein Stromzug in genau dieser Wartezeit schon eine
SD-Karte gekostet.

Reihenfolge: die Units ordnen sich per After=ninlight-display.service
hinter dessen Stop ein, und "ninlight-station display final <kind>"
wartet zusaetzlich, bis systemctl is-active nicht mehr anschlaegt -
dasselbe Muster wie display_handover(), nur ohne Wiederanfahren. Gibt
der Dienst die Leitungen nicht frei, wird nicht gezeichnet (GPIO busy),
sondern gewarnt: ein Anzeigefehler haelt das Herunterfahren nie auf.

Nebenbei behoben: display_run() reichte nur "$1" an display.py weiter
und haette "--final poweroff" halbiert.
This commit is contained in:
Michael Sauer
2026-09-15 03:02:21 +02:00
parent 300edafc3e
commit 4e1a965cbb
12 changed files with 572 additions and 4 deletions
+53
View File
@@ -146,6 +146,13 @@ echo "STUB systemctl \$*" >>"$log"
# ein Szenario NUR ihn scheitern lassen kann, ohne die Anzeige mitzureissen - sonst
# liesse sich nicht zeigen, dass ein fehlgeschlagenes enable/start des Tasters fuer
# sich genommen keinen Abbruch ausloest.
# Gezielt EINE Unit scheitern lassen (Abschlussbild): FAKE_ENABLE_FAIL_SUBSTR nennt den
# Teilstring des Unit-Namens, dessen "enable" fehlschlaegt.
if [ -n "\${FAKE_ENABLE_FAIL_SUBSTR:-}" ] && [ "\$1" = "enable" ]; then
case "\$*" in
*"\$FAKE_ENABLE_FAIL_SUBSTR"*) exit 1 ;;
esac
fi
case "\$*" in
*ninlight-button*)
case "\$1" in
@@ -217,6 +224,8 @@ run_setup() {
NINLIGHT_STATION_UNIT="$state/etc/systemd/system/ninlight-station.service" \
NINLIGHT_DISPLAY_UNIT="$state/etc/systemd/system/ninlight-display.service" \
NINLIGHT_BUTTON_UNIT="$state/etc/systemd/system/ninlight-button.service" \
NINLIGHT_POWEROFF_UNIT="$state/etc/systemd/system/ninlight-poweroff.service" \
NINLIGHT_REBOOT_UNIT="$state/etc/systemd/system/ninlight-reboot.service" \
NINLIGHT_NM_DIR="$state/etc/NetworkManager/system-connections" \
NINLIGHT_BOOT_CONFIG_NEW="$state/boot/firmware/config.txt" \
NINLIGHT_BOOT_CONFIG_OLD="$state/boot/config.txt" \
@@ -1080,6 +1089,50 @@ for d in migrate-wlan migrate-nocreds; do
|| fail "images/$d wurde leer angelegt"
done
echo
echo "=== Szenario: der Abschlussbildschirm wird installiert UND aktiviert ==="
# Der Abschlussbildschirm gehoert ins System, nicht in den Tasterdienst: so greift er bei
# jedem Herunterfahren (Menue, "poweroff" per SSH, Neustart) und nicht nur auf einem von
# drei Wegen. Zwei Units, weil sich die Texte unterscheiden muessen.
STATE="$TMPROOT/sfin-state"; STUBBIN="$TMPROOT/binfin"; LOG="$TMPROOT/sfin.log"
setup_state "$STATE"
setup_stubbin "$STUBBIN" "$LOG"
: >"$LOG"
set +e
OUT=$(run_setup "$STATE" "$STUBBIN" 2>&1)
RC=$?
set -e
[ "$RC" -eq 0 ] && pass "Exit-Code 0" || fail "Exit-Code $RC, Ausgabe: $OUT"
for u in ninlight-poweroff ninlight-reboot; do
[ -f "$STATE/etc/systemd/system/$u.service" ] \
&& pass "$u.service installiert" || fail "$u.service fehlt"
grep -Fq "systemctl enable $u.service" "$LOG" \
&& pass "$u.service aktiviert" || fail "kein 'systemctl enable $u' im Log"
done
# "enable", aber KEIN "start": diese Units tun beim Systemstart nichts, sie gehoeren zur
# Abschalt-Transaktion. Ein "start" wuerde das Abschlussbild mitten im Betrieb zeichnen.
grep -Fq "systemctl restart ninlight-poweroff" "$LOG" \
&& fail "die Abschlussbild-Unit wird beim Einrichten gestartet - das Bild kaeme sofort" \
|| pass "sie wird nicht gestartet, nur aktiviert"
grep -Fq "systemctl start ninlight-poweroff" "$LOG" \
&& fail "die Abschlussbild-Unit wird beim Einrichten gestartet" \
|| pass "auch kein 'systemctl start'"
echo
echo "=== Szenario: ein fehlgeschlagenes enable des Abschlussbilds warnt nur ==="
# Eine Station, deren Panel nach dem Ausschalten das falsche Bild zeigt, ist aergerlich;
# eine, die sich gar nicht einrichten laesst, ist unbrauchbar.
STATE="$TMPROOT/sfin2-state"; STUBBIN="$TMPROOT/binfin2"; LOG="$TMPROOT/sfin2.log"
setup_state "$STATE"
setup_stubbin "$STUBBIN" "$LOG"
: >"$LOG"
set +e
OUT=$(FAKE_ENABLE_FAIL_SUBSTR=ninlight-poweroff run_setup "$STATE" "$STUBBIN" 2>&1)
RC=$?
set -e
[ "$RC" -eq 0 ] && pass "Exit-Code 0 trotz fehlgeschlagenem enable" || fail "Exit-Code $RC: $OUT"
echo "$OUT" | grep -qi "warnung" && pass "Warnung in der Ausgabe" || fail "keine Warnung: $OUT"
echo
if [ "$FAILED" -eq 0 ]; then
echo "Alle Tests bestanden."