Skript Ausführung nach 14 Tagen plötzlich super langsam

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
wmauss
User
Beiträge: 8
Registriert: Samstag 12. September 2015, 10:40

Hallo Zusammen,

Ich habe für den Raspberry ein Python Skript geschrieben, dass zeitgesteuert jeden Tag morgens einen Linearantrieb steuert, der am Frühbeet eines Schilkrötengeheges ein Tor bis zu einer durch einen Endschalter definierten Position auf- und abends wieder zu fährt.
Das Skript funktionierte 14 Tage lang klaglos, wie das Log file bestätigt. Gestern Abend bemerkte ich zufällig, dass die Ausführung ca. 7 Minuten verzögert stattfand und heute morgen fuhr das Tor auch 50 Minuten nach dem eingestellten Zeitpunkt nicht mehr auf.
Ich habe daraufhin in diesem Fehlerzustand folgendes geprüft:
1. Einloggen mittels SSH Konsole über WLAN: Funktionierte heute Morgen (im Fehlerzustand), gestern Abend jedoch nicht.
2. Systemzeit: Stimmte genau mit meiner Armbanduhr überein.
3. CPU Auslastung: Im Mittel wenige Prozent.
4. CPU Temperatur: 35°C.
5. Speicherverbrauch: Ca. 10%.
6. Log file des Python Skriptes: Hier konnte ich am Zeitstempel der einzelnen Prozess Schritte sehen, dass die Ausführung jedes einzelnen Schrittes gestern Abend bereits extrem verlangsamt war und anstelle von ms jetzt z.T. Minuten brauchte. Heute morgen war kein Eintrag mehr zu sehen. Ich hänge eine verkürzte Version an, mit dem ersten, einem weiteren Log von Vorgestern und dem letzten (verlangsamten) von Samstagabend. Man erkennt, dass sich keine schleichende Verlangsamung eingestellt hat.
Ich verwende den RPi B+ (single core) unter Raspbian Stretch mit Python 3.6.0 und folgenden Maßnahmen für einen Dauerbetrieb:
• Swapping ist deaktiviert,
• 2,5A Netzteil mit kurzem Anschlusskabel (Linearantrieb über separates 12V Netzteil versorgt)
• Log files /var/log/ werden auf USB Stick geschrieben.
• HW Watchdog aktiviert, jedoch nur auf OS freezes konfiguriert (Standardkonfig.)
• Kühlkörper auf SoC und Pwr. Mgt. Chip.

Nach einem reboot fuhr das Tor erwartungsgemäss auf.
Es scheint auf den ersten Blick kein Problem mit dem OS oder der Stromversorgung vorgelegen zu haben oder gibt es hier gegenteilige Meinungen? Ohne das näher belegen zu können habe ich den schedule Befehl im Verdacht. Ich würde als nächstes die Funktion mit dem schedule Befehl in der while 1 Schleife anstatt sekündlich in einem 30 sek. Intervall durchlaufen lassen, um die Häufigkeit der Ausführung des schedule Befehls zu reduzieren. Ist das sinnvoll?
Gibt es weitere Ideen was ich tun könnte um der Ursache auf die Schliche zu kommen?

Ich bin Python oder allgemein Programmieranfänger, benötige daher vermutlich etwas Kontext.

Im Voraus vielen Dank für Eure Tipps und viele Grüße

Werner

Das Skript:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
from datetime import datetime
import RPi.GPIO as GPIO
import schedule
import time
import logging

# Dieses Skript fährt das Tor bei Ausführung auf.
# GPIO Konfiguration

# RPi.GPIO Layout verwenden (wie Pin-Nummern)
GPIO.setmode(GPIO.BOARD)

# Alle Relais durch High setzen der entsprechenden GPIOs ausschalten.
# Four relais card:
FR_IN1: int = 15
FR_IN2: int = 13
FR_IN3: int = 11
FR_IN4: int = 7
GPIO.setup(FR_IN1, GPIO.OUT)
GPIO.setup(FR_IN2, GPIO.OUT)
GPIO.setup(FR_IN3, GPIO.OUT)
GPIO.setup(FR_IN4, GPIO.OUT)
GPIO.output(FR_IN1, GPIO.HIGH)
GPIO.output(FR_IN2, GPIO.HIGH)
GPIO.output(FR_IN3, GPIO.HIGH)
GPIO.output(FR_IN4, GPIO.HIGH)

# Two relais card:
TR_IN1: int = 16
TR_IN2: int = 18
GPIO.setup(TR_IN1, GPIO.OUT)
GPIO.setup(TR_IN2, GPIO.OUT)
GPIO.output(TR_IN1, GPIO.HIGH)
GPIO.output(TR_IN2, GPIO.HIGH)

# Geschaltete 230V Versorgung f. 12V Netzteil: Pin 16 (GPIO #4) auf Output setzen
AC230V_12V: int = 16
GPIO.setup(AC230V_12V, GPIO.OUT)

# Tor Endschalter f. Zustand "Geschlossen": Pin 33 (GPIO 13), auf Input setzen
# Achtung: Ursprünglicher GPIO 10 (Pin 19) wahrscheinlich durch Überspg. zerstört. Hängt noch parallel mit an GPIO13
End_swtch_closed: int = 33
GPIO.setup(End_swtch_closed, GPIO.IN)
# Tor Endschalter f. Zustand "Offen": Pin 37 (GPIO 26), auf Input setzen
# Achtung: Ursprünglicher GPIO 9 (Pin 21) wahrscheinlich durch Überspg. zerstört. Hängt noch parallel mit an GPIO26
End_swtch_open: int = 37
GPIO.setup(End_swtch_open, GPIO.IN)

# H-Brücke f. Linearmotor: IN1: Pin 12 (GPIO #18), IN2: Pin 26 (GPIO #7) auf Output setzen
H_brdg_EN1: int = 12
H_brdg_EN2: int = 26
GPIO.setup(H_brdg_EN1, GPIO.OUT)
GPIO.setup(H_brdg_EN2, GPIO.OUT)


def gate_linear_drive_off(self):
    """Motor über H-Brücke ausschalten, kurz darauf 230V für 12V Netzteil ausschalten"""
    # Motor ausschalten.
    GPIO.output(H_brdg_EN1, GPIO.LOW)
    GPIO.output(H_brdg_EN2, GPIO.LOW)
    # 12V Versorgung f. Linearantrieb abschalten.
    time.sleep(1)
    # Relais sind Low aktiv
    GPIO.output(AC230V_12V, GPIO.HIGH)


def end_pos_open(self):
    """Hall sensor has detected end position, write log entry, call gate power off"""
    logging.info("end_pos_open: Hallgeber hat *Offen* Endlage erkannt")
    # Motor ausschalten.
    GPIO.output(H_brdg_EN1, GPIO.LOW)
    GPIO.output(H_brdg_EN2, GPIO.LOW)
    logging.info("end_pos_open: Motor wurde von H-Brücke abgeschaltet")
    # 12V Versorgung f. Linearantrieb abschalten.
    time.sleep(1)
    # Relais sind Low aktiv
    GPIO.output(AC230V_12V, GPIO.HIGH)
    logging.info("end_pos_open: Netzspannung für 12V Netzteil abgeschaltet")


