Automatisches Starten eines Python-Skripts auf dem Raspberry Pi mit Systemd
In diesem Artikel zeige ich, wie man ein Python-Skript automatisch beim Systemstart auf dem Raspberry Pi ausführen kann. Diese Methode funktioniert auf Systemen mit und ohne Desktop-Umgebung und ist mit den aktuellen Versionen des Raspberry Pi OS, einschließlich Bullseye und Bookworm, kompatibel.
Warum Systemd?
Systemd ist ein init-System zur Verwaltung von Systemprozessen auf modernen Linux-Distributionen. Es bietet eine flexible und robuste Möglichkeit, Dienste beim Systemstart zu verwalten. Wer sein Python-Skript mit Systemd startet, kann sicher sein, dass es zuverlässig und konsistent ausgeführt wird.
Schritte zur Einrichtung des Autostarts
1. Python-Skript vorbereiten
Stelle sicher, dass dein Python-Skript den absoluten Pfad zu allen wichtigen Dateien verwendet. Hier ist ein Beispiel für eine SQLite3-Datenbankdatei im Unterordner data und eine Fonts-Datei im Unterordner fonds:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import os import sqlite3 from PIL import ImageFont # Basisverzeichnis des Skripts base_dir = os.path.dirname(os.path.abspath(__file__)) # Absoluter Pfad zur Datenbankdatei db_path = os.path.join(base_dir, 'data', 'data.db') # Absoluter Pfad zur Schriftdatei font_path_large = os.path.join(base_dir, 'fonds', 'webfont.ttf') # Erstelle das Verzeichnis 'data', falls es nicht existiert os.makedirs(os.path.dirname(db_path), exist_ok=True) # Schriftart laden font_large = ImageFont.truetype(font_path_large, 45) font_small = ImageFont.truetype(font_path_large, 13) # Restlicher Code ... |
2. Systemd-Dienstdatei erstellen
Erstelle eine neue Dienstdatei unter /etc/systemd/system/beispiel.service:
1 |
sudo nano /etc/systemd/system/beispiel.service |
beispiel ist hier ein Synonym für den verwendeten Namen deines Skripts.
Füge den folgenden Inhalt ein und passe die Pfade und den Benutzer an:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[Unit] Description=beispiel After=network.target [Service] ExecStart=/usr/bin/python3 /var/www/html/beispiel.py # Passe den Pfad und den Skriptnamen an WorkingDirectory=/var/www/html # Passe den Pfad an, unter dem das Skript ausgeführt werden soll StandardOutput=inherit StandardError=inherit Restart=always User=pi # Passe den Benutzer an, unter dem das Skript ausgeführt werden soll [Install] WantedBy=multi-user.target |
3. Systemd-Dienst aktivieren und starten
Lade die Systemd-Daemon neu und aktiviere den Dienst:
1 2 3 |
sudo systemctl daemon-reload sudo systemctl enable beispiel.service sudo systemctl start beispiel.service |
Beachte: beispiel.service anzupassen.
4. Überprüfen des Dienststatus
Stelle sicher, dass der Dienst korrekt gestartet wurde:
1 |
sudo systemctl status beispiel.service |
Beachte: beispiel.service anzupassen.
5. Dienst deaktivieren und entfernen (optional)
Wenn du den Autostart wieder entfernen möchtest, deaktiviere den Dienst und lösche ggf. die Dienstdatei:
1 2 3 4 |
sudo systemctl disable beispiel.service sudo systemctl stop beispiel.service sudo rm /etc/systemd/system/beispiel.service sudo systemctl daemon-reload |
Beachte: beispiel.service anzupassen.
Fazit
Durch die Verwendung von Systemd kannst du sicherstellen, dass dein Python-Skript beim Systemstart zuverlässig und konsistent ausgeführt wird. Diese Methode ist besonders nützlich für Projekte, die auf verschiedenen Raspberry Pi Modellen im Desktop-Modus und ohne Desktop-Modus laufen.
Hinweis: Auf meinem Blog findest du frühere Beiträge zum Autostart von Python-Skripten auf dem Raspberry Pi:
- Autostart eines Python Programm auf dem Raspberry Pi
- Python Script auf dem Raspberry Pi automatisch starten
Die Verwendung von Systemd bietet eine zusätzliche Möglichkeit, die auf allen Raspberry Pi OS-Versionen funktioniert und sowohl für Desktop- als auch für Headless-Setups geeignet ist.
Mittlerweile läuft wieder (fast) alles. Eine Frage noch: Kann ich den Dienst auch so einrichten, dass er erst gestartet wird, wenn Mosquitto läuft? Was muss ich dafür machen?
Ja, ein Dienst kann mit systemd in Abhängigkeit von einem anderen Dienst gestartet werden. Dies wird durch die Konfiguration der [Unit]-Sektion der Systemd-Dienstdatei erreicht. Hier gibt es verschiedene Anweisungen:
Zum Beispiel: After=: Gibt an, dass der Dienst nach einem anderen Dienst gestartet werden soll.
Siehe: https://manpages.debian.org/unstable/manpages-de/systemd.service.5.de.html
Die mosquitto.service sieht so aus:
[Unit]
Description=Mosquitto MQTT Broker
Documentation=man:mosquitto.conf(5) man:mosquitto(8)
After=network.target
Wants=network.target
[Service]
Type=notify
NotifyAccess=main
ExecStart=/usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
ExecStartPre=/bin/mkdir -m 740 -p /var/log/mosquitto
ExecStartPre=/bin/chown mosquitto /var/log/mosquitto
ExecStartPre=/bin/mkdir -m 740 -p /run/mosquitto
ExecStartPre=/bin/chown mosquitto /run/mosquitto
[Install]
WantedBy=multi-user.target
Persönlich kenne ich mich mit Mosquitto nicht aus. Man findet aber oft einen Hinweis in der Logdatei.
Um systemd zu testen, würde ich einfach ein kleines Python-Skript schreiben, das einfach einen Zähler inkrementiert. Wenn der Dienst korrekt gestartet wurde, kann man ihn sofort abbrechen und löschen.
Die json-data.service habe ich mittlerweile gelöscht, weil auch mosquitto nicht mehr startete. Auch ein reinstall von Mosquitto hat nicht geholfen weshalb ich ein Problem mit systemd vermute. Die Fehlermeldung sieht so aus:
pi@raspberrypi:~ $ sudo systemctl status mosquitto
● mosquitto.service – Mosquitto MQTT Broker
Loaded: loaded (/lib/systemd/system/mosquitto.service; enabled; vendor preset: enabled)
Active: failed (Result: signal) since Thu 2024-05-30 17:00:19 CEST; 13s ago
Docs: man:mosquitto.conf(5)
man:mosquitto(8)
Process: 1298 ExecStartPre=/bin/mkdir -m 740 -p /var/log/mosquitto (code=exited, status=0/SUCCESS)
Process: 1299 ExecStartPre=/bin/chown mosquitto /var/log/mosquitto (code=exited, status=0/SUCCESS)
Process: 1301 ExecStartPre=/bin/mkdir -m 740 -p /run/mosquitto (code=exited, status=0/SUCCESS)
Process: 1303 ExecStartPre=/bin/chown mosquitto /run/mosquitto (code=exited, status=0/SUCCESS)
Process: 1304 ExecStart=/usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf (code=killed, signal=ILL)
Main PID: 1304 (code=killed, signal=ILL)
Mai 30 17:00:19 raspberrypi systemd[1]: mosquitto.service: Failed with result ‘signal’.
Mai 30 17:00:19 raspberrypi systemd[1]: Failed to start Mosquitto MQTT Broker.
Mai 30 17:00:19 raspberrypi systemd[1]: mosquitto.service: Service RestartSec=100ms expired, scheduling restart.
Mai 30 17:00:19 raspberrypi systemd[1]: mosquitto.service: Scheduled restart job, restart counter is at 5.
Mai 30 17:00:19 raspberrypi systemd[1]: Stopped Mosquitto MQTT Broker.
Mai 30 17:00:19 raspberrypi systemd[1]: mosquitto.service: Start request repeated too quickly.
Mai 30 17:00:19 raspberrypi systemd[1]: mosquitto.service: Failed with result ‘signal’.
Mai 30 17:00:19 raspberrypi systemd[1]: Failed to start Mosquitto MQTT Broker.
Ok, da ist eine Fehlersuche nicht mehr möglich.
Das ist seltsam, den Benutzer pi gibt es nämlich und nur den habe ich eingesetzt.
Ok, hört sich tatsächlich seltsam an. Wie sieht den die json-data.service Datei aus?
Ich bekomme unter buster die folgende Fehlermeldung, wenn ich das Kommando sudo systemctl start json-data.service absetze:
Failed to start json-data.service: Unit json-data.service has a bad unit file setting.
See system logs and ‘systemctl status json-data.service’ for details.
systemctl status json-data.service zeigt dann:
Mai 30 10:21:19 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:1: Assignment outside of section. Ignoring.
Mai 30 10:21:19 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:2: Assignment outside of section. Ignoring.
Mai 30 10:21:19 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:9: Invalid user/group name or numeric ID: pi # Passe den Benutzer an, unter dem das Skript ausgeführt wer
Mai 30 10:23:30 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:1: Assignment outside of section. Ignoring.
Mai 30 10:23:30 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:2: Assignment outside of section. Ignoring.
Mai 30 10:23:30 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:9: Invalid user/group name or numeric ID: pi # Passe den Benutzer an, unter dem das Skript ausgeführt wer
Mai 30 10:23:50 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:1: Assignment outside of section. Ignoring.
Mai 30 10:23:50 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:2: Assignment outside of section. Ignoring.
Mai 30 10:23:50 raspberrypi systemd[1]: /etc/systemd/system/json-data.service:9: Invalid user/group name or numeric ID: pi # Passe den Benutzer an, unter dem das Skript ausgeführt wer
Hallo,
die Fehlermeldung deutet darauf hin, dass die Dienstdatei json-data.service syntaktische Fehler enthält. Insbesondere gibt es Zuweisungen außerhalb der Abschnitte und einen ungültigen Benutzernamen oder Kommentar in der Datei.
Daher empfehle ich einmal dein Skript mit der eventuellen Pfadangabe aus dem Terminal aufzurufen und die Daten des Benutzers (User=) anpassen.
Viele Grüße
Wolfgang
Kleiner Hinweis, alle Kommentare werden moderiert.
Dies bedeutet, der Kommentar wird vor der Veröffentlichung durchgelesen und von mir geprüft. Auch behalte ich mir vor, jeden Kommentar zu löschen, der nicht direkt auf das Thema abzielt oder nur den Zweck hat, Leser oder Autoren herabzuwürdigen.
Neuste Beiträge
Kleinen Spickzettel für Raspbian OS Befehle
Entdecke die Welt von Webnist.de
Erfahre mehr über die Hintergründe meines Blogs und wie ich dich bei deinen digitalen Projekten unterstützen kann.Kategorien
KATEGORIEN
Aktuelles Video auf YouTube
Beschreibung der Verwendung eines TTP223B Touch Sensors am GPIO Port des Raspberry Pi mit Python.
Die aktuell 6 derzeit meistbesuchten Beiträge
Beiträge mit den meisten Kommentaren
Funktional Immer aktiv
Vorlieben
Statistiken
Marketing