feat(station): Anzeige ausliefern, Migrationsprofil, display-Befehle
Schritt 8 des Plans: die fertige E-Paper-Anzeige wird endlich ausgeliefert und verdrahtet, dazu zwei liegengebliebene Dinge. - deploy.sh/setup_pi.sh uebertragen display/ (mit Panel-Treibern und HERKUNFT.md) und ninlight-display.service; setup_pi.sh installiert und aktiviert die Unit und zieht python3-pil nach - ohne Pillow beendet sich der Anzeigedienst still mit 0, das faellt sonst nirgends auf. - setup_pi.sh legt auch das Profil fuer den Migrations-Zugangspunkt an (qconnex-firmware, von der alten Klyqa-Firmware fest vorgegeben, gleiche Adresse wie das Rettungsprofil). Ohne das scheiterte "migrate on" auf einem frisch eingerichteten Pi an need_profile. Bestehende Profile bleiben unangetastet. - "ninlight-station display test|clear|off"; der Hilfetext erklaert die Revisionsbestimmung, denn EPD_REVISION laesst sich nur am Testbild bestimmen. - "off" nimmt die Anzeige mit: erst Dienst stoppen, dann Panel leeren (sonst schreibt der Daemon binnen 5 s sein altes Bild zurueck) und beides vor ap_switch, das bei haengendem NetworkManager abbricht. Ein stehengebliebenes "MIGRATION" wuerde einen Betriebszustand behaupten, den es nicht mehr gibt. - test_host.sh sammelt tools/mkimage als Ganzes ein: die 19 Tests in test_nl_mkimage.py liefen in keiner Suite mehr mit, darunter die Wache fuer die Python-3.8-Randbedingung des Build-Containers. Ein neuer Test haelt die Regel fest, dass keine Testdatei mehr herausfallen kann. - Nebenbei: die Temp-Datei mit dem WLAN-Passwort wird wieder zuverlaessig aufgeraeumt, und leere Konfigurationswerte legen kein kaputtes Profil an.
This commit is contained in:
@@ -55,12 +55,41 @@ echo "STUB scp \$*" >>"$log"
|
||||
args=()
|
||||
for a in "\$@"; do
|
||||
case "\$a" in
|
||||
# "-r" muss durchgereicht werden (als cp -R): setup_pi.sh uebertraegt das
|
||||
# Anzeigeverzeichnis als Ganzes, und ein Stub, der das Flag verschluckt, laesst
|
||||
# "cp" an einem Verzeichnis scheitern - der Test wuerde dann den Stub anzeigen,
|
||||
# nicht das Skript. Alle anderen Optionen (-q) bleiben weiterhin draussen.
|
||||
-r|-R) args+=("-R") ;;
|
||||
-*) continue ;;
|
||||
*:*) args+=("\${a#*:}") ;;
|
||||
*) args+=("\$a") ;;
|
||||
esac
|
||||
done
|
||||
exec cp "\${args[@]}"
|
||||
EOF
|
||||
|
||||
# apt-get gibt es auf dem Entwicklungsrechner nicht - und selbst auf einem Debian
|
||||
# duerfte ein Test es nie wirklich aufrufen. Der Stub protokolliert nur.
|
||||
cat >"$bindir/apt-get" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
echo "STUB apt-get \$*" >>"$log"
|
||||
exit "\${FAKE_APT_EXIT:-0}"
|
||||
EOF
|
||||
|
||||
# Steht fuer das python3 DES PI, nicht fuer das des Testrechners: nur die
|
||||
# Pillow-Probe wird beantwortet (steuerbar per FAKE_PIL_MISSING - auf diesem Rechner
|
||||
# ist Pillow sonst je nach Installation zufaellig vorhanden oder nicht, und der
|
||||
# Paketschritt waere damit gar nicht pruefbar). Jeder andere Aufruf laeuft durch das
|
||||
# echte python3.
|
||||
cat >"$bindir/python3" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
echo "STUB python3 \$*" >>"$log"
|
||||
for a in "\$@"; do
|
||||
case "\$a" in
|
||||
*"import PIL"*) exit "\${FAKE_PIL_MISSING:-0}" ;;
|
||||
esac
|
||||
done
|
||||
exec "$(command -v python3)" "\$@"
|
||||
EOF
|
||||
|
||||
# "sudo install -o root -g root ..." (im NetworkManager-Keyfile-Schritt) braucht
|
||||
@@ -104,7 +133,8 @@ fi
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
chmod +x "$bindir"/ssh "$bindir"/scp "$bindir"/sudo "$bindir"/systemctl "$bindir"/nmcli
|
||||
chmod +x "$bindir"/ssh "$bindir"/scp "$bindir"/sudo "$bindir"/systemctl "$bindir"/nmcli \
|
||||
"$bindir"/apt-get "$bindir"/python3
|
||||
}
|
||||
|
||||
# $1 = Sandbox-Wurzel fuer die "Systempfade"
|
||||
@@ -133,6 +163,7 @@ run_setup() {
|
||||
NINLIGHT_STATION_ROOT="$state/opt/ninlight-station" \
|
||||
NINLIGHT_STATION_BIN="$state/usr/local/bin/ninlight-station" \
|
||||
NINLIGHT_STATION_UNIT="$state/etc/systemd/system/ninlight-station.service" \
|
||||
NINLIGHT_DISPLAY_UNIT="$state/etc/systemd/system/ninlight-display.service" \
|
||||
NINLIGHT_NM_DIR="$state/etc/NetworkManager/system-connections" \
|
||||
"$STATION_DIR/setup_pi.sh" pi-test
|
||||
}
|
||||
@@ -247,6 +278,158 @@ for KEY in MIGRATE_AP_CONNECTION MIGRATE_SSID MIGRATE_PSK EPD_REVISION; do
|
||||
grep -Eq "^${KEY}=" "$CONF_OUT4" && pass "fehlender Schluessel $KEY wurde trotzdem ergaenzt" || fail "Schluessel $KEY fehlt weiterhin"
|
||||
done
|
||||
|
||||
echo
|
||||
echo "=== Szenario 5 (Task 6b, Punkt 1): Anzeige wird ausgeliefert, installiert und aktiviert ==="
|
||||
STATE="$TMPROOT/s5-state"; STUBBIN="$TMPROOT/bin5"; LOG="$TMPROOT/s5.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"
|
||||
DISP="$STATE/opt/ninlight-station/display"
|
||||
# Die Panel-Treiber und der Herkunftsnachweis gehoeren mit auf den Pi, nicht nur ins
|
||||
# Repo: HERKUNFT.md ist der Nachweis, woher der uebernommene Waveshare-Code stammt.
|
||||
for F in display.py render.py epdconfig.py epd2in13_V2.py epd2in13_V3.py HERKUNFT.md; do
|
||||
[ -f "$DISP/$F" ] && pass "display/$F ausgeliefert" || fail "display/$F fehlt unter $DISP"
|
||||
done
|
||||
[ -x "$DISP/display.py" ] && pass "display.py ist ausfuehrbar (Handbetrieb 'display test')" || fail "display.py ist nicht ausfuehrbar"
|
||||
MODE=$(file_mode "$DISP/render.py")
|
||||
[ "$MODE" = "644" ] && pass "importierter Code ist 0644" || fail "render.py hat Rechte $MODE statt 644"
|
||||
[ ! -d "$DISP/__pycache__" ] && pass "kein __pycache__ auf dem Pi gelandet" || fail "__pycache__ wurde mitkopiert"
|
||||
[ -f "$STATE/etc/systemd/system/ninlight-display.service" ] && pass "ninlight-display.service installiert" || fail "Anzeige-Unit fehlt - die Unit waere weiter toter Text im Repo"
|
||||
# Ohne "enable" startet die Anzeige nach einem Stromausfall nicht wieder mit.
|
||||
grep -Fq "systemctl enable ninlight-display.service" "$LOG" && pass "Anzeigedienst wurde aktiviert" || fail "kein 'systemctl enable ninlight-display' im Log"
|
||||
grep -Fq "systemctl restart ninlight-display.service" "$LOG" && pass "Anzeigedienst wurde gestartet" || fail "kein 'systemctl restart ninlight-display' im Log"
|
||||
# Die Station selbst bleibt nach dem Einrichten absichtlich AUS - nur die Anzeige
|
||||
# laeuft. Ein versehentliches "enable ninlight-station" waere ein Sicherheitsfehler:
|
||||
# der Zugangspunkt kaeme nach jedem Boot von allein hoch.
|
||||
grep -Fq "systemctl enable ninlight-station" "$LOG" && fail "setup_pi.sh aktiviert den Stationsdienst - der Zugangspunkt kaeme nach jedem Boot von allein hoch" || pass "Stationsdienst bleibt deaktiviert (Station ist nach dem Einrichten aus)"
|
||||
|
||||
echo
|
||||
echo "=== Szenario 6 (Task 6b, Punkt 1): python3-pil wird nachgezogen, wenn Pillow fehlt ==="
|
||||
# Ohne Pillow beendet sich der Anzeigedienst still mit 0 (Absicht) - das faellt
|
||||
# nirgends auf, also muss das Paket hier kommen.
|
||||
STATE="$TMPROOT/s6-state"; STUBBIN="$TMPROOT/bin6"; LOG="$TMPROOT/s6.log"
|
||||
setup_state "$STATE"
|
||||
setup_stubbin "$STUBBIN" "$LOG"
|
||||
: >"$LOG"
|
||||
set +e
|
||||
OUT=$(FAKE_PIL_MISSING=1 run_setup "$STATE" "$STUBBIN" 2>&1)
|
||||
RC=$?
|
||||
set -e
|
||||
[ "$RC" -eq 0 ] && pass "Exit-Code 0" || fail "Exit-Code $RC, Ausgabe: $OUT"
|
||||
grep -Fq "apt-get install -y python3-pil" "$LOG" && pass "python3-pil wird per apt nachinstalliert" || fail "kein 'apt-get install -y python3-pil' im Log"
|
||||
|
||||
echo
|
||||
echo "=== Szenario 7: ist Pillow schon da, wird apt gar nicht erst bemueht ==="
|
||||
STATE="$TMPROOT/s7-state"; STUBBIN="$TMPROOT/bin7"; LOG="$TMPROOT/s7.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"
|
||||
grep -Fq "apt-get" "$LOG" && fail "apt-get wurde trotz vorhandenem Pillow aufgerufen" || pass "kein apt-Aufruf, wenn Pillow schon vorhanden ist"
|
||||
|
||||
echo
|
||||
echo "=== Szenario 8 (Task 6b, Punkt 2): das Profil fuer den Migrations-Zugangspunkt wird angelegt ==="
|
||||
# Ohne dieses zweite Profil scheitert "ninlight-station migrate on" auf einem frisch
|
||||
# eingerichteten Pi an need_profile "$MIGRATE_AP_CONNECTION".
|
||||
#
|
||||
# Geprueft wird der Zustand aus Szenario 7 (ein vollstaendiger Lauf auf einem frischen
|
||||
# Pi, $STATE/$LOG zeigen noch dorthin) - deshalb hier kein eigener Lauf.
|
||||
NMDIR="$STATE/etc/NetworkManager/system-connections"
|
||||
MIGRATE_FILE="$NMDIR/qconnex-firmware.nmconnection"
|
||||
[ -f "$MIGRATE_FILE" ] && pass "qconnex-firmware.nmconnection angelegt" || fail "Migrationsprofil fehlt in $NMDIR: $(ls "$NMDIR")"
|
||||
[ -f "$NMDIR/ninlight-recovery.nmconnection" ] && pass "Rettungsprofil weiterhin angelegt" || fail "Rettungsprofil fehlt"
|
||||
# SSID und PSK sind von der alten Klyqa-Firmware fest vorgegeben - weicht eines ab,
|
||||
# findet keine alte Lampe die Migrationsstation.
|
||||
grep -Fqx "ssid=qconnex-firmware" "$MIGRATE_FILE" && pass "SSID ist die von der Klyqa-Firmware vorgegebene" || fail "falsche SSID: $(grep '^ssid=' "$MIGRATE_FILE")"
|
||||
grep -Fqx "psk=qconnex-firmware" "$MIGRATE_FILE" && pass "PSK ist der von der Klyqa-Firmware vorgegebene" || fail "falscher PSK"
|
||||
grep -Fqx "mode=ap" "$MIGRATE_FILE" && pass "Profil ist ein Zugangspunkt" || fail "mode=ap fehlt"
|
||||
grep -Fqx "method=shared" "$MIGRATE_FILE" && pass "ipv4.method ist 'shared'" || fail "method=shared fehlt"
|
||||
# Dieselbe Adresse wie das Rettungsprofil - genau deshalb schliessen sich beide aus,
|
||||
# und genau darauf verlaesst sich ap_switch() in ninlight-station.
|
||||
grep -Fqx "address1=192.168.8.1/24" "$MIGRATE_FILE" && pass "Adresse 192.168.8.1/24 (wie das Rettungsprofil)" || fail "falsche Adresse: $(grep '^address1=' "$MIGRATE_FILE")"
|
||||
grep -Fqx "autoconnect=false" "$MIGRATE_FILE" && pass "kein Selbststart beim Booten" || fail "autoconnect ist nicht false - der Migrations-AP kaeme nach jedem Boot von allein hoch"
|
||||
MODE=$(file_mode "$MIGRATE_FILE")
|
||||
[ "$MODE" = "600" ] && pass "Keyfile ist 0600 (das Passwort steht darin)" || fail "Keyfile hat Rechte $MODE statt 600"
|
||||
# Das Passwort darf nie als Kommandozeilenargument an nmcli gehen (in "ps" sichtbar).
|
||||
grep -Fq "nmcli connection load" "$LOG" && pass "Profil wird per 'connection load' eingelesen" || fail "kein 'nmcli connection load' im Log"
|
||||
grep -Eq "STUB nmcli .*(psk|wifi-sec)" "$LOG" && fail "das Passwort wurde als nmcli-Argument uebergeben - in 'ps' fuer jeden lokalen Benutzer sichtbar" || pass "kein Passwort in einer nmcli-Kommandozeile"
|
||||
|
||||
echo
|
||||
echo "=== Szenario 9 (Task 6b, Punkt 2): ein bestehendes Migrationsprofil bleibt unangetastet ==="
|
||||
STATE="$TMPROOT/s9-state"; STUBBIN="$TMPROOT/bin9"; LOG="$TMPROOT/s9.log"
|
||||
setup_state "$STATE"
|
||||
setup_stubbin "$STUBBIN" "$LOG"
|
||||
NMDIR9="$STATE/etc/NetworkManager/system-connections"
|
||||
# Von Hand angelegt, mit handjustierten Feldern (anderer Kanal), die dieses Skript
|
||||
# gar nicht kennt.
|
||||
cat >"$NMDIR9/qconnex-firmware.nmconnection" <<'NM'
|
||||
[connection]
|
||||
id=qconnex-firmware
|
||||
uuid=11111111-2222-3333-4444-555555555555
|
||||
type=wifi
|
||||
[wifi]
|
||||
mode=ap
|
||||
ssid=qconnex-firmware
|
||||
channel=11
|
||||
NM
|
||||
chmod 0600 "$NMDIR9/qconnex-firmware.nmconnection"
|
||||
BEFORE=$(cat "$NMDIR9/qconnex-firmware.nmconnection")
|
||||
: >"$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"
|
||||
if [ "$BEFORE" = "$(cat "$NMDIR9/qconnex-firmware.nmconnection")" ]; then
|
||||
pass "bestehendes Migrationsprofil wurde Byte fuer Byte unveraendert gelassen"
|
||||
else
|
||||
fail "bestehendes Migrationsprofil wurde ueberschrieben: $(cat "$NMDIR9/qconnex-firmware.nmconnection")"
|
||||
fi
|
||||
echo "$OUT" | grep -q "unveraendert gelassen" && pass "Ausgabe sagt, dass das Profil unveraendert blieb" || fail "Ausgabe erwaehnt das nicht: $OUT"
|
||||
# Das Rettungsprofil dagegen wird bewusst neu geschrieben (SSID/PSK koennen sich
|
||||
# geaendert haben) - aber unter Beibehaltung der UUID.
|
||||
[ -f "$NMDIR9/ninlight-recovery.nmconnection" ] && pass "Rettungsprofil trotzdem angelegt" || fail "Rettungsprofil fehlt"
|
||||
|
||||
echo
|
||||
echo "=== Szenario 10: ein leerer Konfigurationswert legt kein kaputtes Profil an ==="
|
||||
STATE="$TMPROOT/s10-state"; STUBBIN="$TMPROOT/bin10"; LOG="$TMPROOT/s10.log"
|
||||
setup_state "$STATE"
|
||||
setup_stubbin "$STUBBIN" "$LOG"
|
||||
cat >"$STATE/etc/ninlight-station.conf" <<'CONF'
|
||||
SSID='eigene-ssid'
|
||||
PSK='eigenes-passwort'
|
||||
IMAGE_DIR='/opt/ninlight-station/images'
|
||||
HOME_CONNECTION='preconfigured'
|
||||
AP_CONNECTION='ninlight-recovery'
|
||||
MIGRATE_SSID='qconnex-firmware'
|
||||
MIGRATE_PSK=''
|
||||
MIGRATE_AP_CONNECTION='qconnex-firmware'
|
||||
EPD_REVISION='V3'
|
||||
CONF
|
||||
chmod 0600 "$STATE/etc/ninlight-station.conf"
|
||||
: >"$LOG"
|
||||
set +e
|
||||
OUT=$(run_setup "$STATE" "$STUBBIN" 2>&1)
|
||||
RC=$?
|
||||
set -e
|
||||
[ "$RC" -ne 0 ] && pass "Exit-Code != 0 bei leerem PSK" || fail "Exit-Code 0 trotz leerem Migrations-PSK: $OUT"
|
||||
echo "$OUT" | grep -qi "leer" && pass "Fehlermeldung nennt den leeren Wert" || fail "Fehlermeldung fehlt: $OUT"
|
||||
NMDIR10="$STATE/etc/NetworkManager/system-connections"
|
||||
if [ -f "$NMDIR10/qconnex-firmware.nmconnection" ]; then
|
||||
fail "trotz leerem PSK wurde ein Migrationsprofil geschrieben"
|
||||
else
|
||||
pass "kein Migrationsprofil mit leerem PSK angelegt"
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ "$FAILED" -eq 0 ]; then
|
||||
echo "Alle Tests bestanden."
|
||||
|
||||
Reference in New Issue
Block a user