Samstag, 3. Oktober 2015

systemd timer unter Raspbian

Ende September ist eine neue Raspian Version erschienen, welche auf Debian Jessie basiert. Und damit ist auch systemd als Init-Dienst standardmäßig an Bord.

Davon bekommt man als "normaler" Nutzer erst mal wenig mit, weil man in der Regel wenig "Berührung" mit dem Init-System hat.

Durch den Einsatz von systemd bietet sich aber die Möglichkeit, dessen Timer zu verwenden. systemd Timer sind ein Dienst, welcher periodisch bestimmte, frei festzulegende Aktion ausführen kann - und sind damit eine Alternative zu cron.

Das wird im folgenden anhand eines Beispiels gezeig.

Unter Verwendung eines systemd Timer soll das folgende Python Skript alle 5 Minuten ausgeführt werden:

#!/usr/bin/env python3

import sqlite3
import datetime
from sense_hat import SenseHat

s = SenseHat()
conn = sqlite3.connect('/home/pi/code/ambient_data.db')
sql = 'INSERT INTO data VALUES (?, ?, ?, ?)'
with conn:
    conn.execute(sql, (s.get_temperature(),
                       s.get_pressure(),
                       s.get_humidity(),
                       datetime.datetime.now()))
conn.close()

Das Skript liest den Temperatur-, Luftdruck- und Luftfeuchtigkeitssensor eines SenseHAT aus und schreibt die Daten in eine SQLite-Datenbank.
Das Skript heißt ambient_temperature_logger.py und liegt unter /home/pi/code.
Die zugehörige Datenbank ambient_data.db liegt im gleichen Verzeichnis.

Damit das Skript automatisch ausgeführt wird, muss man noch zwei Dateien für systemd erstellen:
  • eine .service Datei, welche das Skript aufruft
  • eine .timer Datei, welche die Daten für das automatische Ausführen enthält.
Beide Dateien legt man mit Root-Rechten im Verzeichnis /etc/systemd/system an.

Die Datei ambient_data_logger.service bekommt folgenden Inhalt:

[Unit]
Description=SenseHat Ambient Data Logger

[Service]
Type=simple
ExecStart=/home/pi/code/ambient_data_logger.py

Der Inhalt ist wohl weitestgehend selbsterklärend:
Im Abschnitt [Unit] steht eine Beschreibung, was passiert. Im Abschnitt [Service] wird bei Type der Typ festgelegt, was bei Skripten wie in diesem Beispiel normalerweise simple ist. Unter ExecStart wird der Befehl zum Aufruf des Skripts angegeben.

Die Datei ambient_data_logger.timer bekommt den folgenden Inhalt:

[Unit]
Description=Runs the ambient_data_logger Python script every 5 minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Unit=ambient_data_logger.service

[Install]
WantedBy=multi-user.target

Unter [Unit] wird wieder ein Beschreibung hinterlegt, unter [Install] WantedBy, welchem target der Timer zugeordnet wird. Für Skripte wie diese ist multi-user.target eine gute Wahl, weil der (aktiverte) Timer dann beim Systemstart mit gestartet wird.

Im Abschnitt [Timer] wird festgelegt, wann was passieren soll:
  • OnBootSec legt fest, wann das Skript (bzw. im Jargon von systemd die "Unit") ausgeführt werden soll - hier also nach 2 Minuten.
  • OnUnitActiveSec legt fest, nach wie viel Minuten die Unit jedes weitere Mal ausgeführt werden soll - hier also alle 5 Minuten
  • Unit legt fest, welche .service-Datei durch den Timer aufgerufen wird.
Jetzt muss man die .timer und die .service-Dateien noch ausführbar machen:

$ sudo chmod +x ambient_data_logger.*

und den Timer mit den folgenden beiden Befehlen aktivieren:

$ sudo systemctl start ambient_data_logger.timer
$ sudo systemctl enable ambient_data_logger.timer

Der erste Befehl startet den Timer, der zweite stellt sicher, dass der Timer auch nach einem Reboot aktiviert wird.
Zum Deaktivieren des Timers ersetzt man im ersten Befehl start durch stop und im zweiten Befehl enable durch disable.

Um zu prüfen, ob der Timer auch aktiv ist und läuft, kann man sich alle aktiven Timer anzeigen lassen:

$ systemctl list-timers

Das Anlegen von Timer von systemd ist also ziemlich gradlinig und nicht weiter schwierig.

Da systemd bei anderen Distribution (z.B. Fedora, Arch) schon länger im Einsatz ist, findet man im Internet reichlich Beispiele zu systemd und Timern. Da systemd weitestgehend unabhängig von den jeweiligen Eigenheiten der darüber liegenden Distribution ist, sind die Beispiele auch auf Raspbian übertragbar.
Außerdem sind die Man-Pages zu systemd und systemd.timer recht ausführlich.