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
+27 -1
View File
@@ -94,6 +94,7 @@ rm -rf "$STAGE_DIR/ninlight-display" "$STAGE_DIR/ninlight-button"
REMOTE
"$SCP_BIN" -q "$HERE/server.py" "$HERE/products.py" "$HERE/ninlight-station" \
"$HERE/ninlight-station.service" "$HERE/ninlight-display.service" "$HERE/ninlight-button.service" \
"$HERE/ninlight-poweroff.service" "$HERE/ninlight-reboot.service" \
"$HOST:$STAGE_DIR/"
# Das Anzeigeverzeichnis als Ganzes: render.py, display.py, epdconfig.py, die beiden
# uebernommenen Panel-Treiber und HERKUNFT.md (der Herkunftsnachweis gehoert mit auf den
@@ -115,6 +116,8 @@ BIN_PATH=${NINLIGHT_STATION_BIN:-/usr/local/bin/ninlight-station}
UNIT_PATH=${NINLIGHT_STATION_UNIT:-/etc/systemd/system/ninlight-station.service}
DISPLAY_UNIT_PATH=${NINLIGHT_DISPLAY_UNIT:-/etc/systemd/system/ninlight-display.service}
BUTTON_UNIT_PATH=${NINLIGHT_BUTTON_UNIT:-/etc/systemd/system/ninlight-button.service}
POWEROFF_UNIT_PATH=${NINLIGHT_POWEROFF_UNIT:-/etc/systemd/system/ninlight-poweroff.service}
REBOOT_UNIT_PATH=${NINLIGHT_REBOOT_UNIT:-/etc/systemd/system/ninlight-reboot.service}
# Die Ablage wird in JEDEM Fall abgeraeumt, auch wenn dieser Block vorzeitig aussteigt
# (Task 6b F2, N1). Vorher stand das "rm -rf" nur am Blockende und wurde beim Abbruch
@@ -124,7 +127,8 @@ cleanup_stage() {
rm -rf "$STAGE_DIR/server.py" "$STAGE_DIR/products.py" "$STAGE_DIR/ninlight-station" \
"$STAGE_DIR/ninlight-station.service" "$STAGE_DIR/ninlight-display.service" \
"$STAGE_DIR/ninlight-display" "$STAGE_DIR/ninlight-button.service" \
"$STAGE_DIR/ninlight-button"
"$STAGE_DIR/ninlight-button" "$STAGE_DIR/ninlight-poweroff.service" \
"$STAGE_DIR/ninlight-reboot.service"
}
trap cleanup_stage EXIT
@@ -215,6 +219,9 @@ for f in "$ROOT_DIR"/button/*; do
fi
done
sudo install -m 0644 "$STAGE_DIR/ninlight-button.service" "$BUTTON_UNIT_PATH"
# Abschlussbild beim Herunterfahren und beim Neustart (zwei Units, zwei Texte).
sudo install -m 0644 "$STAGE_DIR/ninlight-poweroff.service" "$POWEROFF_UNIT_PATH"
sudo install -m 0644 "$STAGE_DIR/ninlight-reboot.service" "$REBOOT_UNIT_PATH"
# Das Aufraeumen der Ablage macht der EXIT-Trap oben - auf beiden Wegen aus diesem Block.
sudo systemctl daemon-reload
echo " installiert"
@@ -400,6 +407,25 @@ sudo systemctl restart ninlight-button.service >/dev/null 2>&1 || \
echo " Tasterdienst aktiviert"
REMOTE
echo "== Abschlussbild aktivieren =="
# Zwei Units, zwei Texte: beim Herunterfahren "Strom kann getrennt werden", beim Neustart
# "Strom NICHT trennen!". Ohne sie bliebe auf dem E-Paper fuer immer das letzte Bild
# stehen - bei der Abnahme war das die Rueckfrage des Tastermenues.
#
# Dieselbe weiche Behandlung wie Anzeige und Taster: ein fehlgeschlagenes "enable" ist
# eine Warnung, kein Abbruch. Eine Station, deren Panel nach dem Ausschalten das falsche
# Bild zeigt, ist aergerlich; eine Station, die sich gar nicht einrichten laesst, ist
# unbrauchbar. "enable" allein, kein "start": diese Units tun beim Systemstart NICHTS,
# sie gehoeren zur Abschalt-Transaktion.
"$SSH_BIN" "$HOST" bash -s <<'REMOTE'
set -e
for unit in ninlight-poweroff.service ninlight-reboot.service; do
sudo systemctl enable "$unit" >/dev/null 2>&1 || \
echo " Warnung: 'systemctl enable $unit' fehlgeschlagen - das E-Paper behaelt nach dem Herunterfahren sein letztes Bild" >&2
done
echo " Abschlussbild aktiviert (Herunterfahren und Neustart)"
REMOTE
echo "== NetworkManager-Profile =="
# Zwei Dinge, die man an einer echten Lampenstation nicht falsch machen darf:
# - /etc/ninlight-station.conf ist 0600 root:root (das Passwort soll nicht