def end_pos_closed(self):
    """Hall sensor has detected end position, write log entry, call gate power off"""
    logging.info("end_pos_closed: Hallgeber hat *Zu* Endlage erkannt")
    # Motor ausschalten.
    GPIO.output(H_brdg_EN1, GPIO.LOW)
    GPIO.output(H_brdg_EN2, GPIO.LOW)
    logging.info("end_pos_closed: Motor wurde von H-Brücke abgeschaltet")
    # 12V Versorgung f. Linearantrieb abschalten.
    time.sleep(1)
    # Relais sind Low aktiv
    GPIO.output(AC230V_12V, GPIO.HIGH)
    logging.info("end_pos_closed: Netzspannung für 12V Netzteil abgeschaltet")


def gate_open():
    """Ansteuern des Linearantriebes zum auffahren des Törchens"""
    # 1. 12V Versorgung f. Linearantrieb einschalten
    logging.info("----------- gate_open: Tor Öffnungsvorgang eingeleitet -----------")
    GPIO.output(AC230V_12V, GPIO.LOW)
    logging.info("gate_open: Netzspannung an 12V Netzteil eingeschaltet")
    time.sleep(2)
    # 2. Prüfen ob Tor nicht bereits offen ist. Näherungsschalter ist high bei Annäherung#
    if GPIO.input(End_swtch_open) == GPIO.LOW:
        logging.info("gate_open: Prüfung Torstatus vor Öffnungsvorgang ergab: Tor ist nicht bis Endposition offen")
        # Interrupt konfigurieren: Wenn Endschalter für offene Torposition anspricht, dann Motor ausschalten
        GPIO.add_event_detect(End_swtch_open, GPIO.RISING, callback=end_pos_open)
        logging.info("gate_open: Interrupt durch Hallgeber in Position Offen konfiguriert")
        # 3. Wenn Tor noch nicht offen, Motor in Öffnungsrichtung einschalten.
        GPIO.output(H_brdg_EN2, GPIO.LOW)
        GPIO.output(H_brdg_EN1, GPIO.HIGH)
        logging.info("gate_open: Motor wurde durch H-Brücke gestartet, Richtung Position Auf")
        time.sleep(20)
        GPIO.remove_event_detect(End_swtch_open)
        logging.info("gate_open: Interrupt End_swtch_open wurde gelöscht")
    gate_linear_drive_off("1")
    logging.info("----------- gate_open: Funktion wird verlassen ------------")

def gate_close():
    """Ansteuern des Linearantriebes zum zufahren des Törchens"""
    logging.info("----------- gate_close: Tor Schließvorgang eingeleitet -----------")
    # 1. 12V Versorgung f. Linearantrieb einschalten #
    GPIO.output(AC230V_12V, GPIO.LOW)
    logging.info("gate_close: Netzspannung an 12V Netzteil eingeschaltet")
    time.sleep(2)
    # 2. Prüfen ob Tor nicht bereits geschlossen ist. Näherungsschaltersignal ist low, wenn Törchen zu
    if GPIO.input(End_swtch_closed) == GPIO.LOW:
        logging.info("gate_close: Prüfung Torstatus vor Schließvorgang ergab: Tor ist nicht bis Endposition geschlossen")
        # Interrupt konfigurieren: Wenn Endschalter für geschlossene Torposition anspricht, dann Motor ausschalten
        GPIO.add_event_detect(End_swtch_closed, GPIO.RISING, callback=end_pos_closed)
        logging.info("gate_close: Interrupt durch Hallgeber in Position Zu konfiguriert")
        # 3. Wenn Tor noch nicht geschlossen, Motor in Schliessrichtung einschalten. #
        GPIO.output(H_brdg_EN1, GPIO.LOW)
        GPIO.output(H_brdg_EN2, GPIO.HIGH)
        logging.info("gate_close: Motor wurde durch H-Brücke gestartet, Richtung Position Zu")
        time.sleep(20)
        GPIO.remove_event_detect(End_swtch_closed)
        logging.info("gate_close: Interrupt End_swtch_closed wurde gelöscht")
    gate_linear_drive_off("1")
    logging.info("----------- gate_close: Funktion wird verlassen ------------")


def gate_check_on_reboot(oeffnungszeit, schliesszeit):
    """Falls ein Reboot während der Torfahrzeit erfolgte kann das nicht in Endposition stehende Tor zu- oder aufgefahren werden"""
    logging.info("---------- gate_check_on_reboot: Gestartet. Passt Torstatus nach Neustart zur Tageszeit? ----------")
    akt_zeit = datetime.today()
    jahr = akt_zeit.year
    monat = akt_zeit.month
    tag = akt_zeit.day
    soll_zeit = datetime.strptime(schliesszeit, '%H:%M')
    soll_zeit_zu = soll_zeit.replace(year=jahr, month=monat, day=tag)
    soll_zeit = datetime.strptime(oeffnungszeit, '%H:%M')
    soll_zeit_auf = soll_zeit.replace(year=jahr, month=monat, day=tag)

    if (akt_zeit < soll_zeit_auf) or (akt_zeit > soll_zeit_zu):
        logging.info("gate_check_on_reboot: gate_close() wird aufgerufen um zu prüfen ob Tor geschlossen ist")
        gate_close()
    elif (akt_zeit > soll_zeit_auf) and (akt_zeit < soll_zeit_zu):
        logging.info("gate_check_on_reboot: gate_open() wird aufgerufen um zu prüfen ob Tor offen ist")
        gate_open()
    logging.info("----------- gate_check_on_reboot: Funktion wird verlassen -----------")


def main():
    logging.basicConfig(
        filename="/var/log/tccu.log",
        level=logging.DEBUG,
        style="{",
        format="{asctime} [{levelname:8}] {message}",
        datefmt="%Y-%m-%d %H:%M:%S")
    logging.info("------------ Skript gate_open_close.py gestartet ------------")

    # Tor Öffnungs- und Schließzeiten
    oeffnungszeit = "09:00"
    schliesszeit = "19:45"

    schedule.every().day.at(oeffnungszeit).do(gate_open)
    schedule.every().day.at(schliesszeit).do(gate_close)

    gate_check_on_reboot(oeffnungszeit, schliesszeit)

    try:
        while 1:
            schedule.run_pending()
            time.sleep(1)

    except KeyboardInterrupt:
        GPIO.cleanup()
        logging.info("main: keyboardinterrupt ist erfolgt, exiting")
        logging.info("GPIOs wurden zurückgesetzt")

    except:
        GPIO.cleanup()
        logging.info("main: Eine Ausnahme ist aufgetreten, exiting")
        logging.info("GPIOs wurden zurückgesetzt")
if __name__ == '__main__':
    main()
Die Log Datei (auszugsweise):

Code: Alles auswählen

