Python, Relais, Temperaturregelung

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
wusa
User
Beiträge: 40
Registriert: Dienstag 18. Februar 2014, 11:08

Hallo Zusammen,

ich stehe momentan komplett auf dem Schlauch.

Ich frage einen DS18B20 Sensor ab und möchte damit Temperaturgesteuert eine Relais schalten.
Ich kann den Sensor abfragen und auch das Relais schalten.
Sobald ich aber die Abfrag erweitere komme ich durcheinander.

Ich möchte, dass ab einem bestimmen Schwellenwert das Relais geschaltet wird. An diesem Relais hängen 2 Lüfter.
Sobald der Schwellenwert wieder unterschritten ist, soll das Relais wieder geschaltet werden und die Lüfter sollen ausgehen.

Was ich nicht möchte, dass immer wieder das Relais geschaltet wird, obwohl es nicht benötigt wird.
Es soll quasi ein "Merker" gesetzt werden, damit nur bei "ein" oder bei "aus" geschaltet wird.

Code: Alles auswählen

#!/usr/bin/python3

import time
import RPi.GPIO as GPIO

a = ("/sys/bus/w1/devices/28-0000067cc099/w1_slave") # Sensor DS18B20
schwellwert = 22
luefter = "an"

GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT)
GPIO.output(11, GPIO.LOW)
schleife = True

def sensorauslesen():
    try:
            sen1 = open(a)
            tfile1 = sen1.read()
            sen1.close()
            tempdata = tfile1.split("\n")[1].split(" ")[9]
            temp1 = float(tempdata[2:])
            temp1 = temp1 / 1000
            temp1 = round(temp1,2)
            temp1 = float(temp1)
            print(temp1)
            abfrage()
    except Exception as e:
            print ("Sensor 1 Fehler!",e)
            abfrage()


def abfrage():
    #print(temp1)
    if temp1 >= schwellwert and luefter == "an":
        print("Luefter laeuft bereits - Temp immer noch zu hoch")
        pass
    elif temp1 >= schwellwert and luefter == "aus":
        luefter = "an"
        GPIO.output(11, GPIO.LOW)
    elif temp1 < schwellwert and luefter == "an":
        GPIO.output(11, GPIO.HIGH)
        luefter = "aus"
    elif temp1 < schwellwert and luefter == "aus":
        print("Temp i.O.")
        pass

    time.sleep(5)

sensorauslesen()
Jetzt habe ich allerdings 2 Probleme:
- Der "Merker" wird immer wieder überschrieben, sodass nicht der letzte Wert hinterlegt ist
- Bei der IF ELIF Abfrage bin ich mir nicht sicher, ob diese an der richtigen Stelle ist. Ich habe extra "print" Befehle eingebaut, diese werden aber nicht ausgegeben.

Danke für die Hilfe
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

im Moment kann der Wert für `luefter`aber gar nicht mehr als 1x überschrieben werden, weil dein gezeigter Code genau 1x läuft.

Anstatt `luefer`einen String zuzuweisen, solltest du lieber mit Wahrheitswerten arbeiten, also z.b. `luefer_laeuft=False` (oder eben `True`).
`a` ist kein braucbaren Namen für eine Variable. Aussagekrätige Namen sind deutlich besser.
Bei der IF ELIF Abfrage bin ich mir nicht sicher, ob diese an der richtigen Stelle ist. Ich habe extra "print" Befehle eingebaut, diese werden aber nicht ausgegeben.
Da der gezeigte Code nur 1x ausgeführt wird, kann auch nur ein `print` ausgeführt werden...

Und `Schleife=True` wird definiert, aber nicht benutzt...

Gruß, noisefloor
wusa
User
Beiträge: 40
Registriert: Dienstag 18. Februar 2014, 11:08

Ich habe am Ende auch folgendes getestest:

Code: Alles auswählen

while(schleife == True):
    sensorauslesen()
    time.sleep(2)

Deswegen, ist die Deklaration von "schleife=True" noch vorhanden.
Auch wenn ich eine Schleife am Ende einbaue, greift die IF ELIF Abfrage nicht.

Bezüglich der Bezeichnung, da weiß ich das 'a' nicht besonder schlau ist. Ich werde das noch ändern.

Das mit den Wahrheitswerten für "luefter" werde ich versuchen umzusetzen.
Die frage ist allerdings, ob ich mir mit jedem Schleifendurchlauf nicht wieder die Variable überschreibe, so wie ich diese am Anfang deklariert habe?
luefter = "an" ?
bzw
luefter_lauft = True?
Zuletzt geändert von wusa am Dienstag 12. Dezember 2017, 12:44, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du hast diverse Probleme in deinem Code, aber eine der groessten ist konzeptioneller Natur: so wie du vorgehst bekommst du ein munteres Relaisgeklacker selbst im besten Fall, denn wenn die Temperatur *gerade* ueber dem Schwellwert ist, faengst du an zu kuehlen, und dann faellt die Temperatur (durch die Kuehlung, oder nur durch Rauschen im Sensor) und schon geht sie wieder aus. Und das wiederholt sich dann....

