feat(station): Umschalter fuer Migrationsimages mit/ohne WLAN-Daten
Die WLAN-Zugangsdaten stecken zur Bauzeit in der Firmware, es gibt also zwei Abzuege je Ziel. Die Station haelt jetzt beide vor - images/ migrate-nocreds (aus tools/build_nocreds.sh, Lampe startet im Onboarding-AP) und images/migrate-wlan (aus build/, Lampe haengt sofort im eigenen WLAN) - und der Bediener waehlt per Umschalter, welcher ausgeliefert wird: "ninlight-station bildsatz" oder der Menueeintrag am Taster. Der Zustand liegt in /var/lib/ninlight-station/imageset, ueberlebt Neustarts und steht dauerhaft in der Fusszeile des Panels - in jedem Modus, auch bei ausgeschalteter Station: man soll vor dem Einschalten sehen, was gilt. Vorgabe und Rueckfallwert in JEDEM Zweifelsfall ist "ohne-wlan". Im Automatikmodus wird jede Klyqa-Lampe in Reichweite migriert, auch fremde; ein Abzug ohne Zugangsdaten ist dann ein harmloser Fehlgriff, einer mit Zugangsdaten traegt das eigene WLAN-Passwort in ein fremdes Geraet. Fehlt der gewaehlte Satz (Verzeichnis weg oder leer), wird NICHTS ausgeliefert - kein stilles Ausweichen auf den anderen Satz. Der Server antwortet 404 mit Status "noimageset", CLI und Panel sagen "FEHLT". server.py und die Stations-Unit muessen mit: die Auswahl der ausgelieferten Datei ist genau die Aufgabe des Servers, und ein Symlink-Tausch haette "gewaehlt, aber nicht vorhanden" von "dieses Modell fehlt" nicht mehr unterscheidbar gemacht.
This commit is contained in:
@@ -22,6 +22,31 @@ CONF=${NINLIGHT_STATION_CONF:-/etc/ninlight-station.conf}
|
||||
RUN_DIR=${NINLIGHT_RUN_DIR:-/run/ninlight-station}
|
||||
STATION_LIB=${NINLIGHT_STATION_LIB:-/opt/ninlight-station}
|
||||
|
||||
# --- Umschalter: Migrationsimages mit oder ohne WLAN-Zugangsdaten --------------------
|
||||
#
|
||||
# Die WLAN-Zugangsdaten stecken zur BAUZEIT in der Firmware. Es liegen deshalb zwei
|
||||
# Saetze Migrationsimages auf dem Pi:
|
||||
#
|
||||
# ohne-wlan -> $IMAGE_DIR/migrate-nocreds (tools/build_nocreds.sh): die migrierte
|
||||
# Lampe startet im eigenen Onboarding-Zugangspunkt und wartet auf ein WLAN
|
||||
# mit-wlan -> $IMAGE_DIR/migrate-wlan (build/): die Lampe haengt sofort im WLAN
|
||||
# des Bedieners
|
||||
#
|
||||
# Der Umschalter ist ein ZUSTAND, keine Abfrage je Migration: er bleibt, bis jemand ihn
|
||||
# aendert, und er steht dauerhaft auf dem Panel (display.py liest dieselbe Datei).
|
||||
# Deshalb liegt sie NICHT in $RUN_DIR (tmpfs, weg nach jedem Neustart) und nicht in
|
||||
# $CONF (0600 root:root, und setup_pi.sh traegt dort Schluessel nach) - sondern in einer
|
||||
# eigenen, dauerhaften Datei mit 0644, die auch der Anzeigedienst lesen kann.
|
||||
IMAGESET_FILE=${NINLIGHT_IMAGESET_FILE:-/var/lib/ninlight-station/imageset}
|
||||
# Die sichere Vorgabe, und zwar in JEDEM Zweifelsfall (Datei fehlt, unlesbar, unbekannter
|
||||
# Inhalt). Begruendung: im Automatikmodus wird jede alte Klyqa-Lampe in Funkreichweite
|
||||
# migriert, auch fremde. Mit dem Abzug OHNE Zugangsdaten ist ein Fehlgriff aergerlich,
|
||||
# aber harmlos - die Lampe steht im Onboarding-AP und wartet. Mit dem Abzug MIT
|
||||
# Zugangsdaten steht das eigene WLAN-Passwort unwiderruflich in einem fremden Geraet.
|
||||
# Der teurere Fehler darf nie der sein, der ohne Zutun passiert. server.py:read_image_set()
|
||||
# haelt dieselbe Vorgabe unabhaengig ein.
|
||||
IMAGESET_DEFAULT=ohne-wlan
|
||||
|
||||
# --- Zeitschalter ("Auto-Aus") -----------------------------------------------------
|
||||
#
|
||||
# Rein OPTIONAL: nur "--for <minuten>" legt einen an. Ohne die Angabe passiert hier
|
||||
@@ -109,8 +134,111 @@ images() {
|
||||
find "$IMAGE_DIR" -maxdepth 1 -name 'ninlight_*_ota.img' 2>/dev/null | sort
|
||||
}
|
||||
|
||||
# --- Bildsatz lesen, schreiben, benennen --------------------------------------------
|
||||
|
||||
# Der rohe Inhalt der Umschalterdatei (ohne Leerraum), oder leer. Nur fuer die Meldung
|
||||
# unten gedacht - entschieden wird ausschliesslich mit imageset_get().
|
||||
imageset_raw() {
|
||||
cat "$IMAGESET_FILE" 2>/dev/null | tr -d ' \t\r\n' || true
|
||||
}
|
||||
|
||||
# Der eingestellte Bildsatz, oder $IMAGESET_DEFAULT bei fehlender/unlesbarer Datei bzw.
|
||||
# unbekanntem Inhalt. Gibt IMMER einen gueltigen Namen aus und scheitert nie - ein
|
||||
# kaputter Umschalter darf weder "off" noch das Panel aufhalten.
|
||||
imageset_get() {
|
||||
_value=$(imageset_raw)
|
||||
case "$_value" in
|
||||
ohne-wlan|mit-wlan) printf '%s' "$_value" ;;
|
||||
*) printf '%s' "$IMAGESET_DEFAULT" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Das Verzeichnis zum Namen des Bildsatzes ($1).
|
||||
imageset_dir() {
|
||||
case "$1" in
|
||||
mit-wlan) printf '%s' "$IMAGE_DIR/migrate-wlan" ;;
|
||||
*) printf '%s' "$IMAGE_DIR/migrate-nocreds" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
imageset_label() {
|
||||
case "$1" in
|
||||
mit-wlan) printf 'mit-wlan (Lampe haengt sofort im eigenen WLAN)' ;;
|
||||
*) printf 'ohne-wlan (Lampe startet im Onboarding-Zugangspunkt)' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Schreibt den Umschalter atomar mit 0644 - dasselbe Muster wie write_mode()/
|
||||
# write_control(), aber in ein DAUERHAFTES Verzeichnis: der Zustand soll einen Neustart
|
||||
# ueberleben (das ist der Sinn eines Umschalters), und der Anzeigedienst muss ihn lesen
|
||||
# koennen.
|
||||
imageset_set() {
|
||||
sudo mkdir -p "$(dirname "$IMAGESET_FILE")"
|
||||
_tmp="$(dirname "$IMAGESET_FILE")/.imageset-$$"
|
||||
printf '%s\n' "$1" | sudo tee "$_tmp" >/dev/null && sudo chmod 0644 "$_tmp" || return 1
|
||||
sudo mv -f "$_tmp" "$IMAGESET_FILE"
|
||||
}
|
||||
|
||||
migrate_images() {
|
||||
find "$IMAGE_DIR/migrate" -maxdepth 1 -name '*.img' 2>/dev/null | sort
|
||||
find "$(imageset_dir "$(imageset_get)")" -maxdepth 1 -name '*.img' 2>/dev/null | sort
|
||||
}
|
||||
|
||||
# "bildsatz" ohne Argument: nur berichten. Mit Argument: umschalten.
|
||||
bildsatz_cmd() {
|
||||
_want=${1:-}
|
||||
_now=$(imageset_get)
|
||||
if [ -z "$_want" ]; then
|
||||
imageset_status_lines
|
||||
return 0
|
||||
fi
|
||||
case "$_want" in
|
||||
ohne-wlan|mit-wlan) ;;
|
||||
*)
|
||||
echo "Fehler: unbekannter Bildsatz '$_want' - erlaubt sind 'ohne-wlan' und 'mit-wlan'" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
imageset_set "$_want" || {
|
||||
echo "Fehler: $IMAGESET_FILE konnte nicht geschrieben werden" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "Bildsatz: $(imageset_label "$_want")"
|
||||
[ "$_now" = "$_want" ] && echo " (war schon eingestellt)"
|
||||
_dir=$(imageset_dir "$_want")
|
||||
if [ "$(find "$_dir" -maxdepth 1 -name '*.img' 2>/dev/null | wc -l | tr -d ' ')" -eq 0 ]; then
|
||||
# Kein stiller Rueckfall auf den anderen Satz - server.py liefert dann gar nichts
|
||||
# aus (Status "noimageset"), und das Panel sagt "FEHLT". Hier trotzdem sofort
|
||||
# warnen, damit niemand erst an der Lampe merkt, dass nichts kommt.
|
||||
echo "Warnung: $_dir fehlt oder ist leer - in diesem Bildsatz wird NICHTS ausgeliefert. tools/station/deploy.sh erneut laufen lassen." >&2
|
||||
fi
|
||||
if [ "$_want" = "mit-wlan" ]; then
|
||||
echo "Achtung: migrierte Lampen haengen damit sofort im WLAN aus config.local.cmake - auch fremde Lampen, die im Automatikmodus mitgenommen werden." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# Die zwei Zeilen, die "status" und "bildsatz" ohne Argument gemeinsam ausgeben.
|
||||
imageset_status_lines() {
|
||||
_set=$(imageset_get)
|
||||
_dir=$(imageset_dir "$_set")
|
||||
# "Vorhanden" heisst: mindestens ein Image darin - dieselbe Regel wie
|
||||
# server.py:migrate_set_present() und display.py:_read_imageset(). Ein leeres
|
||||
# Verzeichnis liefert genauso nichts aus wie ein fehlendes.
|
||||
_n=$(migrate_images | wc -l | tr -d ' ')
|
||||
if [ "$_n" -gt 0 ]; then
|
||||
_state="$_n Image(s)"
|
||||
else
|
||||
_state="FEHLT - es wird nichts ausgeliefert"
|
||||
fi
|
||||
printf 'Bildsatz: %s\n' "$(imageset_label "$_set")"
|
||||
printf ' %s (%s)\n' "$_dir" "$_state"
|
||||
# Steht in der Datei etwas, das kein Bildsatzname ist, gilt stillschweigend die
|
||||
# Vorgabe - das ist richtig so (sicher), aber der Bediener muss es erfahren: sonst
|
||||
# glaubt er, sein Eintrag von Hand haette gewirkt.
|
||||
_raw=$(imageset_raw)
|
||||
if [ -n "$_raw" ] && [ "$_raw" != "$_set" ]; then
|
||||
printf " (unbekannte Einstellung '%s' in %s - Vorgabe gilt)\n" \
|
||||
"$_raw" "$IMAGESET_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Faehrt erst jedes andere Stationsprofil herunter, dann (falls $1 nicht leer ist)
|
||||
@@ -518,8 +646,10 @@ migrate_on() {
|
||||
done
|
||||
[ "$_for_seen" -eq 1 ] || _for_minutes=""
|
||||
need_profile "$MIGRATE_AP_CONNECTION"
|
||||
_set=$(imageset_get)
|
||||
_setdir=$(imageset_dir "$_set")
|
||||
n=$(migrate_images | wc -l | tr -d ' ')
|
||||
[ "$n" -gt 0 ] || echo "Warnung: $IMAGE_DIR/migrate enthaelt keine Migrationsimages - die Station antwortet auf alles mit 404" >&2
|
||||
[ "$n" -gt 0 ] || echo "Warnung: $_setdir enthaelt keine Migrationsimages - die Station antwortet auf alles mit 404" >&2
|
||||
# Faehrt ninlight-recovery (falls es laeuft) herunter, BEVOR qconnex-firmware
|
||||
# hochkommt, und prueft danach nach, dass wirklich nur eines aktiv ist.
|
||||
ap_switch "$MIGRATE_AP_CONNECTION"
|
||||
@@ -530,6 +660,10 @@ migrate_on() {
|
||||
}
|
||||
start_and_verify "$MIGRATE_AP_CONNECTION" "migration" "$_phase"
|
||||
echo "Migration an: SSID $MIGRATE_SSID auf 192.168.8.1, Phase $_phase, $n Migrationsimage(s)"
|
||||
# Der Bildsatz gehoert in JEDE Einschaltmeldung: er entscheidet, ob die migrierte
|
||||
# Lampe das WLAN-Passwort des Bedieners mitbekommt, und er kann von vorletzter Woche
|
||||
# stehen.
|
||||
echo "Bildsatz: $(imageset_label "$_set")"
|
||||
echo "Achtung: das Passwort dieses Zugangspunkts ist aus der alten Firmware oeffentlich bekannt - siehe README.md." >&2
|
||||
echo "Nicht vergessen: 'ninlight-station off', wenn du fertig bist."
|
||||
autooff_arm_if_requested
|
||||
@@ -861,6 +995,7 @@ PY
|
||||
fi
|
||||
printf 'Modus : %s\n' "$_modus"
|
||||
printf 'Phase : %s\n' "$_phase"
|
||||
imageset_status_lines
|
||||
printf 'Erkannt: %s\n' "$_erkannt"
|
||||
printf 'Dienst : %s\n' "$(systemctl is-active ninlight-station 2>/dev/null || true)"
|
||||
autooff_status_line
|
||||
@@ -898,8 +1033,16 @@ display_cmd() {
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Aufruf: ninlight-station on [--for <minuten>]|recovery {on [--for <minuten>]|off}|migrate {on [--listen] [--for <minuten>]|off}|arm [<target>]|listen|renew [<minuten>]|hold|display {test|clear|off}|off|status" >&2
|
||||
echo "Aufruf: ninlight-station on [--for <minuten>]|recovery {on [--for <minuten>]|off}|migrate {on [--listen] [--for <minuten>]|off}|arm [<target>]|listen|bildsatz [ohne-wlan|mit-wlan]|renew [<minuten>]|hold|display {test|clear|off}|off|status" >&2
|
||||
echo "" >&2
|
||||
echo " bildsatz Umschalter: welcher Satz Migrationsimages ausgeliefert wird." >&2
|
||||
echo " Ohne Argument nur berichten. 'ohne-wlan' (Vorgabe) liefert die" >&2
|
||||
echo " Abzuege aus tools/build_nocreds.sh - die migrierte Lampe startet" >&2
|
||||
echo " im eigenen Onboarding-Zugangspunkt. 'mit-wlan' liefert die" >&2
|
||||
echo " Abzuege aus build/ - die Lampe haengt sofort im WLAN aus" >&2
|
||||
echo " config.local.cmake, auch wenn es eine fremde Lampe ist, die im" >&2
|
||||
echo " Automatikmodus mitgenommen wurde. Der Zustand bleibt, bis ihn" >&2
|
||||
echo " jemand aendert, und steht dauerhaft auf dem Panel." >&2
|
||||
echo " --for <minuten> Zeitschalter: die Station schaltet sich nach <minuten> selbst" >&2
|
||||
echo " wieder aus (zurueck ins Heim-WLAN). OPTIONAL - ohne '--for'" >&2
|
||||
echo " bleibt sie an, bis jemand 'off' sagt. Nuetzlich, wenn du ueber" >&2
|
||||
@@ -956,6 +1099,9 @@ case "$_cmd" in
|
||||
listen)
|
||||
listen_cmd
|
||||
;;
|
||||
bildsatz)
|
||||
bildsatz_cmd "${1:-}"
|
||||
;;
|
||||
renew)
|
||||
renew_cmd "${1:-}"
|
||||
;;
|
||||
|
||||
Reference in New Issue
Block a user