Log Einträge nach erstmaligem Start des Skriptes am 20.08.2019: 
2019-08-20 19:45:00 [INFO    ] Running job Every 1 day at 19:45:00 do gate_close() (last run: [never], next run: 2019-08-20 19:45:00)
2019-08-20 19:45:00 [INFO    ] ----------- gate_close: Tor Schließvorgang eingeleitet -----------
2019-08-20 19:45:00 [INFO    ] gate_close: Netzspannung an 12V Netzteil eingeschaltet
2019-08-20 19:45:02 [INFO    ] gate_close: Prüfung Torstatus vor Schließvorgang ergab: Tor ist nicht bis Endposition geschlossen
2019-08-20 19:45:02 [INFO    ] gate_close: Interrupt durch Hallgeber in Position Zu konfiguriert
2019-08-20 19:45:02 [INFO    ] gate_close: Motor wurde durch H-Brücke gestartet, Richtung Position Zu
2019-08-20 19:45:14 [INFO    ] end_pos_closed: Hallgeber hat *Zu* Endlage erkannt
2019-08-20 19:45:14 [INFO    ] end_pos_closed: Motor wurde von H-Brücke abgeschaltet
2019-08-20 19:45:16 [INFO    ] end_pos_closed: Netzspannung für 12V Netzteil abgeschaltet
2019-08-20 19:45:22 [INFO    ] gate_close: Interrupt End_swtch_closed wurde gelöscht
2019-08-20 19:45:23 [INFO    ] ----------- gate_close: Funktion wird verlassen ------------
2019-08-21 09:00:00 [INFO    ] Running job Every 1 day at 09:00:00 do gate_open() (last run: [never], next run: 2019-08-21 09:00:00)
2019-08-21 09:00:00 [INFO    ] ----------- gate_open: Tor Öffnungsvorgang eingeleitet -----------
2019-08-21 09:00:00 [INFO    ] gate_open: Netzspannung an 12V Netzteil eingeschaltet
2019-08-21 09:00:02 [INFO    ] gate_open: Prüfung Torstatus vor Öffnungsvorgang ergab: Tor ist nicht bis Endposition offen
2019-08-21 09:00:02 [INFO    ] gate_open: Interrupt durch Hallgeber in Position Offen konfiguriert
2019-08-21 09:00:02 [INFO    ] gate_open: Motor wurde durch H-Brücke gestartet, Richtung Position Auf
2019-08-21 09:00:15 [INFO    ] end_pos_open: Hallgeber hat *Offen* Endlage erkannt
2019-08-21 09:00:15 [INFO    ] end_pos_open: Motor wurde von H-Brücke abgeschaltet
2019-08-21 09:00:16 [INFO    ] end_pos_open: Netzspannung für 12V Netzteil abgeschaltet
2019-08-21 09:00:22 [INFO    ] gate_open: Interrupt End_swtch_open wurde gelöscht
2019-08-21 09:00:23 [INFO    ] ----------- gate_open: Funktion wird verlassen ------------

Letzte Log Einträge *vor* verlangsamter Ausführung: 
2019-09-06 19:45:00 [INFO    ] Running job Every 1 day at 19:45:00 do gate_close() (last run: 2019-09-05 19:45:23, next run: 2019-09-06 19:45:00)
2019-09-06 19:45:00 [INFO    ] ----------- gate_close: Tor Schließvorgang eingeleitet -----------
2019-09-06 19:45:00 [INFO    ] gate_close: Netzspannung an 12V Netzteil eingeschaltet
2019-09-06 19:45:02 [INFO    ] gate_close: Prüfung Torstatus vor Schließvorgang ergab: Tor ist nicht bis Endposition geschlossen
2019-09-06 19:45:02 [INFO    ] gate_close: Interrupt durch Hallgeber in Position Zu konfiguriert
2019-09-06 19:45:02 [INFO    ] gate_close: Motor wurde durch H-Brücke gestartet, Richtung Position Zu
2019-09-06 19:45:15 [INFO    ] end_pos_closed: Hallgeber hat *Zu* Endlage erkannt
2019-09-06 19:45:15 [INFO    ] end_pos_closed: Motor wurde von H-Brücke abgeschaltet
2019-09-06 19:45:16 [INFO    ] end_pos_closed: Netzspannung für 12V Netzteil abgeschaltet
2019-09-06 19:45:22 [INFO    ] gate_close: Interrupt End_swtch_closed wurde gelöscht
2019-09-06 19:45:23 [INFO    ] ----------- gate_close: Funktion wird verlassen ------------
2019-09-07 09:00:00 [INFO    ] Running job Every 1 day at 09:00:00 do gate_open() (last run: 2019-09-06 09:00:24, next run: 2019-09-07 09:00:00)
2019-09-07 09:00:00 [INFO    ] ----------- gate_open: Tor Öffnungsvorgang eingeleitet -----------
2019-09-07 09:00:00 [INFO    ] gate_open: Netzspannung an 12V Netzteil eingeschaltet
2019-09-07 09:00:02 [INFO    ] gate_open: Prüfung Torstatus vor Öffnungsvorgang ergab: Tor ist nicht bis Endposition offen
2019-09-07 09:00:02 [INFO    ] gate_open: Interrupt durch Hallgeber in Position Offen konfiguriert
2019-09-07 09:00:02 [INFO    ] gate_open: Motor wurde durch H-Brücke gestartet, Richtung Position Auf
2019-09-07 09:00:16 [INFO    ] end_pos_open: Hallgeber hat *Offen* Endlage erkannt
2019-09-07 09:00:16 [INFO    ] end_pos_open: Motor wurde von H-Brücke abgeschaltet
2019-09-07 09:00:17 [INFO    ] end_pos_open: Netzspannung für 12V Netzteil abgeschaltet
2019-09-07 09:00:22 [INFO    ] gate_open: Interrupt End_swtch_open wurde gelöscht
2019-09-07 09:00:23 [INFO    ] ----------- gate_open: Funktion wird verlassen ------------

Log Eintrag bei letzter stark verlangsamter Ausführung: 
2019-09-07 19:45:31 [INFO    ] Running job Every 1 day at 19:45:00 do gate_close() (last run: 2019-09-06 19:45:23, next run: 2019-09-07 19:45:00)
2019-09-07 19:47:57 [INFO    ] ----------- gate_close: Tor Schließvorgang eingeleitet -----------
2019-09-07 19:49:06 [INFO    ] gate_close: Netzspannung an 12V Netzteil eingeschaltet
2019-09-07 19:50:38 [INFO    ] gate_close: Prüfung Torstatus vor Schließvorgang ergab: Tor ist nicht bis Endposition geschlossen
2019-09-07 19:52:05 [INFO    ] gate_close: Interrupt durch Hallgeber in Position Zu konfiguriert
2019-09-07 19:54:31 [INFO    ] gate_close: Motor wurde durch H-Brücke gestartet, Richtung Position Zu
2019-09-07 19:55:02 [INFO    ] end_pos_closed: Hallgeber hat *Zu* Endlage erkannt
2019-09-07 19:58:16 [INFO    ] end_pos_closed: Motor wurde von H-Brücke abgeschaltet
2019-09-07 19:59:22 [INFO    ] gate_close: Interrupt End_swtch_closed wurde gelöscht
2019-09-07 20:02:23 [INFO    ] end_pos_closed: Netzspannung für 12V Netzteil abgeschaltet
Benutzeravatar
sparrow
User
Beiträge: 4165
Registriert: Freitag 17. April 2009, 10:28

