feat(station): Panel und CLI auf Englisch, IP-Zeile im Off-Bild
Die deutschen Texte sahen auf dem 2,13"-Panel merkwuerdig aus - jetzt sind alle Texte, die der Bediener am Geraet oder auf der Konsole sieht, englisch: Modus-, Phasen-, Bildsatz- und Abschlussbeschriftungen in render.py, die Bedientexte des Tasterdienstes und saemtliche Ausgaben von ninlight-station inklusive des Hilfetexts. Die Testbeschreibungen der Suiten bleiben deutsch - die liest nur, wer die Tests laufen laesst. Neu im Off-Bild: die Adresse, unter der der Pi gerade erreichbar ist. Ist die Station aus, ist der Pi ein gewoehnlicher Rechner im Heimnetz, und die einzige Auskunft, die man dann am Panel braucht, ist die fuer SSH. Die Adresse kommt aus einem UDP-Socket, der nur verbunden und nie benutzt wird (kein Datenverkehr, kein DNS, kein Unterprozess in einer 5-s-Schleife) und liefert genau die Adresse der Standardroute. Ohne Netz sagt die Zeile ausdruecklich "no network": eine fehlende Zeile wuerde offen lassen, warum SSH gerade scheitert. Die Zeile gibt es NUR im Off-Bild - im Betrieb traegt wlan0 die Adresse des Zugangspunkts, die ohnehin auf jedem Statusbild steht.
This commit is contained in:
+110
-110
@@ -107,14 +107,14 @@ elif [ -e "$CONF" ]; then
|
||||
# Rechte aufzuweichen.
|
||||
eval "$(sudo cat "$CONF")"
|
||||
else
|
||||
echo "Fehler: $CONF fehlt - zuerst tools/station/setup_pi.sh ausfuehren" >&2
|
||||
echo "Error: $CONF missing - run tools/station/setup_pi.sh first" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for _key in SSID PSK IMAGE_DIR HOME_CONNECTION AP_CONNECTION \
|
||||
MIGRATE_AP_CONNECTION MIGRATE_SSID MIGRATE_PSK EPD_REVISION; do
|
||||
eval "test -n \"\${$_key-}\"" || {
|
||||
echo "Fehler: $CONF: Schluessel $_key fehlt oder ist leer - tools/station/setup_pi.sh ausfuehren" >&2
|
||||
echo "Error: $CONF: key $_key missing or empty - run tools/station/setup_pi.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
@@ -125,7 +125,7 @@ need_profile() {
|
||||
# -F: der Profilname ist ein Konfigurationswert, kein BRE-Muster - ein Name mit
|
||||
# "." oder "[" wuerde mit "grep -x" sonst falsch (oder gar nicht) treffen.
|
||||
nmcli -t --escape no -f NAME con show | grep -Fqx "$1" || {
|
||||
echo "Fehler: NetworkManager-Profil '$1' fehlt - tools/station/setup_pi.sh ausfuehren" >&2
|
||||
echo "Error: NetworkManager profile '$1' missing - run tools/station/setup_pi.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -163,8 +163,8 @@ imageset_dir() {
|
||||
|
||||
imageset_label() {
|
||||
case "$1" in
|
||||
mit-wlan) printf 'mit-wlan (Lampe haengt sofort im eigenen WLAN)' ;;
|
||||
*) printf 'ohne-wlan (Lampe startet im Onboarding-Zugangspunkt)' ;;
|
||||
mit-wlan) printf 'mit-wlan (lamp joins your Wi-Fi right away)' ;;
|
||||
*) printf 'ohne-wlan (lamp starts its onboarding access point)' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -194,25 +194,25 @@ bildsatz_cmd() {
|
||||
case "$_want" in
|
||||
ohne-wlan|mit-wlan) ;;
|
||||
*)
|
||||
echo "Fehler: unbekannter Bildsatz '$_want' - erlaubt sind 'ohne-wlan' und 'mit-wlan'" >&2
|
||||
echo "Error: unknown image set '$_want' - allowed are 'ohne-wlan' and 'mit-wlan'" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
imageset_set "$_want" || {
|
||||
echo "Fehler: $IMAGESET_FILE konnte nicht geschrieben werden" >&2
|
||||
echo "Error: could not write $IMAGESET_FILE" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "Bildsatz: $(imageset_label "$_want")"
|
||||
[ "$_now" = "$_want" ] && echo " (war schon eingestellt)"
|
||||
echo "Image set: $(imageset_label "$_want")"
|
||||
[ "$_now" = "$_want" ] && echo " (was already set)"
|
||||
_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
|
||||
# aus (Status "noimageset"), und das Panel sagt "MISSING". 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
|
||||
echo "Warning: $_dir missing or empty - this image set serves NOTHING. Run tools/station/deploy.sh again." >&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
|
||||
echo "Caution: migrated lamps join the Wi-Fi from config.local.cmake right away - including lamps that are not yours and got picked up in automatic mode." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -225,18 +225,18 @@ imageset_status_lines() {
|
||||
# Verzeichnis liefert genauso nichts aus wie ein fehlendes.
|
||||
_n=$(migrate_images | wc -l | tr -d ' ')
|
||||
if [ "$_n" -gt 0 ]; then
|
||||
_state="$_n Image(s)"
|
||||
_state="$_n image(s)"
|
||||
else
|
||||
_state="FEHLT - es wird nichts ausgeliefert"
|
||||
_state="MISSING - nothing will be served"
|
||||
fi
|
||||
printf 'Bildsatz: %s\n' "$(imageset_label "$_set")"
|
||||
printf 'Image set: %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" \
|
||||
printf " (unknown setting '%s' in %s - default applies)\n" \
|
||||
"$_raw" "$IMAGESET_FILE"
|
||||
fi
|
||||
}
|
||||
@@ -276,7 +276,7 @@ ap_switch() {
|
||||
# gehoert zum Wert).
|
||||
_active=$(nmcli -t --escape no -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2-)
|
||||
if [ "$_active" = "$AP_CONNECTION" ] || [ "$_active" = "$MIGRATE_AP_CONNECTION" ]; then
|
||||
echo "Fehler: wlan0 zeigt nach dem Ausschalten immer noch '$_active' aktiv - NetworkManager pruefen (Zugangspunkt bleibt an)" >&2
|
||||
echo "Error: after switching off, wlan0 still shows '$_active' active - check NetworkManager (access point stays up)" >&2
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
@@ -287,7 +287,7 @@ ap_switch() {
|
||||
if [ "$_active" != "$_target" ]; then
|
||||
sudo nmcli con down "$AP_CONNECTION" >/dev/null 2>&1 || true
|
||||
sudo nmcli con down "$MIGRATE_AP_CONNECTION" >/dev/null 2>&1 || true
|
||||
echo "Fehler: wlan0 zeigt nach dem Umschalten auf '$_target' unerwartet '$_active' - beide Stationsprofile wieder heruntergefahren" >&2
|
||||
echo "Error: after switching to '$_target', wlan0 unexpectedly shows '$_active' - both station profiles brought down again" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
@@ -326,16 +326,16 @@ write_control() {
|
||||
autooff_check_minutes() {
|
||||
case "${1:-}" in
|
||||
'' )
|
||||
echo "Fehler: '--for' braucht eine Angabe in Minuten ($AUTOOFF_MIN_MINUTES-$AUTOOFF_MAX_MINUTES)" >&2
|
||||
echo "Error: '--for' needs a value in minutes ($AUTOOFF_MIN_MINUTES-$AUTOOFF_MAX_MINUTES)" >&2
|
||||
return 1
|
||||
;;
|
||||
*[!0-9]* )
|
||||
echo "Fehler: '$1' ist keine Minutenangabe - erlaubt sind ganze Zahlen von $AUTOOFF_MIN_MINUTES bis $AUTOOFF_MAX_MINUTES" >&2
|
||||
echo "Error: '$1' is not a number of minutes - allowed are whole numbers from $AUTOOFF_MIN_MINUTES to $AUTOOFF_MAX_MINUTES" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
if [ "$1" -lt "$AUTOOFF_MIN_MINUTES" ] || [ "$1" -gt "$AUTOOFF_MAX_MINUTES" ]; then
|
||||
echo "Fehler: $1 Minuten liegen ausserhalb von $AUTOOFF_MIN_MINUTES-$AUTOOFF_MAX_MINUTES" >&2
|
||||
echo "Error: $1 minutes is outside $AUTOOFF_MIN_MINUTES-$AUTOOFF_MAX_MINUTES" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
@@ -424,11 +424,11 @@ autooff_arm() {
|
||||
set -- "$@" "--setenv=NINLIGHT_STATION_LIB=$NINLIGHT_STATION_LIB"
|
||||
fi
|
||||
if ! sudo systemd-run "$@" "$SELF" __autooff >/dev/null; then
|
||||
echo "Fehler: Zeitschalter liess sich nicht anlegen (systemd-run '$AUTOOFF_UNIT') - die Station bleibt AN, 'ninlight-station off' nicht vergessen." >&2
|
||||
echo "Error: could not create the timer (systemd-run '$AUTOOFF_UNIT') - the station stays ON, do not forget 'ninlight-station off'." >&2
|
||||
return 1
|
||||
fi
|
||||
autooff_write "$_req" "$(( $(date +%s) + _delay ))" "$_deferrals" || {
|
||||
echo "Fehler: $AUTOOFF_FILE konnte nicht geschrieben werden - Zeitschalter wieder abgeraeumt" >&2
|
||||
echo "Error: could not write $AUTOOFF_FILE - timer removed again" >&2
|
||||
autooff_clear
|
||||
return 1
|
||||
}
|
||||
@@ -455,7 +455,7 @@ autooff_busy() {
|
||||
# "ja, beschaeftigt", haette ein fehlendes ss den Zeitschalter bis zur
|
||||
# Obergrenze ausgehebelt - und der Zeitschalter ist angefordert worden, WEIL der
|
||||
# Nutzer sonst nicht mehr an den Pi kommt.
|
||||
echo "Warnung: 'ss' nicht gefunden - laufende Auslieferungen konnten nicht geprueft werden" >&2
|
||||
echo "Warning: 'ss' not found - could not check for downloads in progress" >&2
|
||||
return 1
|
||||
fi
|
||||
_conns=$("$_ss" -Htn state established "( sport = :80 )" dst "$AUTOOFF_STATION_NET" 2>/dev/null | grep -c . || true)
|
||||
@@ -485,10 +485,10 @@ autooff_fire() {
|
||||
if [ "$_deferrals" -lt "$AUTOOFF_MAX_DEFERRALS" ]; then
|
||||
_deferrals=$((_deferrals + 1))
|
||||
autooff_write "$_req" "$(( $(date +%s) + AUTOOFF_RETRY_S ))" "$_deferrals"
|
||||
echo "Zeitschalter verschoben ($_deferrals/$AUTOOFF_MAX_DEFERRALS): eine Auslieferung laeuft noch"
|
||||
echo "Timer deferred ($_deferrals/$AUTOOFF_MAX_DEFERRALS): a download is still running"
|
||||
exit 0
|
||||
fi
|
||||
echo "Warnung: $AUTOOFF_MAX_DEFERRALS Verschiebungen erreicht - es steht immer noch eine Verbindung offen, sie haengt vermutlich. Station wird jetzt trotzdem abgeschaltet." >&2
|
||||
echo "Warning: reached $AUTOOFF_MAX_DEFERRALS deferrals - a connection is still open and has probably stalled. Switching the station off anyway." >&2
|
||||
fi
|
||||
full_off
|
||||
}
|
||||
@@ -529,7 +529,7 @@ start_and_verify() {
|
||||
# Lebendigkeitspruefung unten je erreicht wird, und der eben
|
||||
# hochgefahrene Zugangspunkt bliebe offen ohne Server dahinter stehen.
|
||||
sudo nmcli con down "$_ap" >/dev/null 2>&1 || true
|
||||
echo "Fehler: ninlight-station liess sich nicht (neu) starten - Zugangspunkt wieder abgeschaltet. Details: journalctl -u ninlight-station" >&2
|
||||
echo "Error: could not (re)start ninlight-station - access point switched off again. Details: journalctl -u ninlight-station" >&2
|
||||
exit 1
|
||||
fi
|
||||
# "systemctl restart" meldet bei Type=simple schon Erfolg, sobald der Prozess
|
||||
@@ -542,14 +542,14 @@ start_and_verify() {
|
||||
# sonst suggeriert die Meldung unten einen saubereren Zustand als er ist.
|
||||
sudo systemctl stop ninlight-station 2>/dev/null || true
|
||||
sudo nmcli con down "$_ap" >/dev/null 2>&1 || true
|
||||
echo "Fehler: ninlight-station ist nach dem Start nicht aktiv - Zugangspunkt wieder abgeschaltet. Details: journalctl -u ninlight-station" >&2
|
||||
echo "Error: ninlight-station is not active after starting - access point switched off again. Details: journalctl -u ninlight-station" >&2
|
||||
exit 1
|
||||
fi
|
||||
_actual_mode=$(cat "$RUN_DIR/mode" 2>/dev/null || true)
|
||||
if [ "$_actual_mode" != "$_expect_mode" ]; then
|
||||
sudo systemctl stop ninlight-station 2>/dev/null || true
|
||||
sudo nmcli con down "$_ap" >/dev/null 2>&1 || true
|
||||
echo "Fehler: $RUN_DIR/mode enthaelt nach dem Neustart '$_actual_mode' statt '$_expect_mode' - RuntimeDirectory wurde vermutlich geleert (RuntimeDirectoryPreserve=restart in der Unit pruefen). Zugangspunkt wieder abgeschaltet." >&2
|
||||
echo "Error: after the restart $RUN_DIR/mode holds '$_actual_mode' instead of '$_expect_mode' - the RuntimeDirectory was probably wiped (check RuntimeDirectoryPreserve=restart in the unit). Access point switched off again." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$_expect_phase" ]; then
|
||||
@@ -568,7 +568,7 @@ PY
|
||||
if [ "$_actual_phase" != "$_expect_phase" ]; then
|
||||
sudo systemctl stop ninlight-station 2>/dev/null || true
|
||||
sudo nmcli con down "$_ap" >/dev/null 2>&1 || true
|
||||
echo "Fehler: $RUN_DIR/control.json enthaelt nach dem Neustart Phase '$_actual_phase' statt '$_expect_phase' - RuntimeDirectory wurde vermutlich geleert. Zugangspunkt wieder abgeschaltet." >&2
|
||||
echo "Error: after the restart $RUN_DIR/control.json holds phase '$_actual_phase' instead of '$_expect_phase' - the RuntimeDirectory was probably wiped. Access point switched off again." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -606,26 +606,26 @@ parse_for_option() {
|
||||
autooff_arm_if_requested() {
|
||||
[ -n "$_for_minutes" ] || return 0
|
||||
autooff_arm "$_for_minutes" "$((_for_minutes * 60))" 0 || exit 1
|
||||
echo "Zeitschalter: Auto-Aus in $_for_minutes min ('ninlight-station renew' verlaengert, 'hold' bestellt ab)"
|
||||
echo "Timer: auto-off in $_for_minutes min ('ninlight-station renew' extends it, 'hold' cancels it)"
|
||||
}
|
||||
|
||||
recovery_on() {
|
||||
parse_for_option recovery "$@"
|
||||
need_profile "$AP_CONNECTION"
|
||||
n=$(images | wc -l | tr -d ' ')
|
||||
[ "$n" -gt 0 ] || echo "Warnung: $IMAGE_DIR enthaelt kein Image - die Station antwortet auf alles mit 404" >&2
|
||||
[ "$n" -gt 0 ] || echo "Warning: $IMAGE_DIR holds no image - the station answers everything with 404" >&2
|
||||
ap_switch "$AP_CONNECTION"
|
||||
write_mode "recovery"
|
||||
start_and_verify "$AP_CONNECTION" "recovery"
|
||||
echo "Station an: SSID $SSID auf 192.168.8.1, $n Image(s)"
|
||||
echo "Station on: SSID $SSID at 192.168.8.1, $n image(s)"
|
||||
# Mit dem oeffentlichen Default-Passwort (im Repo dokumentiert) kann jeder in
|
||||
# Funkreichweite, der es kennt, jeder Lampe beliebige Firmware unterschieben - das ist
|
||||
# die eine Haelfte der Betriebsregeln aus README.md/§9, die andere (Station wieder
|
||||
# ausschalten) steht unten.
|
||||
if [ "$PSK" = "ninlight-recovery" ]; then
|
||||
echo "Warnung: PSK ist noch der oeffentliche Default 'ninlight-recovery' - eigenes Passwort in /etc/ninlight-station.conf setzen." >&2
|
||||
echo "Warning: PSK is still the public default 'ninlight-recovery' - set your own password in /etc/ninlight-station.conf." >&2
|
||||
fi
|
||||
echo "Nicht vergessen: 'ninlight-station off', wenn du fertig bist."
|
||||
echo "Do not forget: 'ninlight-station off' when you are done."
|
||||
autooff_arm_if_requested
|
||||
}
|
||||
|
||||
@@ -658,23 +658,23 @@ migrate_on() {
|
||||
_set=$(imageset_get)
|
||||
_setdir=$(imageset_dir "$_set")
|
||||
n=$(migrate_images | wc -l | tr -d ' ')
|
||||
[ "$n" -gt 0 ] || echo "Warnung: $_setdir enthaelt keine Migrationsimages - die Station antwortet auf alles mit 404" >&2
|
||||
[ "$n" -gt 0 ] || echo "Warning: $_setdir holds no migration images - the station answers everything with 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"
|
||||
write_mode "migration"
|
||||
write_control "$_phase" "" || {
|
||||
echo "Fehler: $RUN_DIR/control.json konnte nicht geschrieben werden" >&2
|
||||
echo "Error: could not write $RUN_DIR/control.json" >&2
|
||||
exit 1
|
||||
}
|
||||
start_and_verify "$MIGRATE_AP_CONNECTION" "migration" "$_phase"
|
||||
echo "Migration an: SSID $MIGRATE_SSID auf 192.168.8.1, Phase $_phase, $n Migrationsimage(s)"
|
||||
echo "Migration on: SSID $MIGRATE_SSID at 192.168.8.1, phase $_phase, $n migration image(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."
|
||||
echo "Image set: $(imageset_label "$_set")"
|
||||
echo "Caution: the password of this access point is publicly known from the old firmware - see README.md." >&2
|
||||
echo "Do not forget: 'ninlight-station off' when you are done."
|
||||
autooff_arm_if_requested
|
||||
}
|
||||
|
||||
@@ -722,7 +722,7 @@ display_run() {
|
||||
display_service_resume() {
|
||||
[ "${_was_active:-0}" -eq 1 ] || return 0
|
||||
sudo systemctl start ninlight-display 2>/dev/null \
|
||||
|| echo "Warnung: Anzeigedienst konnte nicht wieder gestartet werden - 'systemctl status ninlight-display' pruefen" >&2
|
||||
|| echo "Warning: could not start the display service again - check 'systemctl status ninlight-display'" >&2
|
||||
}
|
||||
|
||||
display_handover() {
|
||||
@@ -789,7 +789,7 @@ display_off() {
|
||||
sudo systemctl stop ninlight-display 2>/dev/null || true
|
||||
# Kein Abbruch, wenn das Panel fehlt: display.py beendet sich dann selbst mit 0, und
|
||||
# ein Fehler an der Anzeige darf das Ausschalten der Station nie aufhalten.
|
||||
display_run --clear || echo "Warnung: Panel konnte nicht geleert werden - Anzeige pruefen" >&2
|
||||
display_run --clear || echo "Warning: could not clear the panel - check the display" >&2
|
||||
}
|
||||
|
||||
# --- Abschlussbildschirm beim Herunterfahren und beim Neustart ----------------------
|
||||
@@ -820,13 +820,13 @@ display_final() {
|
||||
# Bewusst KEIN "systemctl stop" von hier aus: das liefe mitten in der
|
||||
# Abschalt-Transaktion und koennte sich mit ihr verhaken. Lieber eine ehrliche
|
||||
# Zeile im Journal als ein haengendes Herunterfahren.
|
||||
echo "Warnung: Anzeigedienst laeuft nach ${DISPLAY_RELEASE_WAIT_S}s noch - kein Abschlussbild (GPIO belegt)" >&2
|
||||
echo "Warning: display service still running after ${DISPLAY_RELEASE_WAIT_S}s - no final image (GPIO busy)" >&2
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
_waited=$((_waited + 1))
|
||||
done
|
||||
display_run --final "$1" || echo "Warnung: Abschlussbild konnte nicht gezeichnet werden - Anzeige pruefen" >&2
|
||||
display_run --final "$1" || echo "Warning: could not draw the final image - check the display" >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -846,18 +846,18 @@ full_off() {
|
||||
ap_switch ""
|
||||
if nmcli -t --escape no -f NAME con show | grep -Fqx "$HOME_CONNECTION"; then
|
||||
if sudo nmcli con up "$HOME_CONNECTION" >/dev/null; then
|
||||
echo "Station aus, wlan0 zurueck im Heim-WLAN ($HOME_CONNECTION)"
|
||||
echo "Station off, wlan0 back in the home Wi-Fi ($HOME_CONNECTION)"
|
||||
else
|
||||
echo "Station aus. Zurueckschalten zu '$HOME_CONNECTION' fehlgeschlagen - wlan0-Status pruefen." >&2
|
||||
echo "Station off. Switching back to '$HOME_CONNECTION' failed - check the wlan0 status." >&2
|
||||
fi
|
||||
else
|
||||
echo "Station aus. Profil '$HOME_CONNECTION' fehlt, wlan0 bleibt ungenutzt - der Zugang ueber Kabel ist davon nicht betroffen." >&2
|
||||
echo "Station off. Profile '$HOME_CONNECTION' missing, wlan0 stays unused - access over the cable is unaffected." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
listen_cmd() {
|
||||
write_control "listen" "" || {
|
||||
echo "Fehler: $RUN_DIR/control.json konnte nicht geschrieben werden" >&2
|
||||
echo "Error: could not write $RUN_DIR/control.json" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "Phase: listen"
|
||||
@@ -882,7 +882,7 @@ if not t:
|
||||
print(t)
|
||||
PY
|
||||
); then
|
||||
echo "Fehler: kein zuletzt erkanntes Modell (last_seen) in $_status_file - Ziel angeben: ninlight-station arm <target>" >&2
|
||||
echo "Error: no recently detected model (last_seen) in $_status_file - name a target: ninlight-station arm <target>" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -896,14 +896,14 @@ target = sys.argv[2]
|
||||
sys.exit(0 if any(p.target == target for p in products.PRODUCTS.values()) else 1)
|
||||
PY
|
||||
then
|
||||
echo "Fehler: unbekanntes Ziel '$_target' - gueltige Ziele stehen in products.py" >&2
|
||||
echo "Error: unknown target '$_target' - valid targets are listed in products.py" >&2
|
||||
exit 1
|
||||
fi
|
||||
write_control "armed" "$_target" || {
|
||||
echo "Fehler: $RUN_DIR/control.json konnte nicht geschrieben werden" >&2
|
||||
echo "Error: could not write $RUN_DIR/control.json" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "Freigegeben: $_target"
|
||||
echo "Armed: $_target"
|
||||
}
|
||||
|
||||
# "renew [<minuten>]" - die Uhr zurueckstellen. Ohne Argument auf dieselbe Dauer, die
|
||||
@@ -915,7 +915,7 @@ PY
|
||||
renew_cmd() {
|
||||
_arg=${1:-}
|
||||
if ! _info=$(autooff_read); then
|
||||
echo "Fehler: kein Zeitschalter aktiv - 'renew' stellt nur einen laufenden zurueck. Einen neuen gibt es nur mit 'ninlight-station on --for <minuten>'." >&2
|
||||
echo "Error: no timer active - 'renew' only resets a running one. A new one comes from 'ninlight-station on --for <minutes>'." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Absichtliches Wortsplitting: autooff_read() liefert drei Zahlen, durch Leerzeichen getrennt.
|
||||
@@ -927,17 +927,17 @@ renew_cmd() {
|
||||
_minutes=$_arg
|
||||
fi
|
||||
autooff_arm "$_minutes" "$((_minutes * 60))" 0 || exit 1
|
||||
echo "Zeitschalter zurueckgestellt: Auto-Aus in $_minutes min"
|
||||
echo "Timer reset: auto-off in $_minutes min"
|
||||
}
|
||||
|
||||
# "hold" - den Zeitschalter abbestellen. Die Station bleibt an, bis jemand "off" sagt.
|
||||
hold_cmd() {
|
||||
if ! autooff_read >/dev/null; then
|
||||
echo "Fehler: kein Zeitschalter aktiv - es gibt nichts abzubestellen." >&2
|
||||
echo "Error: no timer active - there is nothing to cancel." >&2
|
||||
exit 1
|
||||
fi
|
||||
autooff_clear
|
||||
echo "Zeitschalter abbestellt - die Station bleibt an, bis 'ninlight-station off'."
|
||||
echo "Timer cancelled - the station stays on until 'ninlight-station off'."
|
||||
}
|
||||
|
||||
# Restzeit fuer "status", oder leer, wenn kein Zeitschalter laeuft (dann steht in der
|
||||
@@ -949,9 +949,9 @@ autooff_status_line() {
|
||||
set -- $_info
|
||||
_rest=$(( ($2 - $(date +%s) + 59) / 60 ))
|
||||
if [ "$_rest" -gt 0 ]; then
|
||||
printf 'Auto-Aus: in %s min (angefordert: %s min)\n' "$_rest" "$1"
|
||||
printf 'Auto-off: in %s min (requested: %s min)\n' "$_rest" "$1"
|
||||
else
|
||||
printf 'Auto-Aus: steht an (angefordert: %s min)\n' "$1"
|
||||
printf 'Auto-off: pending (requested: %s min)\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -994,8 +994,8 @@ PY
|
||||
_modus=$(printf '%s\n' "$_info" | sed -n '1p')
|
||||
_erkannt=$(printf '%s\n' "$_info" | sed -n '2p')
|
||||
elif [ -e "$_status_file" ]; then
|
||||
_modus="unbekannt (Datei nicht lesbar)"
|
||||
_erkannt="unbekannt (Datei nicht lesbar)"
|
||||
_modus="unknown (file not readable)"
|
||||
_erkannt="unknown (file not readable)"
|
||||
else
|
||||
_modus="-"
|
||||
_erkannt="-"
|
||||
@@ -1044,15 +1044,15 @@ PY
|
||||
else
|
||||
_phase="-"
|
||||
fi
|
||||
printf 'Modus : %s\n' "$_modus"
|
||||
printf 'Phase : %s\n' "$_phase"
|
||||
printf 'Mode : %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)"
|
||||
printf 'Detected: %s\n' "$_erkannt"
|
||||
printf 'Service : %s\n' "$(systemctl is-active ninlight-station 2>/dev/null || true)"
|
||||
autooff_status_line
|
||||
printf 'wlan0 : %s\n' "$(nmcli -t --escape no -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2-)"
|
||||
printf 'Adresse: %s\n' "$(ip -4 -br addr show wlan0 2>/dev/null | awk '{print $3}')"
|
||||
echo "Images :"
|
||||
printf 'wlan0 : %s\n' "$(nmcli -t --escape no -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2-)"
|
||||
printf 'Address : %s\n' "$(ip -4 -br addr show wlan0 2>/dev/null | awk '{print $3}')"
|
||||
echo "Images :"
|
||||
images | while read -r f; do
|
||||
printf ' %-34s %s\n' "$(basename "$f")" \
|
||||
"$(python3 - "$f" <<'PY'
|
||||
@@ -1063,10 +1063,10 @@ PY
|
||||
)"
|
||||
done
|
||||
if [ -r "$_status_file" ]; then
|
||||
echo "Zuletzt ausgeliefert:"
|
||||
echo "Last served:"
|
||||
sed 's/^/ /' "$_status_file"
|
||||
elif [ -e "$_status_file" ]; then
|
||||
echo "Fehler: $_status_file existiert, ist aber nicht lesbar (Rechte pruefen)" >&2
|
||||
echo "Error: $_status_file exists but is not readable (check permissions)" >&2
|
||||
fi
|
||||
# "status" soll mit 0 enden, sobald es seine Auskunft geben konnte, auch wenn noch nie
|
||||
# ausgeliefert wurde - ohne das explizite exit 0 waere der Exit-Code des Skripts hier
|
||||
@@ -1082,7 +1082,7 @@ display_cmd() {
|
||||
final)
|
||||
case "${2:-}" in
|
||||
poweroff|reboot) display_final "$2" ;;
|
||||
*) echo "Fehler: 'display final' braucht 'poweroff' oder 'reboot'" >&2; exit 2 ;;
|
||||
*) echo "Error: 'display final' needs 'poweroff' or 'reboot'" >&2; exit 2 ;;
|
||||
esac
|
||||
;;
|
||||
*) usage; exit 2 ;;
|
||||
@@ -1090,48 +1090,48 @@ display_cmd() {
|
||||
}
|
||||
|
||||
usage() {
|
||||
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 "Usage: ninlight-station on [--for <minutes>]|recovery {on [--for <minutes>]|off}|migrate {on [--listen] [--for <minutes>]|off}|arm [<target>]|listen|bildsatz [ohne-wlan|mit-wlan]|renew [<minutes>]|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
|
||||
echo " WLAN angemeldet bist: 'on' macht wlan0 zum Zugangspunkt und" >&2
|
||||
echo " reisst die SSH-Sitzung ab. Erlaubt: 1-240." >&2
|
||||
echo " renew [<min>] Uhr zurueckstellen (ohne Angabe auf die zuletzt angeforderte" >&2
|
||||
echo " Dauer). Laeuft keiner, ist das ein Fehler." >&2
|
||||
echo " hold Zeitschalter abbestellen, Station bleibt an." >&2
|
||||
echo " display test Testbild aufs Panel zeichnen. Das ist der erste Handgriff bei der" >&2
|
||||
echo " Hardware-Abnahme und die EINZIGE Moeglichkeit, die Panel-Revision" >&2
|
||||
echo " zu bestimmen: die steht am Geraet nirgends. Bleibt das Bild leer," >&2
|
||||
echo " verzerrt oder verschoben, ist EPD_REVISION in" >&2
|
||||
echo " /etc/ninlight-station.conf falsch - auf die andere Revision" >&2
|
||||
echo " umstellen (V2 statt V3 oder umgekehrt), das Panel kurz" >&2
|
||||
echo " stromlos machen und erneut 'display test'." >&2
|
||||
echo " Ein laufender Anzeigedienst wird dafuer kurz gestoppt und" >&2
|
||||
echo " danach wieder gestartet (er haelt sonst die GPIO-Leitungen)." >&2
|
||||
echo " display clear Panel leeren (ebenfalls mit kurzer Unterbrechung des Dienstes)." >&2
|
||||
echo " bildsatz Switch: which set of migration images is served." >&2
|
||||
echo " Without an argument it only reports. 'ohne-wlan' (default) serves" >&2
|
||||
echo " the builds from tools/build_nocreds.sh - the migrated lamp comes" >&2
|
||||
echo " up in its own onboarding access point. 'mit-wlan' serves the" >&2
|
||||
echo " builds from build/ - the lamp joins the Wi-Fi from" >&2
|
||||
echo " config.local.cmake right away, including a lamp that is not" >&2
|
||||
echo " yours and got picked up in automatic mode. The setting sticks" >&2
|
||||
echo " until someone changes it, and is shown on the panel." >&2
|
||||
echo " --for <minutes> Timer: the station switches itself off after <minutes> (back to" >&2
|
||||
echo " the home Wi-Fi). OPTIONAL - without '--for' it stays on until" >&2
|
||||
echo " someone says 'off'. Useful when you are logged in over Wi-Fi:" >&2
|
||||
echo " 'on' turns wlan0 into an access point and drops your SSH" >&2
|
||||
echo " session. Allowed: 1-240." >&2
|
||||
echo " renew [<min>] Reset the timer (without an argument to the duration last" >&2
|
||||
echo " requested). If none is running, that is an error." >&2
|
||||
echo " hold Cancel the timer, station stays on." >&2
|
||||
echo " display test Draw a test image on the panel. This is the first step of the" >&2
|
||||
echo " hardware acceptance and the ONLY way to determine the panel" >&2
|
||||
echo " revision: it is printed nowhere on the device. If the image" >&2
|
||||
echo " stays blank, distorted or shifted, EPD_REVISION in" >&2
|
||||
echo " /etc/ninlight-station.conf is wrong - switch it to the other" >&2
|
||||
echo " revision (V2 instead of V3 or the other way round), power the" >&2
|
||||
echo " panel down briefly and run 'display test' again." >&2
|
||||
echo " A running display service is stopped for this and started" >&2
|
||||
echo " again afterwards (it holds the GPIO lines otherwise)." >&2
|
||||
echo " display clear Clear the panel (also with a short interruption of the service)." >&2
|
||||
echo " display final {poweroff|reboot}" >&2
|
||||
echo " Abschlussbild aufs Panel. Kein Handgriff fuer Menschen: das" >&2
|
||||
echo " rufen ninlight-poweroff.service/ninlight-reboot.service beim" >&2
|
||||
echo " Herunterfahren bzw. Neustart auf, nachdem der Anzeigedienst" >&2
|
||||
echo " die GPIO-Leitungen freigegeben hat. E-Paper behaelt sein Bild" >&2
|
||||
echo " dauerhaft - ohne diesen Schritt bliebe die letzte Rueckfrage" >&2
|
||||
echo " auf dem Panel stehen. Die Texte unterscheiden sich: beim" >&2
|
||||
echo " Neustart darf man den Stecker gerade NICHT ziehen." >&2
|
||||
echo " display off Anzeigedienst dauerhaft stoppen und das Panel leeren. 'on'/'off'" >&2
|
||||
echo " der Station brauchen das nicht - der Anzeigedienst laeuft" >&2
|
||||
echo " unabhaengig davon durch und zeichnet den Zustand selbst." >&2
|
||||
echo " Final image on the panel. Not a step for humans: this is what" >&2
|
||||
echo " ninlight-poweroff.service/ninlight-reboot.service call during" >&2
|
||||
echo " shutdown or reboot, once the display service has released the" >&2
|
||||
echo " GPIO lines. E-paper keeps its image forever - without this step" >&2
|
||||
echo " the last confirmation prompt would stay on the panel. The two" >&2
|
||||
echo " texts differ: on a reboot you must NOT unplug." >&2
|
||||
echo " display off Stop the display service for good and clear the panel. The" >&2
|
||||
echo " station's 'on'/'off' do not need this - the display service" >&2
|
||||
echo " keeps running and draws the state by itself." >&2
|
||||
echo "" >&2
|
||||
echo " Taster (GPIO23): kurzer Druck oeffnet am Geraet ein Menue ueber genau diese" >&2
|
||||
echo " Unterbefehle, 3 s gehalten brechen eine laufende Migration/Rettung ab." >&2
|
||||
echo " Button (GPIO23): a short press opens a menu on the device covering exactly" >&2
|
||||
echo " these subcommands, holding 3 s aborts a running migration or" >&2
|
||||
echo " recovery." >&2
|
||||
}
|
||||
|
||||
_cmd=${1:-}
|
||||
|
||||
Reference in New Issue
Block a user