Pi 3B+ Überwachung Temperatur/Luftfeuchtigkeit mit 2x DHT22 + CPU-Temp an ThingSpeak scheitert

L I V E Stammtisch ab 20:30 Uhr im Chat
  • Guten Morgen.

    Ich bin neu hier und habe noch nicht so viel Erfahrung mit Python.

    Ein Ergebnis meiner wochenlangen Recherche habe ich diesem Post als Datei angehangen.

    Mein Wunsch:

    - Temperatur/Luftfeuchtigkeit mit 2 Temperatursensoren (DHT22) für Umgebungstemperatur und im Pi-Gehäuse ermitteln

    - Temperatur der internen CPU-Temperatur (über vcgencmd measure_temp) ermitteln

    - von einem anderen Ort mittels ThingSpeak alle 3 Temperaturen+Luftfeuchtigkeit überwachen

    Meine aktuelle Situation:

    die Ermittlung der Temperaturen/Luftfeuchtigkeit der beiden DHT22-Sensoren und der Übermittlung an ThingSpeak funktioniert einwandfrei

    die Übertragung der CPU-Temperatur funktioniert derzeit nicht :helpnew:

    -> Hier benötige ich Hilfe, da ich noch keine Lösung gefunden habe, wie ich die Funktion/Scriptcode (vcgencmd measure_temp) ohne Fehlermeldung in meine Parameterübergabe "response = channel.update({'field5': cputemp)}" an ThingSpeak einbinden kann.

    Wie im py-Script zu erkennen ist, bekomme ich entweder über das Script "def get_cpu_temperature()" die Fehlermeldung "IndentationError: unexpected indent" oder über den Parameter "cputemp = os.popen('vcgencmd measure_temp')" die Fehlermeldung "SyntaxError: invalid syntax".

    -> Sicher habe ich irgendwo einen Denkfehler oder Verständnisfehler von Python, vielleicht könnt Ihr mir helfen, würde mich riesig freuen.

    --> habe auch keine andere Lösung im Forum sowie Google gefunden ;(

    P.S.: Damit das Script aktuell wenigstens die Werte von den beiden DHT22-Sensoren an ThingSpeak überträgt, habe ich die Sache mit der CPU-Temp. in der py-Datei im Anhang mit # auskommentiert.

  • Pi 3B+ Überwachung Temperatur/Luftfeuchtigkeit mit 2x DHT22 + CPU-Temp an ThingSpeak scheitert? Schau mal ob du hier fündig wirst!

  • Hallo,

    bitte stelle das Skript direkt mittels des Code-Button in das Forum, dann kann es jeder gleich sehen. Hier erstmal dein Skript:

    'os' verwendet man nicht mehr, das wurde durch 'subprocess' abgelöst. Schau dir in diesem Zusammenhang mal 'subprocess.run' an. Ich weis es nicht auswendig, aber damit wird es ungefähr so gehen:

    cpu_temperature = subprocess.run(['vcgencmd measure_temp'], check=True)

    Allgemein schreibt man in Python KONSTANTEN in Großbuchstaben, Variablen und Funktionen klein_mit_unterstrich. Normalerweise hat ein Python-Programm noch eine 'main'-Funktion in der der Ablauf des Hauptprogramms bestimmt wird. Und was auch noch wichtig wäre, benutze bitte keine Abkürzungen oder durchnummerierte Namen. Wenn du sinnvolle Namen verwendest ist es viel einfach der den Code zu verstehen. Wenn du durchnummerierte Namen benötigst, dann lässt sich das meistens über die Verwendung einer Liste oder einer anderen passenden Datenstruktur lösen. Kommentare sollten erklären wieso der Code etwas macht. Was er macht kann man meist aus den Codezeilen schon lesen. Aber in den Anfängen kommentiere ich auch immer alles um selbst den Überblick zu behalten.

    Grüße

    Dennis

    🎧 With the music execution and the talk of revolution, it bleeds in me and it goes 🎧

  • Das Argument check bei subprocess.run ist was anderes. Das prüft, ob ein Programm mit dem Fehlercode 0 beendet worden ist und wenn das nicht der Fall ist, wird ein CalledProcessError ausgelöst und der Rückgabewert von subprocess.run ist eine Instanz von CompletedProcess.

    Um die Ausgabe von stdout als Text zu speichern, muss man subprocess.run ein anderes Argument übergeben:

    Code
    proc = subprocess.run(["ls", "-l"], capture_output=True, encoding="utf8")
    print(proc.stdout.upper())

    Da es hier um das Umwandeln in einen float geht, kann man das encoding auch weglassen.

    float() kann auch mit bytes umgehen, sofern der Inhalt eine gültige Gleitkommazahl ist.

    Code
    import subprocess
    
    
    def get_cpu_temperature():
        proc = subprocess.run(['vcgencmd', 'measure_temp'], capture_output=True)
        return float(temp.replace(b"temp=", b"").replace(b"'C\n", b""))
  • Hallo @DeaD_EyE ,

    ich habe gar nicht an den Rückgabewert gedacht :blush: Ich wollte eigentlich mit 'check' nur sicherstellen, dass der Befehl erfolgreich ausgeführt worden ist. Danke für die Richtigstellung :)

    Grüße

    Dennis

    🎧 With the music execution and the talk of revolution, it bleeds in me and it goes 🎧

  • Guten Morgen und kurze Rückmeldung.

    Habe leider erst jetzt wieder etwas Zeit gehabt das Obige auszuprobieren.

    Leider bekomme ich weiterhin Syntax-Fehler, habe aber auch schon einen weiteren Ansatz zur Lösung gefunden.

    -> Daher werde ich bei Gelingen den Code in den nächsten Tagen hier Posten.

    Bis dahin.

    habe einen Raspberry Pi 3B+, Raspbian 10 (buster) / blutiger Raspberry Pi/Python-Anfänger :helpnew:

  • Kann man die CPU Temperatur nicht auch mit gpiozero auslesen?

    Python
    from gpiozero import CPUTemperature
    from signal import pause
    
    cpu = CPUTemperature()
    
    print(f"CPU Temperatur: {cpu.temperature}")
    
    pause()

    Unter 17.1.3 kann man das noch Mal nach lesen.

  • Kann man machen.

    Wenn man in den Code schaut, sieht es recht ähnlich aus:

    Code
        @property
        def temperature(self):
            """
            Returns the current CPU temperature in degrees celsius.
            """
            with io.open(self.sensor_file, 'r') as f:
                return float(f.read().strip()) / 1000

    Folgende Datei wird gelesen:

    Code
    sensor_file='/sys/class/thermal/thermal_zone0/temp'

    Falls es das gleiche Ergebnis ist, wie von vcgencmd ist, würde ich lieber das nutzen.

    Der Unterschied besteht darin, dass man ein Programm startet, dass einem dann die cpu_temperatur als Text zurückliefert.

    /sys/class/thermal/thermal_zone0/temp wird vom Kernel beschrieben. D.h. um dort drauf zuzugreifen, braucht man kein Programm starten. Man liest dann einfach nur die durch den Kernel vorbereitete Arbeit.

    Die Klasse hat noch die Funktion, dass man einen minimalen und maximalen Wert festlegen kann, aus dem dann der Offset und die Messbereich berechnet wird.

    Falls gpiozero eh eingesetzt wird, kann man sich das alles sparen und einfach das Modul einfach nutzen.

    Wenn man kein gpio benötigt, kann man die kleine Funktion auch selbst implementieren. Dann spart man sich eine Abhängigkeit.

  • Hallo und gute Neuigkeiten, nach neuem Anlauf funktioniert es jetzt super.

    Zugleich habe ich das Script mit weiteren Funktionen (CPU-Temp, CPU-Auslastung, Meldung von Übertragungsfehlern) noch ausgebaut. ^^

    Zur besseren Seiten-Übersicht habe ich die Scripte in Spoiler gesetzt.

    Ich hoffe, dass das so ok ist.

    Auch mögen Programmierexperten in den Scripten die Durchnummerierung von Konstanten nicht, sondern genaue Bezeichnungen.

    Dies gilt auch für die Kommentierungen.

    Mir hilft es für meine Orientierung und Übersicht aber so besser. ;)


    Script: Verarbeitung (send_thingspeak.py)

    "xxx"-Werte mit eigenen Zugangsdaten ersetzen

    Spoiler anzeigen

    #!/usr/bin/env python3

    import thingspeak

    import time

    import Adafruit_DHT # Sensoren initialisieren

    from gpiozero import CPUTemperature # CPU-Werte initialiseren

    import psutil # CPU-Auslastung initialisieren


    channel_id = xxxxx # ThingSpeak-Kanal

    write_key = 'xxxxxxx' # ThingSpeak write-key

    read_key = 'xxxxxxx' # ThingSpeak read-key

    pin1 = 12 # Gehaeusetemperatur

    pin2 = 16 # Aussentemperatur

    sensor1 = Adafruit_DHT.DHT22

    sensor2 = Adafruit_DHT.DHT22

    cputemp = CPUTemperature()

    cpuusage = psutil.cpu_percent(interval=0.5)

    textuebertragungsfehler = ' + Daten nicht uebertragen'

    datumuebertragungsfehler = time.strftime("%Y.%m.%d %H:%M:%S")


    # Verarbeitung aller Werte, Sendung an ThingSpeak

    def measure(channel):

    try:

    humidity1, temperature1 = Adafruit_DHT.read_retry(sensor1, pin1)

    humidity2, temperature2 = Adafruit_DHT.read_retry(sensor2, pin2)

    # Senden neuer Werte an ThingSpeak

    response = channel.update({'field1': round(temperature1, 0), 'field2': round(humidity1, 0), 'field3': round(temperature2, 0), 'field4': round(humidity2, 0), 'field5': round(cputemp.temperature, 0), 'field6': round(cpuusage, 0)})

    # Abrufen vorhandener Werte von ThingSpeak

    # read = channel.get({})

    # print("Read:", read)

    except:

    print(datumuebertragungsfehler + textuebertragungsfehler)

    if __name__ == "__main__":

    channel = thingspeak.Channel(id=channel_id, write_key=write_key, api_key=read_key)

    while True:

    measure(channel)

    # Senden neuer Werte wegen free account > 15 Sek. moeglich, standard 3600

    time.sleep(3600)


    Script: Start (start.sh)

    - P1 zur Vorbeitung für weitere Scripts (P2, P3, ...) für den Autostart genutzt

    Spoiler anzeigen

    #!/bin/bash

    python /home/pi/Adafruit_Python_DHT/Adafruit_DHT/send_thingspeak.py &

    P1=$!

    wait $P1

    Script: Autostart-Ordner (start.desktop)

    - Pfad im Buster-Image: \etc\xdg\autostart

    Spoiler anzeigen

    [Desktop Entry]

    Type=Application

    Name=Start

    Comment=Start für Temp

    NoDisplay=false

    Exec=sudo sh /home/pi/Adafruit_Python_DHT/Adafruit_DHT/start.sh

    habe einen Raspberry Pi 3B+, Raspbian 10 (buster) / blutiger Raspberry Pi/Python-Anfänger :helpnew:

    • Offizieller Beitrag

    Zur besseren Seiten-Übersicht habe ich die Scripte in Spoiler gesetzt.

    Besser wären Code-Boxen (), weil da die Einrückungen erhalten bleiben. ;)


    #!/bin/bash

    python /home/pi/Adaf

    Verwende hier python3 statt python, da das Sript sonst mit Python 2 aufgerufen werden würde.

    Exec=sudo sh /home/pi/Ad

    Ist sudo wirklich nötig für das Skript? Wenn nicht, dann lass das weg!

    - Der Weg zur Erkenntnis: Wie frage ich nach Hilfe? | Zur Erinnerung: Forenregeln | Quatsch und Tratsch: Plauderecke -

    Einmal editiert, zuletzt von hyle (27. März 2021 um 10:48) aus folgendem Grund: Ein Beitrag von hyle mit diesem Beitrag zusammengefügt.

  • Hallo,

    die ersten drei Kommentare sind falsch. Es wird nichts initialisiert, sondern es werden Bibliotheken importiert.

    Konstanten schreibt man GANZ_GROSS. Wenn du sprechende Namen wählst, müsstest du 'pin1' nicht mit '#Gehaeusetemperatur' kommentieren.

    Auf dieser Ebene werden auch nur Konstanten definiert, hier sollte kein Code stehen.

    Dein except' verschluckt den eigentlichen Fehler und wirft stattdessen einen Fehler aus, der nicht mehr wie das Datum aussagt und etwas Text. Funktioniert das mit dem '+' ?

    Das muss man nicht alles so einzeln zusammen basteln. Dafür gibt es z.B. f-Strings.

    Ein Python-Programm hat normalerweise eine Funktion 'main' in der der Hauptprogrammablauf gesteuert wird.

    Ungetestet:

    Grüße

    Dennis

    🎧 With the music execution and the talk of revolution, it bleeds in me and it goes 🎧

  • Hallo.

    Vielen Dank für die vielen Hinweise und weitere Optimierung meiner Scripte. Werde diese erneut ausprobieren und mich hier wieder melden.

    Schönen Abend.

    habe einen Raspberry Pi 3B+, Raspbian 10 (buster) / blutiger Raspberry Pi/Python-Anfänger :helpnew:

  • kurze Info zum Stand:

    Ich hänge leider immer noch an einem anderen Thema mit meinem Raspberry Pi 3B+, Raspbian 10 (Buster) und Erstellung einer WLan-Bridge wlan0 auf wlan1 (OHNE eth0) fest (in der Suche immer nur unpassendes mit Stretch und eth0 gefunden). ;(

    Daher ist das Thema der Überschrift aktuell sehr zu kurz gekommen. Ich melde mich aber auch jeden Fall wieder, wenn es bei mir wieder in den Fokus rückt. :bussi2:

    Ein schönes Wochenende.

    habe einen Raspberry Pi 3B+, Raspbian 10 (buster) / blutiger Raspberry Pi/Python-Anfänger :helpnew:

Jetzt mitmachen!

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