Grundsätzlich würde ich kein Programm dauernd warten lassen, dass es 2x am Tag ausgeführt wird. Es vebraucht Ressourcen und ist offensichtlich unzuverlässig.
Betriebssysteme haben ihre eigenen Dienste um dafür zu sorgen, dass Befehle zu bestimmten Zeiten ausgeführt werden. Unter Linux wäre das der cron daemon.
wmauss
User
Beiträge: 8
Registriert: Samstag 12. September 2015, 10:40

Danke für die rasche Antwort. Ich möchte im nächsten Schritt die Öffnungs- und Schließzeiten von den Sonnenauf- und untergangszeiten abhängig machen, d.h. die Zeiten ändern sich täglich.
Ist hier noch nicht berücksichtigt aber deshalb habe ich für cron keine Möglichkeit gesehen.
Außerdem wird der Raspberry zukünftig auch die Heizung und die Wärmelampe steuern und dafür wird er permanent messen und regeln/steuern müssen. Die Torsteuerung läuft da quasi nebenbei mit.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich habe schlechte Erfahrungen mit RPI.GPIO gemacht, gerade im Langzeitbetrieb. Darum würde ich das rausschmeißen & durch pigpio ersetzen.

Oder noch besser einen ESP32 mit NTP und RTC ausstatten. Der läuft deutlich robuster. Und wenn es sein soll auch mit microPython.
wmauss
User
Beiträge: 8
Registriert: Samstag 12. September 2015, 10:40

@__deets__
Danke für den Hinweis auf pigpio, bisher waren mir Probleme mit RPI.GPIO nicht bewusst.
Das werde ich angehen und dann mal schauen wo ich lande mit der Dauerbetriebsstabilität. Umstieg auf eine andere HW Plattform ist mir erstmal zu aufwändig, zumal ich Zusatz HW entwickelt habe und der Konnektor auf der Leiterplatte an die RPi Stiftleiste angepasst ist.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@wmauss: ein RasPi ist für stabile Steuerungsaufgaben ungeeignet. Das ist eher ein Spielzeug. Selbst große Desktop-PCs sind für den 24/7-Betrieb nicht ausgelegt. Für solche Aufgaben nimmt man Microkontroller, wie z.B. den von __deets__ bereits angesprochenen ESP32.

Zum Code: in Python gibt es eine Namenskonvention, dass Module, Funktionen und Variablennamen komplett klein geschrieben werden, Konstanten dagegen KOMPLETT_GROSS.
Zu Beginn stimmt die Schreibweise noch, bei `End_swtch_closed` weichst Du dann aber von der Großschreibung ab. Benutze keine Abkürzungen. Auch ein Microkontroller kommt heutzutage mit dem zusätzlichen `i` bei switch zurecht. I's scheinen wirklich teuer zu sein, bei `brdg` fehlt auch eins.

Dieses unsinnige `: int` kannst Du überall weglöschen. Sowohl der Compiler als auch der menschliche Leser weiß bei einer Zahl 12, dass es sich um ein int handelt.

Alle GPIO-Aufrufe am Anfang gehören in eine Funktion, die ich üblicherweise `initialize` oder ähnlich nenne. `setup` kann viel mehr, so dass sie viele Zeilen zu einer kürzen lassen

Code: Alles auswählen

GPIO.setup([FR_IN1, FR_IN2, FR_IN3, FR_IN4], GPIO.OUT, initial=GPIO.HIGH)
`gate_linear_drive_off`, `end_pos_open` und `end_pos_closed` tun exakt das selbe. Ebenso `gate_open` und `gate_close`. Wenn Du gerne unterschiedliche Namen dafür haben willst, weise den allgemeinen Funktionen einfach andere Namen zu.

Code: Alles auswählen

end_pos_open = gate_linear_drive_off
In `gate_check_on_reboot` hast Du etwas viele Variablennamen definiert, die Klammern um die Bedingungen sind überflüssig. Die zweite Bedingung kann kürzer als `soll_zeit_auf < akt_zeit < soll_zeit_zu` geschrieben werden und der erste if-Block wäre dann ein else-Block.

In `main` wäre die 1 bei while besser `True`. Nackte excepts sollte man nicht benutzen, wenn man nicht die ursprüngliche Fehlermeldung ausgibt. Mach aus `except` ein `finally` dann hast Du auch keine Code-Dopplung mehr für cleanup.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wmauss: Schreibst Du auch Logs vom Kernel? Hast Du Dir die ``dmesg``-Ausgaben angeschaut? Wenn der Rechner insgesamt und nicht nur das Python-Programm langsam war/nicht reagiert hat, dann klingt das ja nach etwas Ausserhalb des Programms. Hast Du irgendendwelche Cronjobs die viel auf dem Hintergrundspeicher machen? Automatische Sicherheitsupdates? Den Dienst der für eine aktuelle DB für ``locate`` sorgt? Backups?

Neben den Kernel-Logs, würde ich bei so etwas wahrscheinlich regelmässig Speicher- und CPU-Verbrauch und IO-Auslastung protokollieren, mit den Top 10 Prozessen wenn bestimmte Grenzen überschritten werden.

Noch ergänzend zu Sirius3's Anmerkungen zu den Typannotationen: *wenn* man die verwendet, sollte man auch unbedingt regelmässig mit einem passenden Werkzeug testen ob der Code und die Typannotationen stimmen/passen, denn sonst sind die Typannotationen nicht nur überflüssig, sondern eventuell sogar verwirrend für den Leser wenn sie nicht passen.

Es gibt keine Klasse(n) aber einige unbenutzte `self`-Argumente in Funktionen‽
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
wmauss
User
Beiträge: 8
Registriert: Samstag 12. September 2015, 10:40

@ sirius3 und __blackjack__
Vielen Dank für Eure Hinweise! Ich arbeite die gerade ein, bin zunächst noch an den Hinweisen von sirius3

@sirius3:
Ich hatte die GPIO Aufrufe am Anfang zuvor bereits probeweise in eine Funktion gesammelt, habe dann allerdings von der IDE (Pycharm) haufenweise Fehlermeldungen der Art "Unresolved Reference" erhalten für all die Konstantennamen in den anderen Funktionen.
Wo muss ich denn die gpio_init Funktion aufrufen um das zu vermeiden? Als erstes in main() gehts nicht und auch sonst habe ich keine Möglichkeit gefunden die Funktion aufzurufen und so die Fehlermeldungen zu vermeiden.

Zu Deinem Kommentar
`gate_linear_drive_off`, `end_pos_open` und `end_pos_closed` tun exakt das selbe. Ebenso `gate_open` und `gate_close`. Wenn Du gerne unterschiedliche Namen dafür haben willst, weise den allgemeinen Funktionen einfach andere Namen zu.
Ja, tun exakt dasselbe ausser dass jeweils ein anderer Log Datei Eintrag geschrieben wird. Weil ich keine Möglichkeit gefunden habe bspw. in

Code: Alles auswählen

GPIO.add_event_detect(END_SWITCH_CLOSED, GPIO.RISING, callback=end_pos_closed)
für die callback Funktion einen Parameter mit dem Log Text zu übergeben hatte ich das so gelöst. Geht das auch anders?

