Mittwoch, 13. Mai 2020

systemd unit file

Ich habe mich etwas mit systemd, speziell dem unit file von fhem und dem Start von für FHEM notwendigen Komponenten beschäftigt.
Für detailliertere Information wird diese Seite als Start empfohlen.  Eine Befehlsübersicht zu systemctl habe ich hier gefunden.
Die Datei fhem.service ist ein systemd unit file und wird bei der debian Installation von FHEM mit ausgeliefert.
Änderungen an dieser Datei sind normalerweise nicht notwendig. Man sollte zumindest genau wissen was man tut!
Ich möchte hier ein paar Fälle behandeln, wo das notwendig wird und dabei auch ein paar Erkenntnisse und Tipps aufschreiben.

Unit File - ein paar kurze Erklärung

Den aktuellen Inhalt kann man jederzeit anschauen:
systemctl cat fhem
Stand Mai 2020 hat die Datei folgenden Inhalt:

Inhalt fhem.service

# $Id: fhem.service 19235 2019-04-21 13:26:17Z betateilchen $

[Unit]
Description=FHEM Home Automation
Wants=network.target
After=network.target
#Requires=postgresql.service
#After=postgresql.service
#Requires=mysql.service
#After=mysql.service

[Service]
Type=forking
User=fhem
Group=dialout
WorkingDirectory=/opt/fhem
ExecStart=/usr/bin/perl fhem.pl fhem.cfg
#ExecStart=/usr/bin/perl fhem.pl configDB
Restart=always

[Install]
WantedBy=multi-user.target

Erklärung ausgewählter Parameter

