Wettersensor-Daten "richtig" abfragen

  • Hallo,

    ich bin aktuell dabei eine "Wetterstation" mit dem Raspberry Pi 3 + Standard-Hardware (ASH 2200 Sensoren, USB WDE1-2 als Empfänger der Funk-Infos) zu bauen. Ein Stück weit bin ich dem Ansatz hier gefolgt: Feuchtegesteuerte Kellerlüftung und habe mir für das Python-Skript div. Artikel zu dem Thema durchgelesen. Grundsätzlich funktioniert das auch alles so weit, wenn ich es mir im Putty ausgeben lasse. Jetzt will ich das aber nicht in Putty sehen, sondern in eine MariaDB speichern, um es später an einer Web-Oberfläche anzuzeigen.

    Wo ich nun aber ins Stocken gekommen bin ist folgendes: Aktuell läuft das Skript in einer endlosschleife (while (1 == 1)) und wird einmalig aufgerufen. Das finde ich aber nicht wirklich schön. Sollte es einmal, warum auch immer, abbrechen, würde es eben nicht mehr laufen, bis ich es merke. Deshalb würde ich es gerne per Cronjob alle X Minuten starten lassen. Das habe ich auch umgesetzt, dass es alle 5 Minuten gestartet wird.

    Nun ist es aber ja so, dass nicht genau dann, wenn der Cronjob startet, auch Daten gesendet werden. Die Frequenz kann sich ja auch ändern, wenn z.B. die Batterien des Sensors leer sind. Ich müsste also warten, bis ein Datensatz kam und dann das Skript beenden. Da wiederum sehe ich das Problem, wenn kein Datensatz kommt (z.B. weil Batterien leer), dann werden alle 5 Minuten neue Skripte gestartet, von denen keines mehr endet, bis der Sensor sich wieder meldet, um dann x-fach denselben Eintrag in die DB zu schreiben.

    Habt ihr einen Vorschlag / Ideen, wie ich das so umsetzen kann? Klar könnte ich eine while-Schleife laufen lassen die sagt "laufe so lange wie aktuelle - startzeit < 5 Minuten". Schön ist aber anders, wie ich finde. Macht es grundsätzlich für solche Themen in Python Sinn, objektorientiert zu programmieren?

    Vielen Dank und viele Grüße,

    Dirk

  • Hallo Dirk,

    da gibt es mehrere Möglichkeiten.

    Zunächst einmal sollte man einen gewissen Aufwand in eine Programmentwicklung investieren, dass das Programm nicht einfach mal so abstürzt.

    Wenn das aus welchem Grund auch immer nicht gehen sollte, dann musst Du regelmäßig prüfen, ob Dein Programm noch läuft.

    Da würde ich es so machen, dass nicht alle 5 Minuten Dein Programm neu startet (und Du die zuvor gestartete Instanz "abschießen" müsstest) sondern ein anderes Hilfsprogramm, dessen Aufgabe darin besteht, mal eben zu prüfen, ob Dein eigentliches Programm noch "lebt". Wenn ja, beendet sich das Hilfsprogramm sofort wieder. Gibt es Dein eigentliches Programm nicht mehr, ruft startet das Hilfsprogramm Deine Anwendung, bevor es sich dann auch beendet.

    Auf diese Weise läuft Dein eigentliches Programm immer - und das Hilfsprogramm regelmäßig sehr kurzfristig.

    Alle anderen Ideen, die Du noch gebracht hast, funktionieren zwar, ist aber schlechter Stil - wie es Dir auch schon aufgefallen ist.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Hallo Andreas,

    vielen Dank für deine schnelle Antwort. Dann werde ich den Ansatz verfolgen. Ich möchte eh noch Nagios bzw. Icinga 2 (muss mal schauen, was genau) verwenden, das mich dann informiert. Ob ich es dann automatisiert wieder gestartet haben möchte, weiß ich noch nicht. Eine Benachrichtigung würde ja erst mal reichen.

    Wie würdest du denn empfehlen, dass ich mein Wetterstation-Skript starten lasse? Ich habe schon geschaut, wie ich es als "Service" mit /etc/init.d/weather start|stop|status machen kann, aber das hat nicht so wirklich funktioniert. Über die /etc/rc.local, damit es auch immer da ist, sobald ich den Raspberry Pi neu starte?

    Vielen Dank und viele Grüße,

    Dirk

  • Da Du ja meinen Thread referenziert hast, kurz eine Erläuterung, wie ich das gelöst habe: Ich starte in der crontab @reboot ein Skript, das in einer Endlosschleife immer wieder das eigentliche Skript zur Sensorabfrage aufruft. Sollte dieses also aus irgendwelchen Gründen abbrechen, wird es umgehend neu gestartet. Gleichzeitig erfolgt ein Eintrag in eine Logdatei. Das ist sicher nicht 100%ig wasserdicht (u.a. deshalb überwache ich zusätzlich per Icinga2), läuft aber jetzt seit Mai ohne Aussetzer.

  • Hallo Dirk,

    ich würde es so einfach wie möglich halten.

    Wenn über einen Cronjob getestet werden soll, ob Deine Anwendung läuft und ggf. dann gestartet wird, dann kannst Du Deine Anwendung darüber auch initial starten. Also brauchst Du für Deine Anwendung dann noch einen Autostart? Nö, oder?

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Hallo,

    vielen Dank für eure Antworten. Ich habe mich jetzt wieder zu meiner ursprünglichen Variante umorientiert und per Dauerschleife die Daten ausgelesen. Dabei wurden die Daten zunächst pro Auslesen in eine eigene Datei (Datum_Uhrzeit_weather.log) geschrieben. Da das recht zuverlässig zu funktionieren schien, habe ich mich heute rangemacht die Daten in die DB schreiben zu lassen.

    Das funktioniert grundsätzlich auch, nur kann ich das abgeänderte Skript nun nicht mehr per cronjob (wie vorgeschlagen mit @reboot) starten. Ich finde im /var/log/syslog nichts und auch eine /var/log/cron.log existiert erst gar nicht (obwohl das Logging in der Konfiguration aktiviert ist). Könntet ihr vielleicht mal draufschauen, ob euch was auffällt? Von der shell aus kann ich es problemlos starten, die Berechtigungen stehen auf u+x und der Cronjob selbst (der mit der "schreibe in die Datei"-Version noch funktionierte) ist über crontab -e mit dem Benutzer pi angelegt:
    [code=php]#!/usr/bin/env python

    import serial
    import sys
    import os
    import datetime
    import MySQLdb as mdb

    # serial port of USB-WDE1-2
    port = '/dev/ttyUSB0'
    # DB config settings
    host = '**********'
    username = '**********'
    password = '*****************************'
    database = '****************'

    # main
    def main():
    connection = mdb.connect(host, username, password, database)
    # open serial line
    ser = serial.Serial(port, 9600)
    if not ser.isOpen():
    file.write("Unable to open serial port %s" % port)
    sys.exit(1)

    while (1 == 1):
    line = ser.readline()
    line = line.strip()
    line = str(line)
    lineArray = line.split(';')
    connection = mdb.connect('localhost',username, password, database)

    now = datetime.datetime.now()
    currentDateTime = now.strftime("%Y-%m-%d %H:%M:%S")
       
    with connection:
    cursor = connection.cursor()
    query = 'INSERT INTO daily_live_data_temp (sensor_id, datetime, temperature, humidity) VALUES(1,\''+currentDateTime+'\','+lineArray[3].replace(',', '.')+','+lineArray[11].replace(',', '.')+')'
    cursor.execute(query)
    query = 'INSERT INTO daily_live_data_temp (sensor_id, datetime, temperature, humidity) VALUES(2,\''+currentDateTime+'\','+lineArray[4].replace(',', '.')+','+lineArray[12].replace(',', '.')+')'
    cursor.execute(query)

    if __name__ == '__main__':
    main()[/php]

    Der Cronjob ist wie folgt angelegt:
    [code=php]@reboot python /usr/local/share/weatherstation/weatherstation.py[/php]

    Gebe ich den Befehl hinter dem @reboot auf der Shell ein, dann wird er auch ausgeführt und schreibt in meine DB. Reboote ich und rufe dann
    ps ax | grep weatherstation.py
    auf, dann sehe ich nur meine Suchanfrage als Ergebnis.

    Vielen Dank und viele Grüße,

    Dirk

  • Hallo Dirk,


    Der Cronjob ist wie folgt angelegt:

    PHP
    @reboot python /usr/local/share/weatherstation/weatherstation.py[/php]
    
    
    Gebe ich den Befehl hinter dem @reboot auf der Shell ein, dann wird er auch ausgeführt und schreibt in meine DB. [/quote]
    
    
    Gebe bitte vor python auch den Pfad dazu ein. Diesen erhältst Du durch
    [code]which python

    Dann sollte Dein Skript auch beim Reboot gestartet werden.


    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Hallo Andreas,

    vielen Dank für deine schnelle Antwort. Diese hat das Problem aber leider nicht gelöst.

    [code=php]which python[/php]

    liefert mir

    /usr/bin/python

    zurück. Dies habe ich anstelle von python im crontab des pi-Benutzers eingegeben und, nachdem dies alleine auch nicht geholfen hat, auch noch in der .py-Datei (beim Shebang): #!/usr/bin/python

    Ebenfalls keine Besserung, weshalb ich den Shebang auf #!/usr/bin/python3 -u und den crontab auf /usr/bin/python3 geändert habe - ebenfalls ohne Erfolg.

    Grundsätzlich hat der Cronjob aber ja mit einer älteren Version funktioniert. Ich mache es so, dass ich alte Stände damit "versioniere", dass ich sie in meinem Ordner in einen script_backup-Ordner verschiebe, damit ich ggf. wieder darauf zugreifen kann.

    Ein shutdown -h now und anschließender Neustart brachte auch keine Änderung.

    Hat vielleicht noch jemand eine Idee, woran das genau liegen könnte?

    Vielen Dank und viele Grüße,

    Dirk

  • Hallo Dirk,

    Du musst natürlich auch die Python-Version aufrufen, mit der Du auch den Python-Code laufen lassen kanst. Eine andere Python-Version fünktioniert meistens nicht, weil Python 2.x nicht vollkommen kompatibel zu Python 3.x ist.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Hallo Andreas,

    danke. Das sollte aber eher nicht das Problem sein, da ich mit demselben Befehl der auch im crontab steht das Skript auch normal über die Shell starten kann.

    Was mir noch in den Sinn kam: Kann es an der Reihenfolge liegen, in der die Skripte ausgeführt und Dienste gestartet werden? Was, wenn MariaDB zum Zeitpunkt der Skriptausführung noch gar nicht (fertig-)gestartet hat?

    Ich habe dann nach und nach die Maria bzw. MySqlDB-Komponenten aus- und dann wieder einkommentiert. Als alle außer dem import MySqlDB as mdb raus waren ging es, sobald ich die Verbindung zur DB erstellt habe ging es wieder nicht mehr.

    Da das meine Theorie bestätigte, habe ich innerhalb der main()-Methode ein time.sleep(30) an den Start gestellt. Nun funktioniert es.

    Ich werde das Script jetzt peu à peu so umbauen, dass nicht mehr das Pythonskript direkt gestartet wird, sondern ein anderes, dass, wie dasmaul es geschrieben hat, permanent das andere skript aufruft. Dann kann ich auch das DB-Handling dahingehend ändern, dass die Verbindung nur / erst dann aufgebaut wird, wenn sie vorhanden ist.

    Vielen Dank und viele Grüße,

    Dirk

  • Hallo Dirk,


    Was mir noch in den Sinn kam: Kann es an der Reihenfolge liegen, in der die Skripte ausgeführt und Dienste gestartet werden? Was, wenn MariaDB zum Zeitpunkt der Skriptausführung noch gar nicht (fertig-)gestartet hat?


    Richtig, bevor Deine Anwendung startet, muss alles (Dienste, DB etc.), worauf Deine Anwendung Zugriff haben möchte, soweit eingerichtet und gestartet sein.



    Ich werde das Script jetzt peu à peu so umbauen, dass nicht mehr das Pythonskript direkt gestartet wird, sondern ein anderes, dass, wie dasmaul es geschrieben hat, permanent das andere skript aufruft. Dann kann ich auch das DB-Handling dahingehend ändern, dass die Verbindung nur / erst dann aufgebaut wird, wenn sie vorhanden ist.


    Das halte ich persönlich nicht für den besten Weg. Du kannst auch in Deiner Anwendung prüfen, ob die Datenbank "da" ist.

    Der Weg, ein Skript aufzurufen, das ein Skript aufruft, das prüft, ob ein anderes Programm läuft, ist umständlich.

    Statt auf Bash-Ebene einen 30-sekündigen Schlaf einzulegen, würde ich lieber in Deiner Anwenung eine Routine einbauen, die in einer Schleife prüft, ob alle für Dein Python-Skript erforderlichen Ressourcen vorhanden sind, und erst dann die Schleife verlässt und in Deine eigentliche Anwendung gelangt - die ja wohl schon funktionioert.

    Vor ein paar Wochen habe ich einen GPS-Tracker programmiert. In der ersten Schleife wird die Anwensenheit eines GPS-Receivers geprüft. Ist keiner da, erfolgt einmalig eine Warnung. Das Programm bleibt in dieser Schleife, bis ein GPS-Tracker aufgefunden wurde. Erst sobald dieser sendet, werden die empfangenen Daten gelesen und ausgewertet. Würde ich das vorher machen, würde das System auch wieder meckern.
    Würde ich ohne auf GPS-Receiver prüfen und gleich zu lesen versuchen, gäbe es auch eine Fehlermeldung.

    Es kommt also auf die richtige Reihenfolge von Code-Blöcken an, ob ein Programm sauber läuft - oder ob das alles ein wirres Durcheinander gibt.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Hallo Andreas,

    danke für deine Tipps.


    Das halte ich persönlich nicht für den besten Weg. Du kannst auch in Deiner Anwendung prüfen, ob die Datenbank "da" ist.

    Das wäre halt der Weg gewesen, den auch schon "manul" (den ich vorher warum auch immer als "dasmaul" bezeichnet habe, sorry dafür O:-)) geht, also dass bei ihm der Cronjob ein Skript aufruft, das dann wiederum in Endlosschleife läuft und immer daraus das WDE1-2-Ausleseskript aufruft.

    Ich kann auch alles in dasselbe Skript packen, irgendwann wird es halt ziemlich überladen. Ich habe mir auch überlegt eine DB-Klasse zu erstellen, in der ich einige Dinge kapsle, das ganze etwas objektorientierter zu gestalten als "Übung". Oder macht das für ein solches Projekt wenig(er) Sinn?

    Vielen Dank und viele Grüße,

    Dirk

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!