feat(station): Tasterdienst per deploy.sh/setup_pi.sh ausliefern

This commit is contained in:
Michael Sauer
2026-09-14 22:34:56 +02:00
parent 82a3942554
commit 24b37ee58f
6 changed files with 286 additions and 12 deletions
+58 -6
View File
@@ -90,15 +90,20 @@ echo "== Server, CLI und Units installieren =="
"$SSH_BIN" "$HOST" bash -s <<'REMOTE'
set -e
STAGE_DIR=${NINLIGHT_STAGE_DIR:-/tmp}
rm -rf "$STAGE_DIR/ninlight-display"
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" "$HOST:$STAGE_DIR/"
"$HERE/ninlight-station.service" "$HERE/ninlight-display.service" "$HERE/ninlight-button.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
# Pi). "scp -r" statt rsync, weil setup_pi.sh - anders als deploy.sh - ausdruecklich nur
# ssh/scp voraussetzt; __pycache__ wird auf der Gegenseite weggeraeumt (unten).
"$SCP_BIN" -q -r "$HERE/display" "$HOST:$STAGE_DIR/ninlight-display"
# Das Tasterverzeichnis genauso: als Ganzes, mit demselben "vorher aufraeumen"-Schutz
# gegen ein "scp -r" auf ein bereits vorhandenes Ziel (siehe Kommentar oben zu
# ninlight-display).
"$SCP_BIN" -q -r "$HERE/button" "$HOST:$STAGE_DIR/ninlight-button"
# Pfade als Variablen mit Default (wie in deploy.sh): so kann ein Test die
# Installation gegen ein Sandbox-Verzeichnis statt gegen echte Systempfade laufen
# lassen.
@@ -109,6 +114,7 @@ ROOT_DIR=${NINLIGHT_STATION_ROOT:-/opt/ninlight-station}
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}
# 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
@@ -117,11 +123,12 @@ DISPLAY_UNIT_PATH=${NINLIGHT_DISPLAY_UNIT:-/etc/systemd/system/ninlight-display.
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-display" "$STAGE_DIR/ninlight-button.service" \
"$STAGE_DIR/ninlight-button"
}
trap cleanup_stage EXIT
rm -rf "$STAGE_DIR/ninlight-display/__pycache__"
rm -rf "$STAGE_DIR/ninlight-display/__pycache__" "$STAGE_DIR/ninlight-button/__pycache__"
# Harte Vorbedingung, und zwar VOR dem ersten "sudo install" (Task 6b F2, N1): ohne
# display.py in der Ablage hat das scp nicht geliefert, was es sollte - abgebrochen,
# falsch verschachtelt oder gar nicht gelaufen. Die Installationsschleife weiter unten
@@ -134,11 +141,19 @@ rm -rf "$STAGE_DIR/ninlight-display/__pycache__"
# den diese Pruefung gedacht ist, log das Skript den Bediener an. Jetzt stimmt der Satz.
if [ ! -f "$STAGE_DIR/ninlight-display/display.py" ]; then
echo "Fehler: $STAGE_DIR/ninlight-display/display.py fehlt - die Uebertragung des Anzeigeverzeichnisses ist fehlgeschlagen." >&2
echo " Nichts installiert: $ROOT_DIR, $BIN_PATH und beide Units sind unveraendert. Ablage aufgeraeumt, Lauf einfach wiederholen." >&2
echo " Nichts installiert: $ROOT_DIR, $BIN_PATH und alle drei Units sind unveraendert. Ablage aufgeraeumt, Lauf einfach wiederholen." >&2
exit 1
fi
# Dieselbe harte Vorbedingung wie bei display.py, aus demselben Grund: ohne button.py in
# der Ablage hat das scp nicht geliefert, was es sollte, und die Installationsschleife
# unten wuerde das stillschweigend als "nichts zu tun" verbuchen.
if [ ! -f "$STAGE_DIR/ninlight-button/button.py" ]; then
echo "Fehler: $STAGE_DIR/ninlight-button/button.py fehlt - die Uebertragung des Tasterverzeichnisses ist fehlgeschlagen." >&2
echo " Nichts installiert: $ROOT_DIR, $BIN_PATH und alle drei Units sind unveraendert. Ablage aufgeraeumt, Lauf einfach wiederholen." >&2
exit 1
fi
sudo install -d -m 0755 "$ROOT_DIR" "$ROOT_DIR/images" "$ROOT_DIR/display"
sudo install -d -m 0755 "$ROOT_DIR" "$ROOT_DIR/images" "$ROOT_DIR/display" "$ROOT_DIR/button"
sudo install -m 0755 "$STAGE_DIR/server.py" "$ROOT_DIR/server.py"
sudo install -m 0644 "$STAGE_DIR/products.py" "$ROOT_DIR/products.py"
sudo install -m 0755 "$STAGE_DIR/ninlight-station" "$BIN_PATH"
@@ -165,6 +180,25 @@ for f in "$ROOT_DIR"/display/*; do
fi
done
sudo install -m 0644 "$STAGE_DIR/ninlight-display.service" "$DISPLAY_UNIT_PATH"
# Taster: dieselbe Behandlung wie die Anzeige - button.py ist ausfuehrbar (die Unit ruft
# es zwar ueber /usr/bin/python3 auf, von Hand pruefen laesst es sich trotzdem), der Rest
# (aktuell nichts weiter) waere importierter Code.
for f in "$STAGE_DIR"/ninlight-button/*; do
[ -f "$f" ] || continue
case "$(basename "$f")" in
button.py) sudo install -m 0755 "$f" "$ROOT_DIR/button/$(basename "$f")" ;;
*) sudo install -m 0644 "$f" "$ROOT_DIR/button/$(basename "$f")" ;;
esac
done
# Dasselbe Argument wie bei display/: button/ ist reiner Code aus dem Repo.
for f in "$ROOT_DIR"/button/*; do
[ -e "$f" ] || continue
if [ ! -e "$STAGE_DIR/ninlight-button/$(basename "$f")" ]; then
sudo rm -rf "$f"
echo " veraltete Datei entfernt: button/$(basename "$f")"
fi
done
sudo install -m 0644 "$STAGE_DIR/ninlight-button.service" "$BUTTON_UNIT_PATH"
# Das Aufraeumen der Ablage macht der EXIT-Trap oben - auf beiden Wegen aus diesem Block.
sudo systemctl daemon-reload
echo " installiert"
@@ -335,6 +369,21 @@ sudo systemctl restart ninlight-display.service >/dev/null 2>&1 || \
echo " Anzeigedienst aktiviert"
REMOTE
echo "== Tasterdienst aktivieren =="
# Dieselbe weiche Behandlung wie die Anzeige, aus demselben Grund: der Taster ist
# nirgends Voraussetzung. Fehlt gpiozero, fehlt der Taster oder ist GPIO23 belegt,
# beendet sich button.py still mit 0 (siehe dessen Modul-Docstring) - ein
# fehlgeschlagenes enable/start darf setup_pi.sh trotzdem nicht abbrechen, denn eine
# Station ohne Taster muss vollstaendig benutzbar bleiben.
"$SSH_BIN" "$HOST" bash -s <<'REMOTE'
set -e
sudo systemctl enable ninlight-button.service >/dev/null 2>&1 || \
echo " Warnung: 'systemctl enable ninlight-button' fehlgeschlagen - der Taster startet nach einem Neustart des Pi nicht von allein mit" >&2
sudo systemctl restart ninlight-button.service >/dev/null 2>&1 || \
echo " Warnung: 'systemctl restart ninlight-button' fehlgeschlagen - journalctl -u ninlight-button" >&2
echo " Tasterdienst aktiviert"
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
@@ -486,4 +535,7 @@ Naechste Schritte:
tools/station/deploy.sh <pi-host> Images ausliefern
ssh <pi-host> ninlight-station on Station einschalten
ssh <pi-host> ninlight-station off wieder ausschalten (nicht vergessen)
Der Taster auf GPIO23 ist mit eingerichtet: kurzer Druck oeffnet das Menue am Geraet,
3 s gehalten brechen eine laufende Migration/Rettung ab.
EOF