[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 # Gehoeren seit systemd 229 ins [Unit], nicht ins [Service] (dort standen sie zuerst - # Fixrunde 1, I1: systemd ignoriert sie dort mit "Unknown key name", die Vorgabe (5 # Starts/10s) greift dann bei RestartSec=5 nie, und genau das sollte die Deckelung unten # eigentlich verhindern). ninlight-station.service (dieselbe Sektion) macht es richtig. StartLimitIntervalSec=60 StartLimitBurst=5 [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 NoNewPrivileges=yes ProtectSystem=strict ProtectHome=yes PrivateTmp=yes # KEIN ReadOnlyPaths=/run/ninlight-station hier (stand hier zuerst, Fixrunde 1, C3): # server.py's Unit traegt RuntimeDirectory=ninlight-station, und "ninlight-station off" # stoppt den Hauptdienst regulaer - dabei raeumt systemd dessen RuntimeDirectory auf, # sofern nicht gerade ein Neustart lief (RuntimeDirectoryPreserve=restart deckt nur den # Neustart-Fall ab, nicht den regulaeren Stop). Ein nicht mit "-" prefigierter Pfad in # ReadOnlyPaths=/ReadWritePaths=/BindPaths=, der beim Start fehlt, laesst systemd die # Namensraum-Einrichtung mit 226/NAMESPACE abbrechen - ausgerechnet dann, wenn die # Anzeige "Station aus" zeigen soll, waere sie selbst nicht mehr startbar gewesen. Die # Zeile war obendrein wirkungslos: ProtectSystem=strict macht "/" (und damit "/run", # soweit nicht per ReadWritePaths= explizit freigegeben) bereits schreibgeschuetzt. RestrictAddressFamilies=AF_UNIX AF_NETLINK MemoryMax=64M # Laeuft als root (wie der Hauptdienst) fuer /dev/spidev0.0 und die GPIO-Zeichenleitung - # kein SupplementaryGroups=spi gpio hier (stand hier zuerst, Fixrunde 1, I2): auf reinem # Debian (im Unterschied zu Raspberry Pi OS) gibt es diese Gruppen oft gar nicht, und # eine fehlende Gruppe ist fuer systemd ein harter Startfehler (216/GROUP) - ausgerechnet # in der Unit, die nie stoeren soll, wenn etwas an der Anzeige fehlt. Als root sind die # Gruppen fuer den Geraetezugriff ohnehin nicht noetig. [Install] WantedBy=multi-user.target