Hier habe ich leider nicht verstanden, was du damit meinst:
und der erste if-Block wäre dann ein else-Block.


Skript sieht mit den Änderungen jetzt so aus.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
from datetime import datetime
import RPi.GPIO as GPIO
import schedule
import time
import logging


def gpio_init():
    """GPIOs konfigurieren"""

    # RPi.GPIO Layout verwenden (wie Pin-Nummern)
    GPIO.setmode(GPIO.BOARD)

    # Alle Relais durch High setzen der entsprechenden GPIOs ausschalten.
    # Four relais card:
    FR_IN1 = 15
    FR_IN2 = 13
    FR_IN3 = 11
    FR_IN4 = 7
    # Two relais card:
    TR_IN1 = 16
    TR_IN2 = 18
    # Geschaltete 230V Versorgung f. 12V Netzteil: Pin 16 (GPIO #4) auf Output setzen
    AC230V_12V = 16
    GPIO.setup([FR_IN1, FR_IN2, FR_IN3, FR_IN4, TR_IN1, TR_IN2, AC230V_12V], GPIO.OUT, initial=GPIO.HIGH)

    # Tor Endschalter f. Zustand "Geschlossen": Pin 33 (GPIO 13), auf Input setzen
    # Achtung: Ursprünglicher GPIO 10 (Pin 19) wahrscheinlich durch Überspg. zerstört. Hängt noch parallel mit an GPIO13
    END_SWITCH_CLOSED = 33
    # Tor Endschalter f. Zustand "Offen": Pin 37 (GPIO 26), auf Input setzen
    # Achtung: Ursprünglicher GPIO 9 (Pin 21) wahrscheinlich durch Überspg. zerstört. Hängt noch parallel mit an GPIO26
    END_SWITCH_OPEN = 37
    GPIO.setup([END_SWITCH_CLOSED, END_SWITCH_OPEN], GPIO.IN)

    # H-Brücke f. Linearmotor: IN1: Pin 12 (GPIO #18), IN2: Pin 26 (GPIO #7) auf Output setzen
    H_BRIDGE_EN1 = 12
    H_BRIDGE_EN2 = 26
    GPIO.setup([H_BRIDGE_EN1, H_BRIDGE_EN2], GPIO.OUT, initial=GPIO.LOW)


def gate_linear_drive_off(self):
    """Motor über H-Brücke ausschalten, kurz darauf 230V für 12V Netzteil ausschalten"""
    # Motor ausschalten.
    GPIO.output(H_BRIDGE_EN1, GPIO.LOW)
    GPIO.output(H_BRIDGE_EN2, GPIO.LOW)
    # 12V Versorgung f. Linearantrieb abschalten.
    time.sleep(1)
    # Relais sind Low aktiv
    GPIO.output(AC230V_12V, GPIO.HIGH)


def end_pos_open(self):
    """Hall sensor has detected end position, write log entry, call gate power off"""
    logging.info("end_pos_open: Hallgeber hat *Offen* Endlage erkannt")
    # Motor ausschalten.
    GPIO.output(H_BRIDGE_EN1, GPIO.LOW)
    GPIO.output(H_BRIDGE_EN2, GPIO.LOW)
    logging.info("end_pos_open: Motor wurde von H-Brücke abgeschaltet")
    # 12V Versorgung f. Linearantrieb abschalten.
    time.sleep(1)
    # Relais sind Low aktiv
    GPIO.output(AC230V_12V, GPIO.HIGH)
    logging.info("end_pos_open: Netzspannung für 12V Netzteil abgeschaltet")


def end_pos_closed(self):
    """Hall sensor has detected end position, write log entry, call gate power off"""
    logging.info("end_pos_closed: Hallgeber hat *Zu* Endlage erkannt")
    # Motor ausschalten.
    GPIO.output(H_BRIDGE_EN1, GPIO.LOW)
    GPIO.output(H_BRIDGE_EN2, GPIO.LOW)
    logging.info("end_pos_closed: Motor wurde von H-Brücke abgeschaltet")
    # 12V Versorgung f. Linearantrieb abschalten.
    time.sleep(1)
    # Relais sind Low aktiv
    GPIO.output(AC230V_12V, GPIO.HIGH)
    logging.info("end_pos_closed: Netzspannung für 12V Netzteil abgeschaltet")


def gate_open():
    """Ansteuern des Linearantriebes zum auffahren des Törchens"""
    # 1. 12V Versorgung f. Linearantrieb einschalten
    logging.info("----------- gate_open: Tor Öffnungsvorgang eingeleitet -----------")
    GPIO.output(AC230V_12V, GPIO.LOW)
    logging.info("gate_open: Netzspannung an 12V Netzteil eingeschaltet")
    time.sleep(2)
    # 2. Prüfen ob Tor nicht bereits offen ist. Näherungsschalter ist high bei Annäherung#
    if GPIO.input(END_SWITCH_OPEN) == GPIO.LOW:
        logging.info("gate_open: Prüfung Torstatus vor Öffnungsvorgang ergab: Tor ist nicht bis Endposition offen")
        # Interrupt konfigurieren: Wenn Endschalter für offene Torposition anspricht, dann Motor ausschalten
        GPIO.add_event_detect(END_SWITCH_OPEN, GPIO.RISING, callback=end_pos_open)
        logging.info("gate_open: Interrupt in Position Offen durch Hallgeber wurde konfiguriert")
        # 3. Wenn Tor noch nicht offen, Motor in Öffnungsrichtung einschalten.
        GPIO.output(H_BRIDGE_EN2, GPIO.LOW)
        GPIO.output(H_BRIDGE_EN1, GPIO.HIGH)
        logging.info("gate_open: <<< Motor wurde durch H-Brücke gestartet, Richtung Position Auf <<<")
        time.sleep(20)
        GPIO.remove_event_detect(END_SWITCH_OPEN)
        logging.info("gate_open: Interrupt End_swtch_open wurde gelöscht")
    gate_linear_drive_off("1")
    logging.info("----------- gate_open: Funktion wird verlassen ------------")


def gate_close():
    """Ansteuern des Linearantriebes zum zufahren des Törchens"""
    logging.info("----------- gate_close: Tor Schließvorgang eingeleitet -----------")
    # 1. 12V Versorgung f. Linearantrieb einschalten #
    GPIO.output(AC230V_12V, GPIO.LOW)
    logging.info("gate_close: Netzspannung an 12V Netzteil eingeschaltet")
    time.sleep(2)
    # 2. Prüfen ob Tor nicht bereits geschlossen ist. Näherungsschaltersignal ist low, wenn Törchen zu
    if GPIO.input(END_SWITCH_CLOSED) == GPIO.LOW:
        logging.info("gate_close: Prüfung Torstatus vor Schließvorgang ergab: Tor ist nicht bis Endposition geschlossen")
        # Interrupt konfigurieren: Wenn Endschalter für geschlossene Torposition anspricht, dann Motor ausschalten
        GPIO.add_event_detect(END_SWITCH_CLOSED, GPIO.RISING, callback=end_pos_closed)
        logging.info("gate_close: Interrupt durch Hallgeber in Position Zu wurde konfiguriert")
        # 3. Wenn Tor noch nicht geschlossen, Motor in Schliessrichtung einschalten. #
        GPIO.output(H_BRIDGE_EN1, GPIO.LOW)
        GPIO.output(H_BRIDGE_EN2, GPIO.HIGH)
        logging.info("gate_close: >>> Motor wurde durch H-Brücke gestartet, Richtung Position Zu >>>")
        time.sleep(20)
        GPIO.remove_event_detect(END_SWITCH_CLOSED)
        logging.info("gate_close: Interrupt End_swtch_closed wurde gelöscht")
    gate_linear_drive_off("1")
    logging.info("----------- gate_close: Funktion wird verlassen ------------")


