Skript bricht ab. Automatischer neu start?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

Hallo zusammen,

an meinem Raspberry PI werden jede Sekunde Daten vom Microcontroller über den UART gesendet.
Leider hat der Raspberry PI keinen richtigen UART sondern nur eine "miniuart" Schnittstelle. Sprich die Baudrate kann je nach Belastung ein wenig schwanken. Um dies zu verhindern habe ich in der /boot/config.txt folgende Zeile eingetragen:
dtoverlay=pi3-miniuart-bt dadurch habe ich zwar keine interne Bluetooth Schnittstelle mehr aber das ganze läuft sehr viel stabiler.

Allerdings kommt es immer noch zu abbrüchen. Gibt es eine Möglichkeit, sobald es zu solch einem Abbruch kommt, damit das Script neu gestartet wird? mit diesem Skript überwache ich nämlich die Temperatur meines Gewächshauses. Wenn mal ein Wert fehlt ist es nicht so schlimm, da die Werte allerdings grafisch dargestellt werden, sollte sich das Script sich wieder neu starten. Hat jemand eine Idee?

vielen Dank im voraus

Code: Alles auswählen

#!/usr/bin/python3
import serial
import time
ser = serial.Serial("/dev/ttyAMA0")
ser.baudrate = 9600
def serial():
    while True:
        try:
            daten = ser.readline()
            print(daten.decode('utf8'))
        except:     
            print("Irgendwas lief schief")
            break;

serial()


Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

ja - in dem du es über eine systemd Service Unit startest. Dort kannst du eine Direktive hinterlegen, dass das Skript bei einem Crash automatisch neu gestartet wird.

Je nach dem, wie oft du die Daten abfragst macht es ggf. mehr Sinn, dass Skript periodisch als systemd Timer Unit ausführen zu lassen anstatt in einer Endlosschleife.

Zum Skript: das nackte `try... except` solltest du verbessern - Fehler fängt man gezielt ab. Aktuell fängst du alle Fehler ab (inkl. Programmierfehler), was beim Debugging ziemlich störend sein kann.

Gruß, noisefloor
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

Das habe ich jetzt nicht verstanden 🤔Hättest du mir da einen guten Link, damit ich mich in dieser Hinsicht einarbeiten kann?
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Systemd ist ein umfangreicheres Thema. Die Tutorials bei DigitalOcean sind wohl nicht schlecht. Einstieg: https://www.digitalocean.com/community/ ... he-journal

Wie Unit-Dateien aufgebaut sind: https://www.digitalocean.com/community/ ... unit-files
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

ohje, hat nicht jemand ein Beispiel?
es gibt unzählige Beipiele im Netz, was ein skript machen soll, wenn es einen ghewissen Pfd nicht gibt.
Aber ich hab kein Beispiel gefunden, wie das Skript bei einem Absturz neu startet
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Es gibt sicher auch unter Linux Möglichkeiten den Rückgabewert in einem Shellskript auszulesen, wieso verwendest du das nicht?
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@erdmulch: Warum löst Du das nicht *in* dem Programm? Du brichst das ja ab wenn irgend eine Ausnahme kommt. Das dann neu zu ”starten” kannst Du doch auch *im* Programm lösen.

Zum Programm selbst: Du importierst das `serial`-Modul und definierst dann eine `serial()`-Funktion. Also bedeutet der Name `serial` zwei ziemlich unterschiedliche Sachen auf Modulebene, je nach dem wo man gerade in der Abarbeitung des Codes ist. Das ist nicht schön, da verwirrend. Und wird ausserdem zum Problem wenn man den neustart im Skript lösen möchte, denn nachdem die `serial()`-Funktion definiert ist, kann man nicht mehr ans `serial`-Modul heran kommen um eine neue Verbindung aufzubauen.

`serial()` ist auch ein schlechter Name für eine Funktion, denn Funktionsnamen sollten beschreiben was die Funktion tut. `serial` ist keine Tätigkeit.

Das die `serial()`-Funktion einfach so magisch auf `ser` zugreift ist auch nicht schön. Funktionen und Methoden sollten alles ausser Konstanten als Argumente übergeben bekommen. Dann lassen sich Abhängigkeiten leicht erkennen und der Code ist auch leichter testbar und Funktionen/Methoden lassen sich auch leichter wiederverwenden oder in andere Module verschieben. Bei dem Beispiel sehe ich auch keinen Grund warum `ser` nicht *in* der Funktion definiert werden könnte.

Das Semikolon bei ``break`` ist überflüssig.

Wenn man das ``try``/``except`` um die Schleife legt, wird auch das ``break`` selbst überflüssig.

Die Serielle Verbindung solle explizit wieder geschlossen werden. `Serial`-Objekte sind Kontextmanager, also kann man dafür die ``with``-Anweisung verwenden.

Zusätzlich sind `Serial`-Objekte wie Dateien über Zeilen iterierbar. Die ``while``-Schleife kann man also durch eine ``for``-Schleife ersetzen.

Ich lande dann ungefähr bei so etwas:

Code: Alles auswählen

#!/usr/bin/env python3
import time

from serial import Serial


def main():
    while True:
        try:
            with Serial('/dev/ttyAMA0') as connection:
                for line in connection:
                    print(line.decode('utf8'))
        except Exception as error:
            # 
            # TODO Eigentlich möchte man hier den kompletten
            #   Traceback ausgeben um die Fehlersuche nicht zu
            #   erschweren.  Das `logging`-Modul bietet sich hier
            #   eher an als `print()`.
            # 
            print('Irgendwas lief schief:', error)
            time.sleep(5)


if __name__ == '__main__':
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Aber ich hab kein Beispiel gefunden, wie das Skript bei einem Absturz neu startet
In der Man-Page von systemd Service Units ist das auch alles beschrieben. Musst du halt nur ein bisschen lesen. Da sich systemd voraussichtlich noch ein bisschen im Linux-Umfeld halten wird, schadet das so wie so nicht, wenn man sich mal damit beschäftigt hat.

Brauchbare deutschsprachige Links für systemd Service Units:
https://wiki.ubuntuusers.de/systemd/Service_Units/
https://wiki.ubuntuusers.de/Howto/syste ... _Beispiel/
Gilt so auch für Raspbian, nicht nur für Ubuntu.

Gruß, noisefloor
Antworten