Fuer so etwas benutzt man darum *zwei* Temperaturen, und programmiert eine "Hysterese". Also eine obere Temperatur, bei welcher die Luefter angehen. Und eine untere Temperatur (zb zwei Grad niedriger), bei der sie ausgehen.

Code: Alles auswählen

UPPER = 20
LOWER = 18

luefter_an = False
while True:
     temp = read_temperature()
     if luefter_an and temp < LOWER:
           luefter_an = False
           relais(False)
     if luefter_aus and temp > UPPER:
           luefter_an = False
           relais(True)
     time.sleep(.1)
wusa
User
Beiträge: 40
Registriert: Dienstag 18. Februar 2014, 11:08

Code: Alles auswählen

#!/usr/bin/python3

import time
import RPi.GPIO as GPIO

a = ("/sys/bus/w1/devices/28-0000067cc099/w1_slave") # temp1 Umgebung

UPPER = 23
LOWER = 20

luefter_an = False


GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT)

def sensorauslesen():
    try:
            sen1 = open(a)
            tfile1 = sen1.read()
            sen1.close()
            tempdata = tfile1.split("\n")[1].split(" ")[9]
            temp1 = float(tempdata[2:])
            temp1 = temp1 / 1000
            temp1 = round(temp1,2)
            temp1 = float(temp1)
            return(temp1)
    except Exception as e:
            print ("Sensor 1 Fehler!",e)



while True:
     temp = sensorauslesen()
     print(temp)
     if luefter_an == True and temp < LOWER:
           luefter_an = False
           GPIO.output(11, GPIO.HIGH)
           print("aus")
     if luefter_an == False and temp > UPPER:
           luefter_an = True
           GPIO.output(11, GPIO.LOW)
           print("an")
     time.sleep(5)

Ich habe jetzt das ganze umgebaut. Jetzt ist aber anscheinend wieder das Problem dass die IF Abfrage nicht greift.
Hier habe ich extra einen "print" Befehl eingebaut, dass ich sehe wie weit alles funktioniert.
Es wird keiner der beiden "print" Befehle ausgegeben.
Ich bin auch mit der "while" noch nicht 100%ig zufrieden.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@wusa: GPIO ist ein Modul, sollte deshalb klein geschrieben werden: `import RPi.GPIO as gpio`. `a` ist immer noch ein schlechter Name für einen Dateinamen. Eingerückt wird immer mit 4 Leerzeichen pro Ebene und nicht mal 5 und mal 6. `sen1`, `tfile1` und `temp1` sind kryptische Abkürzungen. Gewöhn Dir gleich an, sprechende Namen zu verwenden, dann liest sich der Code viel einfacher und ist verständlicher. Dass man Zahlen runden muß, ist höchst selten sinnvoll, Zeile 25 und 26 können ersatzlos entfallen. `return` ist keine Funktion, die Klammern gehören also weg. Falls eine Exception auftritt, liefert die Funktion None als Rückgabewert. Das führt in Python3 bei der größer- kleiner- Prüfung zu einem weiteren Fehler, der nicht mehr abgefangen wird. Fehlerbehandlung sollte nur dort durchgeführt werden, wo ein sinnvolles Weiterarbeiten im Fehlerfall möglich ist. Was gibt denn die print-Zeile aus? Ist die Temperatur richtig und >23 und trotzdem wird der Ausgang nicht geschaltet? Oder wie drückt sich das nicht-Funktionieren aus?
wusa
User
Beiträge: 40
Registriert: Dienstag 18. Februar 2014, 11:08

Code: Alles auswählen


#!/usr/bin/python3

import time
import RPi.GPIO as gpio

netzwerkschrank = ("/sys/bus/w1/devices/28-0000067cc099/w1_slave") # Temp Netzwerkschrank

UPPER = 23
LOWER = 20

luefter_an = False


gpio.setmode(gpio.BOARD)
gpio.setup(11, gpio.OUT)
gpio.setwarnings(False)

def sensorauslesen():
    try:
            sensor = open(netzwerkschrank)
            sensordata = sensor.read()
            sensor.close()
            tempdata = sensordata.split("\n")[1].split(" ")[9]
            temp_netzwerkschrank = float(tempdata[2:])
            temp_netzwerkschrank = temp_netzwerkschrank / 1000
#            temp1 = round(temp1,2)
#            temp1 = float(temp1)
#            print(temp1)
            return temp_netzwerkschrank
    except Exception as e:
            print ("Sensor 1 Fehler!",e)



