[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