feat(station): E-Paper-Anzeige fuer Modus, Lampe und Auslieferungen
render.lines() zerlegt den zusammengefuehrten Zustand (status.json + control.json + SSID aus der Konfigurationsdatei) in Textzeilen, ohne Pillow und ohne Hardware zu brauchen - render.compose() importiert Pillow erst innerhalb der Funktion. epdconfig.py ist eine eigene GPIO/SPI-Schicht auf gpiozero/spidev, weil RPi.GPIO auf Debian 13 mit Python 3.13 nicht mehr traegt; epd2in13_V2.py/epd2in13_V3.py sind unveraendert aus dem Waveshare-Repository uebernommen (siehe HERKUNFT.md), nur der epdconfig-Import zeigt auf unser Modul. display.py laeuft als eigener systemd-Dienst (Wants=, Restart=on-failure), fehlendes Panel/SPI/Bibliothek beendet ihn sauber mit sys.exit(0) statt einer Neustartschleife - eine Migration darf davon nie abhaengen. Verdrahtung in setup_pi.sh/deploy.sh/ninlight-station folgt in einem eigenen Durchgang.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
[Unit]
|
||||
Description=ninlight E-Paper-Anzeige (Status der Migrations-/Rettungsstation)
|
||||
# Nur eine Anzeige fuer den Hauptdienst - Wants=/After=, NICHT Requires=/BindsTo=: ein
|
||||
# fehlendes oder abgestuerztes Panel darf server.py niemals mitreissen, und server.py
|
||||
# darf umgekehrt starten, auch wenn dieser Dienst fehlt oder deaktiviert ist. Siehe
|
||||
# display.py's Modul-Docstring: die Anzeige ist nirgends Voraussetzung fuer die
|
||||
# Migration.
|
||||
After=ninlight-station.service
|
||||
Wants=ninlight-station.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# Reihenfolge wichtig: systemd wendet Environment=/EnvironmentFile= in der Reihenfolge
|
||||
# an, in der sie hier stehen, und eine spaetere Zuweisung ueberschreibt eine gleichnamige
|
||||
# fruehere. EPD_REVISION=V3 hier ist nur der Vorgabewert, falls die Konfigurationsdatei
|
||||
# (unten, per EnvironmentFile=) den Schluessel (noch) nicht enthaelt - z.B. auf einem Pi,
|
||||
# der vor Task 6 aufgesetzt wurde. Steht er dort, gewinnt er.
|
||||
Environment=EPD_REVISION=V3
|
||||
Environment=NINLIGHT_RUN_DIR=/run/ninlight-station
|
||||
Environment=NINLIGHT_STATION_CONF=/etc/ninlight-station.conf
|
||||
EnvironmentFile=/etc/ninlight-station.conf
|
||||
ExecStart=/usr/bin/python3 /opt/ninlight-station/display/display.py
|
||||
|
||||
# display.py faengt ein fehlendes/abgestuerztes Panel als DisplayUnavailable ab,
|
||||
# protokolliert eine Zeile und beendet sich mit sys.exit(0) - das ist also nie ein
|
||||
# "Fehlschlag" im systemd-Sinne und loest kein Restart= aus. Restart=on-failure (nicht
|
||||
# always) greift nur fuer echte Abstuerze (z.B. ein Python-Traceback aus einem
|
||||
# Programmierfehler); ohne den Deckel wuerde ein dauerhaft fehlendes Panel sonst NICHT
|
||||
# staendig neu versucht (gut so), waehrend ein echter Bug endlos neu starten wuerde und
|
||||
# so das Journal fluten koennte.
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
StartLimitIntervalSec=60
|
||||
StartLimitBurst=5
|
||||
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
PrivateTmp=yes
|
||||
ReadOnlyPaths=/run/ninlight-station
|
||||
RestrictAddressFamilies=AF_UNIX AF_NETLINK
|
||||
MemoryMax=64M
|
||||
|
||||
# Fuer /dev/spidev0.0 und die GPIO-Zeichenleitung (per lgpio/gpiozero) noetig - laeuft
|
||||
# deshalb nicht mit DynamicUser=, sondern als root wie der Hauptdienst.
|
||||
SupplementaryGroups=spi gpio
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user