def gate_check_on_reboot(oeffnungszeit, schliesszeit):
    """Falls ein Reboot während der Torfahrzeit erfolgte wird das nicht in Endposition stehende Tor zu- oder aufgefahren"""
    logging.info("---------- gate_check_on_reboot: Gestartet. Passt Torstatus nach Neustart zur Tageszeit? ----------")
    akt_zeit = datetime.today()
    jahr = akt_zeit.year
    monat = akt_zeit.month
    tag = akt_zeit.day
    soll_zeit = datetime.strptime(schliesszeit, '%H:%M')
    soll_zeit_zu = soll_zeit.replace(year=jahr, month=monat, day=tag)
    soll_zeit = datetime.strptime(oeffnungszeit, '%H:%M')
    soll_zeit_auf = soll_zeit.replace(year=jahr, month=monat, day=tag)

    if akt_zeit < soll_zeit_auf or akt_zeit > soll_zeit_zu:
        logging.info("gate_check_on_reboot: gate_close() wird aufgerufen um zu prüfen ob Tor geschlossen ist")
        gate_close()
    elif soll_zeit_auf < akt_zeit < soll_zeit_zu:
        logging.info("gate_check_on_reboot: gate_open() wird aufgerufen um zu prüfen ob Tor offen ist")
        gate_open()
    logging.info("----------- gate_check_on_reboot: Funktion wird verlassen -----------")


def main():
    logging.basicConfig(
        filename="/var/log/tccu.log",
        level=logging.DEBUG,
        style="{",
        format="{asctime} [{levelname:8}] {message}",
        datefmt="%Y-%m-%d %H:%M:%S")
    logging.info("------------ Skript gate_open_close.py gestartet ------------")

    gpio_init()

    # Tor Öffnungs- und Schließzeiten
    oeffnungszeit = "09:00"
    schliesszeit = "19:10"

    schedule.every().day.at(oeffnungszeit).do(gate_open)
    schedule.every().day.at(schliesszeit).do(gate_close)

    gate_check_on_reboot(oeffnungszeit, schliesszeit)

    try:
        while true:
            schedule.run_pending()
            time.sleep(30)

    except KeyboardInterrupt:
        logging.info("main: keyboardinterrupt ist erfolgt, exiting")

    finally:
        GPIO.cleanup()
        logging.info("main: Eine Ausnahme ist aufgetreten, exiting")
        logging.info("GPIOs wurden zurückgesetzt")
if __name__ == '__main__':
    main()
Zuletzt geändert von wmauss am Montag 9. September 2019, 15:29, insgesamt 2-mal geändert.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Konstanten müssen außerhalb von `gpio_init` definiert werden.

Bei Callbacks kann man zusätzliche Parameter mit Hilfe von functools.partial übergeben. Schönes Programm würde ich aber schönen Log-Meldungen vorziehen. An einer gate_open-Meldung sieht man ja, dass die nachfolgenden Meldungen sich auf das Öffnen beziehen.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
from datetime import datetime
import RPi.GPIO as GPIO
import schedule
import time
import logging

logger = logging.getLogger(__name__)

# Four relais card:
FR_IN1 = 15
FR_IN2 = 13
FR_IN3 = 11
FR_IN4 = 7
# Two relais card:
TR_IN1 = 16
TR_IN2 = 18
END_SWITCH_CLOSED = 33
END_SWITCH_OPEN = 37
H_BRIDGE_EN1 = 12
H_BRIDGE_EN2 = 26

def gpio_init():
    """GPIOs konfigurieren"""
    # RPi.GPIO Layout verwenden (wie Pin-Nummern)
    GPIO.setmode(GPIO.BOARD)

    # Alle Relais durch High setzen der entsprechenden GPIOs ausschalten.
    # Geschaltete 230V Versorgung f. 12V Netzteil: Pin 16 (GPIO #4) auf Output setzen
    AC230V_12V = 16
    GPIO.setup([FR_IN1, FR_IN2, FR_IN3, FR_IN4, TR_IN1, TR_IN2, AC230V_12V], GPIO.OUT, initial=GPIO.HIGH)

    # Tor Endschalter f. Zustand "Geschlossen": Pin 33 (GPIO 13), auf Input setzen
    # Tor Endschalter f. Zustand "Offen": Pin 37 (GPIO 26), auf Input setzen
    # Achtung: Ursprünglicher GPIO 9/10 (Pin 21/19) wahrscheinlich durch Überspg. zerstört. Hängt noch parallel mit an GPIO26/13
    GPIO.setup([END_SWITCH_OPEN, END_SWITCH_CLOSED], GPIO.IN)

    # H-Brücke f. Linearmotor: IN1: Pin 12 (GPIO #18), IN2: Pin 26 (GPIO #7) auf Output setzen
    GPIO.setup([H_BRIDGE_EN1, H_BRIDGE_EN2], GPIO.OUT)


def gate_linear_drive_off(_=None):
    """Motor über H-Brücke ausschalten, kurz darauf 230V für 12V Netzteil ausschalten"""
    # Motor ausschalten.
    logger.info("Hallgeber hat *Offen* Endlage erkannt")
    GPIO.output(H_BRIDGE_EN1, GPIO.LOW)
    GPIO.output(H_BRIDGE_EN2, GPIO.LOW)
    logger.info("Motor wurde von H-Brücke abgeschaltet")
    # 12V Versorgung f. Linearantrieb abschalten.
    time.sleep(1)
    # Relais sind Low aktiv
    GPIO.output(AC230V_12V, GPIO.HIGH)
    logger.info("Netzspannung für 12V Netzteil abgeschaltet")

def gate_open_close(switch):
    """Ansteuern des Linearantriebes zum auffahren des Törchens"""
    # 1. 12V Versorgung f. Linearantrieb einschalten
    GPIO.output(AC230V_12V, GPIO.LOW)
    logger.info("gate_open: Netzspannung an 12V Netzteil eingeschaltet")
    time.sleep(2)
    # 2. Prüfen ob Tor nicht bereits offen/geschlossen ist. Näherungsschalter ist high bei Annäherung#
    if GPIO.input(switch) == GPIO.LOW:
        logger.info("Prüfung Torstatus ergab: Tor ist nicht an Endposition")
        # Interrupt konfigurieren: Wenn Endschalter für offene Torposition anspricht, dann Motor ausschalten
        GPIO.add_event_detect(switch, GPIO.RISING, callback=gate_linear_drive_off)
        logger.info("Interrupt in Position Offen durch Hallgeber wurde konfiguriert")
        # 3. Wenn Tor noch nicht offen, Motor in Öffnungsrichtung einschalten.
        if switch == END_SWITCH_OPEN:
            GPIO.output(H_BRIDGE_EN2, GPIO.LOW)
            GPIO.output(H_BRIDGE_EN1, GPIO.HIGH)
        else:
            GPIO.output(H_BRIDGE_EN1, GPIO.LOW)
            GPIO.output(H_BRIDGE_EN2, GPIO.HIGH)
        logger.info("<<< Motor wurde durch H-Brücke gestartet <<<")
        time.sleep(20)
        GPIO.remove_event_detect(switch)
        logger.info("Interrupt End_swtch_open wurde gelöscht")
    gate_linear_drive_off()

