Fhem.service (systemd unit file)

Aus FHEMWiki

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! Der Artikel soll die Datei etwas beschreiben und ein paar Fälle behandeln die ein Anpassung notwendig machen.

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 /etc/systemd/system/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.

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.

unit file bearbeiten

Dieser Befehl editiert die (fhem.service) unit Datei mit dem Standard Editor (z.B. nano) und führt zum Abschluss auch ein daemon-reload durch.

sudo systemctl edit --full fhem

Tipp: Datei speichern ctrl+s und Editor verlassen ctrl+x

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.

Dazu gibt es mehrere Lösungswege:

  • die Datei fhem.service modifizieren
  • einen separaten Service implementieren
  • Abhängigkeiten definieren

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 /usr/local/bin/EnableXX.sh

Den Code (Beispiele am Ende) hier einfügen und die Datei speichern und Editor verlassen (ctrl+s ctrl+x).

Hier kann meist der Original Scriptcode verwendet werden, der früher in das init.d Script eingefügt werden sollte.

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 /usr/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!

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 (siehe oben).

Vor der Zeile ExecStart= wir diese Zeile eingefügt:

[Service]
...
ExecStartPre= bash /opt/fhem/ExecStartPre.sh
ExecStart=...

Die beiden Zeilen User und Group muss man auskommentieren, da die Unit sonst mit dem User fhem ausgeführt wird.

X mark.svgAchtung: Die Gruppenmitgliedschaft des Users fhem (z.B. gpio) ist beim Systemstart an der Stelle noch nicht wirksam.
#User=fhem 
#Group=dialout


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!

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

Insbesondere empfiehlt es sich auf den kompletten Start des Netzwerkes zu warten, vor allem wenn beim Start von FHEM Netzwerkressourcen online sein müssen (Netzlaufwerke, Dienste wie ser2net usw.).

Wants=network-online.target 
After=network-online.target

Man kann auch erzwingen, dass FHEM nicht startet falls die Voraussetzungen nicht erfüllt sind. Dafür muss anstatt Wants= Requires= verwendet werden.

Einstellungen dies und das

Start verzögern

Es ist immer besser eine direkte Abhängigkeit zu definieren. In unklaren Situationen oder als erste Abhilfe kann es notwendig sein, einfach den FHEM Start zu verzögern.

Der default Wert für TimeoutStartSec= liegt bei 90 sec. Anzeige mit systemctl show fhem.service -p TimeoutStartUSec

Soll die Startverzögerung länger sein, muss dieser Wert zusätzlich gesetzt werden. Ansonsten wird der Start mit einer Fehlermeldung abgebrochen.

[Service]
...
ExecStartPre=/bin/sleep 10
#TimeoutStartSec=            # default 90, set for larger sleep time

Restart verzögern

Sollte man z.B. bei einem Neustart über die FHEM Oberfläche (shutdown restart) zwei Starts innerhalb von 1 Sekunde im Logfile beobachten, kann man den Neustart im unit file mit einem Parameter um 2 - 10 Sekunden (siehe auch diesen Forenbeitrag) verzögern:

[Service]
...
Restart=...
RestartSec=2
...

Hinweise und Tipps

Startreihenfolge beeinflussen

Wie man erzwingen kann, dass FHEM nach hciuart (Bluetooth Service) startet, ist in diesem Forenbeitrag beschrieben.

Ausgaben im Script

Ausgaben mit echo landen im /var/log/syslog. Das Log kann man mit diesem Befehl anzeigen. 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
cat /var/log/syslog|grep -A 15 "FHEM Home"

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