Wants= die angegebene Services werden benötigt, fhem startet aber trotzdem falls die Services nicht gestartet werden können.
Requires= wenn der Service nicht gestartet werden kann, wird fhem nicht gestartet.
After= bewirkt, dass fhem nach dem Service (der Gruppe) gestartet wird. Das ist wichtig damit Services die für fhem notwendig sind schon gestartet sind. Benötig fhem z.B. Datenbanken sind die entsprechenden  Zeilen einzubauen oder durch entfernen des Kommentarzeichens (#) zu aktivieren.
Die eben genannten Optionen können mehrfach oder mit mehreren, Komma getrennten Einträgen vorkommen.
User=fhem bewirkt das der Services mit user fhem gestartet wird. Falls fhem mit dem user root gestartet wird, startet fhem.pl einen neuen Prozess unter dem User fhem.
Group=dialout Es wird die Gruppe dialout zum Start benutzt.
Beide Zeilen können für den normalen Start von FHEM auch auskommentiert werden.

Zusätzlicher Parameter

ExecStartPre= Hier kann ein Shell Befehl stehen, der vor dem Start des eigentlichen Service (ExecStart=) ausgeführt wird. Diese Zeile kann auch mehrfach vorkommen. Bei wenigen Zeilen kann man sich die Auslagerung in separate Scripte sparen.

Prozesse vor dem FHEM Start ausführen

Ziel ist es sicherzustellen, dass für den Start von FHEM alle Voraussetzungen erfüllt sind, z.B.
  • Hardware aktiviert
  • Datenbank gestartet
  • Systemprozess läuft (z.B. Bluetooth gestartet)
  • eigenen Prozessen ist gestartet 
Dazu gibt es mehrere Lösungswege:
  • die Datei fhem.service modifizieren
  • einen separaten Service implementieren
  • Abhängigkeiten definieren

Ein Script zusammen mit FHEM starten

1. Script bereitstellen
Dazu wird eine Scriptdatei erzeugt, Beispiel:
sudo nano /opt/fhem/ExecStartPre.sh
Den Code (Beispiele am Ende) hier einfügen und die Datei speichern und Editor verlassen (ctrl+s ctrl+x).

2. ExecStartPre aktivieren
Um ein Script mit root Rechten in der fhem.service unit auszuführen, müssen drei Zeilen in der Datei geändert werden.
sudo systemctl edit --full fhem
Vor der Zeile ExecStart= wir diese Zeile eingefügt:
ExecStartPre= bash /opt/fhem/ExecStartPre.sh
Die beiden Zeilen User und Group muss man auskommentieren, da die Unit sonst mit dem User fhem ausgeführt wird.
#User=fhem
#Group=dialout
Achtung: Die Gruppenmitgliedschaft des Users fhem (z.B. gpio) ist beim Systemstart an der Stelle noch nicht wirksam.

3. Änderungen aktivieren
Die Änderungen werden erst nach einem daemon-reload aktiv und nach einem restart wirksam.
#sudo systemctl daemon-reload # nur notwendig wenn nicht systemctl edit verwendet wurde
sudo systemctl restart fhem
Den Erfolg auch nach einem komplette Neustart testen!

Ein Script mit separater service unit starten

Wir erstellen quasi einen eigenen Service - Vorteil: Die fhem.service braucht man nicht verändern.

1. Script bereitstellen
Das Beispiel hier in einem allgemeinerem Pfad:
sudo nano /user/local/bin/EnableXX.sh
Den Code (Beispiele am Ende) hier einfügen und die Datei speichern und Editor verlassen (ctrl+s ctrl+x).

2. unit file erzeugen
Man erstellt eine neues unit file.
sudo systemctl edit --full --force enablexx.service
Mit folgendem Inhalt
[Unit]
Description=EnableXX
Before=fhem.service
#After=network.target

[Service]
Type=oneshot
ExecStart=bash /user/local/bin/EnableXX.sh
StandardOutput=journal

[Install]
WantedBy=multi-user.target

Die Zeile Before=fhem.service stellt sicher, dass der Start vor FHEM erfolgt

3. Service aktivieren
#sudo systemctl daemon-reload # nur notwendig wenn nicht systemctl edit verwendet wurde
sudo systemctl enable enablexx
sudo systemctl start enablexx
Den Erfolg auch nach einem komplette Neustart testen!

Start von anderen Services abhängig machen

In der fhem.service unit kann man sicherstellen, dass ein Service fertig gestartet wurde bevor fhem startet. Dazu kann man im unit Abschnitt zwei Zeilen einfügen (bzw. Kommentar entfernen):
Wants=xxx.service
After=xxx.service
Man kann auch erzwingen, dass FHEM nicht startet falls die Voraussetzungen nicht erfüllt sind. Dafür muss anstatt Wants= Requires= verwendet werden.

Hinweise und Tipps

Ich habe hier noch eine gute Befehlszusammenstellung gefunden.

Ausgaben im Script

Ausgaben mit echo landen im /var/log/syslog. Das Log kann man mit diesem Befehl anzeigen:
cat /var/log/syslog
Ist das Logfile zu unübersichtlich kann man sich auch z.B. nur 15 Zeilen nach systemd Ausgabe des unit files anzeigen lassen.
cat /var/log/syslog|grep -A 15 "FHEM Home"

Editieren von unit files

Es wird die integrierte Methode von systemctl empfohlen. Diese hat den Vorteil das nach dem Speichern automatisch ein daemon-reload durchgeführt wird.
sudo systemctl edit --full fhem
Typischerweise wird nano zum editieren geöffnet.
ctrl+s speichert die Datei
ctrl+x verlässt den Editor

Tipp für Windows

Windows 10 verfügt seit der Version 1709 über einen integrierten ssh Client, zusätzliche Tools wie putty & co sind nicht notwendig. Mit der Tastenkombination Windows + r die Ausführen Zeile öffnen und einfach den ssh Befehl eingeben:
ssh pi@raspib2
ssh -t pi@raspib2 sudo systemctl edit --full fhem
ssh -t pi@raspib2 sudo systemctl cat fhem; bash

Beispielcode

Diese Codebeispiel ist auf dem Raspberry Pi ausführbar und lässt vor dem Start von FHEM die grüne LED (ACT) blinken.
Beispiel 1: 3 mal kurz und 3 mal lang
# Lass die ACT LED (grün) am Pi 3 mal kurz und 3 mal lang blinken
ANZAHL=3
#Status (Standard [mmc0] )sichern
trigger=$(cat /sys/class/leds/led0/trigger|grep -o "\[.*\]"|tr -d [+])
#umschalten auf manuell
echo "none" >/sys/class/leds/led0/trigger
#blinken
for ((i=1 ; i<=$(( $ANZAHL * 2 )) ; i++ )); do
  echo $(( $i % 2 )) >/sys/class/leds/led0/brightness
  sleep 0.3
done
for ((i=1 ; i<=$(( $ANZAHL * 2 )) ; i++ )); do
  echo $(( $i % 2 )) >/sys/class/leds/led0/brightness
  sleep 1
done
#Status wieder herstellen
echo $trigger >/sys/class/leds/led0/trigger

Beispiel 2: Morsezeichen "FHEM"
echo "starte pre Script "
# act LED
led="/sys/class/leds/led0/brightness"
Status sichern
trigger=$(cat /sys/class/leds/led0/trigger|grep -o "\[.*\]"|tr -d [+])
# Zeichenfolge FHEM als Morsecode ausgeben
# Zeichen F · · − ·
echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2
echo 1 >$led;sleep 0.2;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.1;echo 0 >$led
sleep 0.4
# Zeichen H · · · ·
echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2
echo 1 >$led;sleep 0.1;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.1;echo 0 >$led
sleep 0.4
# Zeichen E ·
echo 1 >$led;sleep 0.1;echo 0 >$led
sleep 0.4
# Zeichen M − −
echo 1 >$led;sleep 0.2;echo 0 >$led;sleep 0.2;echo 1 >$led;sleep 0.2;echo 0 >$led
sleep 0.4
echo $trigger >/sys/class/leds/led0/trigger

Der Start von fhem.pl

Beim normalen Start der fhem.pl wird der Startprozess ziemlich schnell wieder beendet und ein neuer Prozess im Hintergrund gestartet. In der Doku steht dazu:
Falls FHEM als root gestartet wurde, und ein OS-Benutzer fhem existiert, dann wechselt FHEM nach dem start zu diesem Benutzer (via setuid).
Wird fhem.pl mit einem normalen User gestartet, wird der Hintergundprozess mit diesem User fortgeführt. Dies führt in der Regel zu Berechtigungsproblemen:

  • kein Schreibzugriff auf  Dateien die User fhem gehören (Logdateien usw.)

D.h.: Es ist nicht zwingend notwendig fhem.pl initial mit User fhem zu starten.

ToDo?
Code Block

Text

Keine Kommentare:

Kommentar veröffentlichen