- 'on' prueft nach dem Start wirklich, ob der Dienst aktiv ist (Type=simple meldet sonst schon Erfolg, wenn der Prozess nur gestartet wurde), und faehrt den Zugangspunkt bei einem toten Server wieder herunter statt ihn offen mit bekanntem Passwort ohne Server dahinter stehen zu lassen. - 'off' faengt einen fehlschlagenden Wechsel zurueck ins Heim-WLAN ab statt unter set -eu mit nmclis Rohausgabe abzubrechen. - Fehlende Schluessel in der Konfiguration werden nach dem Sourcen explizit geprueft und mit einem Verweis auf setup_pi.sh gemeldet statt mit "parameter not set" abzubrechen. - station.conf.example verwendet einfache statt doppelter Anfuehrungszeichen: POSIX ". datei" wertet $ und ` auch in doppelten Anfuehrungszeichen aus, ein Passwort mit "$1" waere sonst lautlos durch ein Shell-Argument ersetzt worden. systemds EnvironmentFile= fuehrt ohnehin nie eine Shell aus und entfernt einfache wie doppelte Anfuehrungszeichen gleichermassen. - ninlight-station.service: BindsTo=NetworkManager.service entfernt (ein dadurch ausgeloester Stop gilt fuer systemd als sauber und wird von keiner Restart=-Politik erneut gestartet - ein NetworkManager-Neustart haette den Server sonst still und dauerhaft mitgerissen); stattdessen nur After=NetworkManager.service fuer die Startreihenfolge und Restart=always, damit der Prozess nach einem Absturz (z.B. Bind-Fehler) automatisch wiederkommt. - Trailer-Reader im 'status'-Zweig nutzt jetzt errors="replace" wie trailer_version() in server.py, statt bei nicht-ASCII-Bytes im Versionsfeld abzustuerzen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
89 lines
3.5 KiB
Bash
Executable File
89 lines
3.5 KiB
Bash
Executable File
#!/bin/sh
|
|
# Schaltet die ninlight-Recovery-Station an und aus.
|
|
#
|
|
# Die Station ist absichtlich nicht dauerhaft an: Solange sie laeuft, kann jeder
|
|
# in Funkreichweite mit dem Passwort einer Lampe beim naechsten Boot beliebige
|
|
# Firmware unterschieben, und der Werksreset per fuenf Stromzyklen funktioniert
|
|
# bei keiner Lampe in Reichweite mehr (die Firmware loescht den Zaehler vor
|
|
# jedem Recovery-Versuch).
|
|
set -eu
|
|
|
|
CONF=/etc/ninlight-station.conf
|
|
[ -r "$CONF" ] || { echo "Fehler: $CONF fehlt - zuerst tools/station/setup_pi.sh ausfuehren" >&2; exit 1; }
|
|
# shellcheck disable=SC1090
|
|
. "$CONF"
|
|
|
|
for _key in SSID PSK IMAGE_DIR HOME_CONNECTION AP_CONNECTION; do
|
|
eval "test -n \"\${$_key-}\"" || {
|
|
echo "Fehler: $CONF: Schluessel $_key fehlt oder ist leer - tools/station/setup_pi.sh ausfuehren" >&2
|
|
exit 1
|
|
}
|
|
done
|
|
unset _key
|
|
|
|
need_profile() {
|
|
nmcli -t -f NAME con show | grep -qx "$AP_CONNECTION" || {
|
|
echo "Fehler: NetworkManager-Profil '$AP_CONNECTION' fehlt - tools/station/setup_pi.sh ausfuehren" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
images() {
|
|
find "$IMAGE_DIR" -maxdepth 1 -name 'ninlight_*_ota.img' 2>/dev/null | sort
|
|
}
|
|
|
|
case "${1:-}" in
|
|
on)
|
|
need_profile
|
|
n=$(images | wc -l | tr -d ' ')
|
|
[ "$n" -gt 0 ] || echo "Warnung: $IMAGE_DIR enthaelt kein Image - die Station antwortet auf alles mit 404" >&2
|
|
sudo nmcli con up "$AP_CONNECTION" >/dev/null
|
|
sudo systemctl start ninlight-station
|
|
# "systemctl start" meldet bei Type=simple schon Erfolg, sobald der Prozess
|
|
# gestartet wurde - nicht, sobald er ueberlebt hat. Kurz warten und wirklich
|
|
# nachsehen, sonst bleibt ein offener AP ohne Server dahinter stehen.
|
|
sleep 1
|
|
if systemctl is-active --quiet ninlight-station; then
|
|
echo "Station an: SSID $SSID auf 192.168.8.1, $n Image(s)"
|
|
echo "Nicht vergessen: 'ninlight-station off', wenn du fertig bist."
|
|
else
|
|
sudo nmcli con down "$AP_CONNECTION" >/dev/null 2>&1 || true
|
|
echo "Fehler: ninlight-station ist nach dem Start nicht aktiv - Zugangspunkt wieder abgeschaltet. Details: journalctl -u ninlight-station" >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
off)
|
|
sudo systemctl stop ninlight-station 2>/dev/null || true
|
|
sudo nmcli con down "$AP_CONNECTION" >/dev/null 2>&1 || true
|
|
if nmcli -t -f NAME con show | grep -qx "$HOME_CONNECTION"; then
|
|
if sudo nmcli con up "$HOME_CONNECTION" >/dev/null; then
|
|
echo "Station aus, wlan0 zurueck im Heim-WLAN ($HOME_CONNECTION)"
|
|
else
|
|
echo "Station aus. Zurueckschalten zu '$HOME_CONNECTION' fehlgeschlagen - wlan0-Status pruefen." >&2
|
|
fi
|
|
else
|
|
echo "Station aus. Profil '$HOME_CONNECTION' fehlt, wlan0 bleibt ungenutzt - der Zugang ueber Kabel ist davon nicht betroffen." >&2
|
|
fi
|
|
;;
|
|
status)
|
|
printf 'Dienst : %s\n' "$(systemctl is-active ninlight-station 2>/dev/null || echo inaktiv)"
|
|
printf 'wlan0 : %s\n' "$(nmcli -t -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 :"
|
|
images | while read -r f; do
|
|
printf ' %-34s %s\n' "$(basename "$f")" \
|
|
"$(python3 - "$f" <<'PY'
|
|
import pathlib, sys
|
|
t = pathlib.Path(sys.argv[1]).read_bytes()[-512:]
|
|
print(t[21:37].rstrip(b"\x00").decode("ascii", "replace") if t[:4] == b"NINL" else "kein Trailer")
|
|
PY
|
|
)"
|
|
done
|
|
[ -r /run/ninlight-station/status.json ] && { echo "Zuletzt ausgeliefert:"; sed 's/^/ /' /run/ninlight-station/status.json; }
|
|
;;
|
|
*)
|
|
echo "Aufruf: ninlight-station on|off|status" >&2
|
|
exit 2
|
|
;;
|
|
esac
|