while True:
     temp = sensorauslesen()
     print(temp)
     if luefter_an == True and temp < LOWER:
           luefter_an = False
           gpio.output(11, gpio.HIGH)
           print("aus")
     if luefter_an == False and temp > UPPER:
           luefter_an = True
           gpio.output(11, gpio.LOW)
           print("an")
     time.sleep(5)

Ich habe jetzt hoffentlich alle Punkt umgebaut.

Das Script läuft ohne Fehlermeldung durch. Die Ausgabe ist wie folgt:
21.812
21.812
21.812
Das ist die Temperatur, die der Sensor zurückliefert.

Innerhalb der IF Abfrage sind 2 print Befehle eingebaut. Keine der beiden Prints wird ausgegeben.

Ob das Relais schaltet oder nicht kann ich leider nicht sagen, da ich nicht vor Ort bin.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Keine der beiden Prints wird ausgegeben.
Ist ja auch richtig so, da bei 21.182 keine der beiden Bedingungen erfüllt ist :-)

Gruß, noisefloor
wusa
User
Beiträge: 40
Registriert: Dienstag 18. Februar 2014, 11:08

Ou Mann..... :shock:

Manchmal sieht man den Wald vor lauter Bäumen nicht...
Wenn ich das richtig sehe, dann muss ich ganz am Anfang das Relais anziehen lassen oder nicht, da ich sonst zwischen den Werten keinen definierten Zustand habe?

Vielen Dank für die ganze Hilfe!
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Wenn ich das richtig sehe, dann muss ich ganz am Anfang das Relais anziehen lassen oder nicht, da ich sonst zwischen den Werten keinen definierten Zustand habe?
Richtig, aktuell kennt dein Programm den Zustand nicht, was ungeünstig ist.

Gruß, noisefloor
wusa
User
Beiträge: 40
Registriert: Dienstag 18. Februar 2014, 11:08

Ich bin jetzt am überlegen das ganze nicht über eine Schleife sondern alle 15 Min über einen Cronjob laufen zu lassen.
Hier würde ich dann einfach die Schleife rausnehmen.

Problem sehe ich dabei, dass ich auch keinen definierten Zustand habe.
Ich kann zwar am Anfang des Scripts einen definierten Zustand einbauen. Quasi dass dass das Relais "aus" ist.

Dann läuft das restlich Script durch und merkt, dass die Temperatur zu hoch ist und schaltet das Relais.

Wenn jetzt die 15 Min vergangen sind, kommt der nächste Durchlauf des Cronjobs und schaltet erstmal das Relais wieder aus um dann vielleicht beim restlichen Script das Relais wieder zu schalten...

Ich hoffe es kommt verständlich rüber, wie ich das ganze meine.

Wie könnte ich soetwas über einen Cronjob abfangen?

Über eine externe Datei, die ich beschreibe oder gibt es da etwas schlaueres?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Schlauer ist, keinen cronjob zu nehmen. Das einzige was der bringt ist Ausfallsicherheit. Die kann man aber auch zb mit einer systemd Unit bekommen, oder supervisord. Und spart sich fragilen externen Zustand dessen schreibzyklen die sd Karte belasten und zb gegen korrupte Daten abgesichert werden müssen.
wusa
User
Beiträge: 40
Registriert: Dienstag 18. Februar 2014, 11:08

Gut.
Warum ich eigentlich drauf gekommen bin. Ich betreibe den Pi Headless.
Verbinde mich nur per SSH auf den Pi.
Jetzt kann ich natürlich das Python Script starten mit
"sudo python3 datei.py &"
So wird es im Hintergrund ausgeführt, und ich kann weiterhin mit der selben Session arbeiten.

Verlasse ich aber die SSH Session, bricht mir auch das Python Script ab.

Wie kann ich das umgehen?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Habe ich doch schon geschrieben. systemd unit, supervisord sind zwei moeglichkeiten, die auch bei einem Absturz des Skripts wieder einen Neustart ausloesen.

one-shot Alternativen sind @reboot-Eintraege in der crontab, oder rc.local Eintraege.

Aber das Thema "Skripte beim hochfahren des Rasperry PI starten" und "Skripte am leben halten" sind auch durchaus schon an 1-2 Stellen im Internet besprochen worden.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@wusa: Du startest mit
[codebox=bash file=Unbenannt.sh]sudo nohup python3 datei.py &[/code]
dann überlebt das Skript auch das Ausloggen.
wusa
User
Beiträge: 40
Registriert: Dienstag 18. Februar 2014, 11:08

__deets__ hat geschrieben:Habe ich doch schon geschrieben. systemd unit, supervisord sind zwei moeglichkeiten, die auch bei einem Absturz des Skripts wieder einen Neustart ausloesen.
Danke nochmals. Hatte das beim ersten Beitrag falsch verstanden.
Ich werde mich da direkt mal einlesen.
Antworten