def gate_open(switch):
    logger.info("----------- gate_open: Tor Öffnungsvorgang eingeleitet -----------")
    gate_open_close(END_SWITCH_OPEN)
    logger.info("----------- gate_open: Funktion wird verlassen ------------")

def gate_close():
    """Ansteuern des Linearantriebes zum zufahren des Törchens"""
    logger.info("----------- gate_close: Tor Schließvorgang eingeleitet -----------")
    gate_open_close(END_SWITCH_CLOSED)
    logger.info("----------- gate_close: Funktion wird verlassen ------------")


def gate_check_on_reboot(oeffnungszeit, schliesszeit):
    """Falls ein Reboot während der Torfahrzeit erfolgte wird das nicht in Endposition stehende Tor zu- oder aufgefahren"""
    logger.info("---------- gate_check_on_reboot: Gestartet. Passt Torstatus nach Neustart zur Tageszeit? ----------")
    akt_zeit = datetime.today()
    soll_zeit_zu = datetime.strptime(schliesszeit, '%H:%M')
    soll_zeit_zu = soll_zeit_zu.replace(year=akt_zeit.year, month=akt_zeit.month, day=akt_zeit.day)
    soll_zeit_auf = datetime.strptime(oeffnungszeit, '%H:%M')
    soll_zeit_auf = soll_zeit_auf.replace(year=akt_zeit.year, month=akt_zeit.month, day=akt_zeit.day)
    if soll_zeit_auf < akt_zeit < soll_zeit_zu:
        logger.info("gate_check_on_reboot: gate_open() wird aufgerufen um zu prüfen ob Tor offen ist")
        gate_open()
    else:
        logger.info("gate_check_on_reboot: gate_close() wird aufgerufen um zu prüfen ob Tor geschlossen ist")
        gate_close()
    logger.info("----------- gate_check_on_reboot: Funktion wird verlassen -----------")


def main():
    logging.basicConfig(
        filename="/var/log/tccu.log",
        level=logging.DEBUG,
        style="{",
        format="{asctime} [{levelname:8}] {message}",
        datefmt="%Y-%m-%d %H:%M:%S")
    logger.info("------------ Skript gate_open_close.py gestartet ------------")
    
    gpio_init()
    
    # Tor Öffnungs- und Schließzeiten
    oeffnungszeit = "09:00"
    schliesszeit = "19:10"

    schedule.every().day.at(oeffnungszeit).do(gate_open)
    schedule.every().day.at(schliesszeit).do(gate_close)

    gate_check_on_reboot(oeffnungszeit, schliesszeit)

    try:
        while True:
            schedule.run_pending()
            time.sleep(30)

    except KeyboardInterrupt:
        logger.info("main: keyboardinterrupt ist erfolgt, exiting")
    finally:
        GPIO.cleanup()
        logger.info("GPIOs wurden zurückgesetzt")

if __name__ == '__main__':
    main()
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

__blackjack__ hat geschrieben: Montag 9. September 2019, 13:21 @wmauss: Schreibst Du auch Logs vom Kernel? Hast Du Dir die ``dmesg``-Ausgaben angeschaut? Wenn der Rechner insgesamt und nicht nur das Python-Programm langsam war/nicht reagiert hat, dann klingt das ja nach etwas Ausserhalb des Programms. Hast Du irgendendwelche Cronjobs die viel auf dem Hintergrundspeicher machen? Automatische Sicherheitsupdates? Den Dienst der für eine aktuelle DB für ``locate`` sorgt? Backups?
Wenn es denn unbedingt der Rapberry Pi bleiben muss, wäre eine weitere Möglichkeit, um noch etwas Perfomance und "Reaktivität" rauszukitzeln, statt Raspbian ein minimaleres Linux zu nehmen, zum Beispiel Alpine Linux oder Archlinux. Insbesondere mit ersterem habe ich auf dem Raspberry Pi sehr gute Erfahrungen gemacht. Beide sind allerdings etwas komplexer in der Einrichtung und im Betrie und Alpine weicht in einigen Punkten deutlich von "Mainstream-Distributionen" ab.
wmauss
User
Beiträge: 8
Registriert: Samstag 12. September 2015, 10:40

@sirius:
Wow! Viel eleganter, herzlichen Dank für die Python Nachhilfe!
Die elseif Sache habe ich jetzt auch verstanden und mit ist klar, was genau Du mit "vielen Variablen" meintest bei der Erzeugung der täglichen Öffnungs- und Schließzeit.

@__blackjack__: Ich verwende Raspbian praktisch unverändert, also von mir nichts Wesentliches zusätzlich konfiguriert. Insbesondere keine cron Jobs, Backups, automatische Sicherheitsupdates oder was Du da mit ``locate´´ meinen könntest, es sei denn, es wäre standardmässig eingestellt. Allerdings habe ich außer Swapping auch nichts deaktiviert.
Folgende Änderungen habe ich gemacht:
https://docdro.id/gMMvVsa
Ich werde mir als nächstes mal die Kernelmeldungen mit dmesg ansehen und ggf. hier posten. Weitere logs wie von Dir vorgeschlagen habe ich nicht erstellt, müßte erstmal herausfinden wie man das überhaupt macht.
Kann sich denn eine Situation, in der der RPI über einige Minuten nicht auf mehrere SSH Loginversuche antwortet von selbst wieder auflösen? Am nächsten Morgen ging der SSH Login ja wieder problemlos, das Skript wurde hingegen gar nicht mehr oder so langsam ausgeführt, dass der einminütige Zeitschlitz verpasst wurde.
Ich kann allerdings tatsächlich bestätigen, dass es diese Situation, in der der RPi nicht auf einen Login Versuch reagiert hat, in den 14 Tagen ein weiteres Mal gegeben hat. Da hatte ich mich allerdings über eine VPN Verbindung zur Fritzbox zuhause auf dem RPi einloggen wollen und das klappte nicht (obwohl der Tunnel zustand kam), am nächsten Tag war dann alles wieder normal.

@ nezzcarth:
Danke für den Hinweis auf die alternativen Images. Ich bin mangels einschlägigem know-how und mangels Zeit leider auf Lösungen angewiesen, für die es im Netz möglichst viel Beispielcode gibt, denn was ich im wesentlichen mache, ist abschreiben/abgucken. Wenn ich da eine eher exotische Distribution nehme, dann habe ich Bedenken ob ich das überhaupt hinkriege.
Wäre es möglich, die im Raspbian enthaltenen nicht benötigten Dienste etc. nach und nach zu deaktivieren um so zu einem schlankeren, stabilerem Image zu kommen?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dein Skript macht so gut wie nichts. Das da die Last anderer Services eine Rolle spielt denke ich eher nicht. Aber natürlich schadet ein Blick auf top/htop nicht. Aber die Distribution zu wechseln halte ich für nicht notwendig.
wmauss
User
Beiträge: 8
Registriert: Samstag 12. September 2015, 10:40

Ich habe mir das Log mit dmesg angeschaut.
Zunächst mal habe ich festgestellt, dass es nur ca. 6 Stunden zurückreichte, also keinen reboot oder gar den Fehlerzeitpunkt am vergangenen Samstag enthielt.
Es sind nur 1-wire Einträge im 30-Sekunden Takt vorhanden:
Auszug:

Code: Alles auswählen

[Mo Sep  9 22:48:24 2019] w1_master_driver w1_bus_master1: Attaching one wire slave 00.85c000000000 crc 07
[Mo Sep  9 22:48:24 2019] w1_master_driver w1_bus_master1: Family 0 for 00.85c000000000.07 is not registered.
[Mo Sep  9 22:49:04 2019] w1_master_driver w1_bus_master1: Attaching one wire slave 00.45c000000000 crc cd
[Mo Sep  9 22:49:04 2019] w1_master_driver w1_bus_master1: Family 0 for 00.45c000000000.cd is not registered.
[Mo Sep  9 22:49:54 2019] w1_master_driver w1_bus_master1: Attaching one wire slave 00.c5c000000000 crc 41
[Mo Sep  9 22:49:54 2019] w1_master_driver w1_bus_master1: Family 0 for 00.c5c000000000.41 is not registered.
[Mo Sep  9 22:50:21 2019] w1_master_driver w1_bus_master1: Attaching one wire slave 00.25c000000000 crc a8
[Mo Sep  9 22:50:21 2019] w1_master_driver w1_bus_master1: Family 0 for 00.25c000000000.a8 is not registered.
[Mo Sep  9 22:51:13 2019] w1_master_driver w1_bus_master1: Attaching one wire slave 00.a5c000000000 crc 24
[Mo Sep  9 22:51:13 2019] w1_master_driver w1_bus_master1: Family 0 for 00.a5c000000000.24 is not registered.
[Mo Sep  9 22:52:29 2019] w1_master_driver w1_bus_master1: Attaching one wire slave 00.65c000000000 crc ee
[Mo Sep  9 22:52:29 2019] w1_master_driver w1_bus_master1: Family 0 for 00.65c000000000.ee is not registered.
[Mo Sep  9 22:53:08 2019] w1_master_driver w1_bus_master1: Attaching one wire slave 00.e5c000000000 crc 62
[Mo Sep  9 22:53:08 2019] w1_master_driver w1_bus_master1: Family 0 for 00.e5c000000000.62 is not registered.
Das hatte mich dann daran erinnert, dass die 1-wire Konfiguration noch fehlte, was ich erledigte, daraufhin war ein reboot nötig.
In der folgenden dmesg Ausgabe konnte ich sehen dass es mit set_pullup ein vermutlich kleineres Problem gibt

Code: Alles auswählen

[Mo Sep  9 23:23:05 2019] Driver for 1-wire Dallas network protocol.
[Mo Sep  9 23:23:05 2019] w1-gpio onewire@28: gpio pin 40, external pullup pin -1, parasitic power 1
[Mo Sep  9 23:23:05 2019] w1_add_master_device: set_pullup requires write_byte or touch_bit, disabling
Desweiteren noch ein anderer Fehler, der mir aktuell nichts sagt:

Code: Alles auswählen

[Mo Sep  9 23:22:58 2019] systemd-fstab-generator[49]: Failed to create mount unit file /run/systemd/generator/var-log.mount, as it already exists. Duplicate entry in /etc/fstab?
Die oben gezeigte 30-sekündige Ausgabe der w1_master_driver... Einträge war jetzt immerhin weg.

Gibt es noch andere logs, die sich anzuschauen lohnen könnten?

@ __deets__, top hatte ich mir angeschaut, als die Skriptausführung hing. Da zeigte sich m.E. nichts Auffälliges, sprich es gab keine Prozesse, die länger als ein, zwei Sekunden niedrige bis mittlere zweistellige CPU Last Prozente erzeugt hatten. htop hatte ich in der Situation nicht verwendet.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wie schon gesagt - ich halte nichts von RPI.GPIO. Also raus damit, oder ggf einfach dein Programm per systemd unit starten, und bei Absturz neu starten lassen. Und dann einmal nachts per kill beenden.
wmauss
User
Beiträge: 8
Registriert: Samstag 12. September 2015, 10:40

Der Austausch RPI.GPIO auf pigpio steht noch auf meiner To-Do Liste. Urlaub ist aber seit Dienstag rum, muss schauen wann ich dazu komme.
Inzwischen habe ich mich etwas mit dem ESP32 beschäftigt und werde ihn wohl in die V2 meiner TCCU (Turtle Compound Control Unit) einbauen.

Nochmals vielen Dank an alle für die wirklich sehr hilfreichen und immer konstruktiven Beiträge!

Werner
pumukel
User
Beiträge: 5
Registriert: Samstag 24. März 2018, 17:32

Hallo wmauss,
habe 3 Raspis im Langzeitbetrieb seit 2 Jahren laufen. Davon 2 ununterbrochen seit 9 Monaten. Dabei wird auch RPI.GPIO genutzt. Probleme mit den Ports oder den Raspis habe ich keine. Ich hatte aber am Anfang auch den Effekt, dass die Raspis nach ca. 2 Wochen langsam wurden. Bei mir war das der Samba-Server für die Datenzugriffe untereinander und zum USB-Stick. Nach Abschaltung des Samba-Servers gab es keine Probleme mehr. Den Datenaustausch mit Stick und den einzelnen Raspis mache ich mit SFTP.
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

__deets__ hat geschrieben: Montag 9. September 2019, 21:59 Aber die Distribution zu wechseln halte ich für nicht notwendig.
Ja, ss kann sehr gut sein, dass du recht hast. Wenn der Raspberry PI als Plattform gesetzt ist, ist das Verwenden eines solchen minimalen Linux aus meiner Sicht aber eine der Stellschrauben, mit der man teilweise noch ein bisschen etwas heraus holen kann. Ich habe leider nie Benchmarks gemacht, insofern sind meine Aussagen nicht belast- oder belegbar, aber sowohl Arch Linux als auch und insb. Alpinelinux fühlten sich im Vergleich zu Raspbian (lite) und gerade auch OpenSuse deutlich "flüssiger" an. Man muss jeweils im Einzelfall überprüfen, ob es etwas bringt und ggf. den Lernaufwand rechtfertigt. Gerade bei Alpinelinux hat man ja wie gesagt die Besonderheit, dass das stark vom Mainstream Linux abweicht (musl statt glibc, openrc statt systemd/sysvinit, busybox für's userland, per default kein presistenter Speicher, etc.).
Antworten