Aquariumsteuerung mit Raspi und Python

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
ReneBe
User
Beiträge: 2
Registriert: Samstag 13. Februar 2021, 19:25

Hallo in die Runde,

ich bin ganz neu hier, auch was das Thema "Python" betrifft, bin ich Autodidakt. Man möge mir nachsehen. Ich habe mir eine kleine Aquariensteuerung gebaut - mittels Raspi und Relaisboard. Dazu habe ich mir ein Python-Script zusammengebastelt, was jetzt wohl das Problem zu sein scheint.

Ich habe es direkt auf dem Raspi in Thonny-Python aus diversen "Schnipseln" zusammengebaut. In Thonny lief es auch zeitweise, wenn ich es über die Kommandozeile gestartet habe, nur sehr kurz und hing sich dann auf.

Ich komm nicht mehr weiter, woran das liegen könnte. Wahrscheinlich schlagt ihr die Hände über dem Kopf zusammen, aber vielleicht hätte ja jemand mal die Zeit, über das Script zu schauen:

Code: Alles auswählen

#!/usr/bin/env python3
"""

*************************** Variablen ******************************

#NanoCube

CO2Cube        = Boolean, Schaltzustand CO2Cube

#Amazonas-Becken

UVLampe        = Boolean, Schaltzustand UVLampe
CO2Pumpe       = Boolean, Schaltzustand CO2Pumpe
CO2Ama         = Boolean, Schaltzustand CO2Ama
Bodenheizer    = Boolean, Schaltzustand Bodenheizer
Stabheizer     = Boolean, Schaltzustand Stabheizer
Fuellpumpe     = Boolean, Schaltzustand Fuellpumpe
Duengerpumpe   = Boolean, Schaltzustand Duengerpumpe
alive          = Boolean, Anzeige, dass Programm läuft


t1           = Einschaltzeit 1 UVLampe
t2           = Ausschaltzeit 1 UVLampe
t3           = Einschaltzeit 2 UVLampe
t4           = Ausschaltzeit 2 UVLampe 
t5           = Einschaltzeit 3 CO2Pumpe
t6           = Ausschaltzeit 3 CO2Pumpe
t7           = Einschaltzeit 1 CO2Cube
t8           = Ausschaltzeit 1 CO2Cube
t9           = Einschaltzeit 2 CO2Ama
t10          = Ausschaltzeit 2 CO2Ama

Duengen      = Zeitpunkt für Tagesduenger
Nachfuellen  = Zeitpunkt für Nachfuellen

Ln           = Fuellstand Normallevel
Ll           = Fuellstand Lowlevel
Lh           = Fuellstand Highlevel

s1           = Dauer Doesierung Tagesduenger in sec
s2           = Dauer Nachfuellen ins sec

Temp1        = Temperatur1 in °C
Temp2        = Temperatur2 in °C

BHL          = Bodenheizer Low (ein)
BHH          = Bodenheizer High (aus)

SHL          = Stabheizer Low (ein)
SHH          = Stabheizer High (aus)

TWH          = Temperatur-Warnlevel High
TWL          = Temperatur-Warnlever Low

************************ Ende Variablen ******************************

"""

# ******************** Importierte Module *****************************

import time
import RPi.GPIO as GPIO
import re
import lcddriver
from time import *
from time import sleep


# ******************* Definieren der GPIOs ***************************


GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(14, GPIO.OUT) # UVLampe
GPIO.setup(15, GPIO.OUT) # CO2Pumpe
GPIO.setup(18, GPIO.OUT) # CO2Cube
GPIO.setup(17, GPIO.OUT) # CO2Ama
#GPIO.setup(24, GPIO.OUT) # Bodenheizer
GPIO.setup(25, GPIO.OUT) # Stabheizer
GPIO.setup(8, GPIO.OUT) # Fuellpumpe
GPIO.setup(7, GPIO.OUT)  # Duengerpumpe
GPIO.setup(5, GPIO.OUT)  # Alive
GPIO.setup(4, GPIO.OUT)  # Temperatur out of range
GPIO.setup(20, GPIO.OUT) # Fuellstand Trigger
GPIO.setup(21, GPIO.IN) # Fuellstand Echo
GPIO_TRIGGER = 20
GPIO_ECHO = 21


#  ****************** Beginn Einstellparameter **************************

# Ein- und Ausschaltzeiten der Lampen

# UVLampe
t1 = "04:00"
t2 = "07:00"
t3 = "13:00"
t4 = "16:00"

# CO2Pumpe
t5 = "11:00"
t6 = "19:00"

# CO2Cube
t7 = "11:00"
t8 = "16:00"

# CO2Ama
t9 = "11:00"
t10 = "18:00"

# Duengerpumpe
s1 = 10
Duengen = "11:00"

# Fuellstand
Ln = 4.0    # Abstand Normal-Level
Ll = -1.0   # Level-Low
Lh = 0.5    # Level-High
s2 = 60     # Maximale Pumpdauer

# Temperatur-Schaltpunkte

# BHL = 22.0  # Bodenheizer Low (ein)
# BHH = 25.0  # Bodenheizer High (aus)

SHL = 23.5  # Stabheizer Low (ein)
SHH = 24.0  # Stabheizer High (aus)

TWH = 24.8  # Warnlevel Temperatur High
TWL = 22.0  # Warnlevel Temperatur Low


# ************************ Ende Einstellparameter *******************************


# ************************ Beginn Programm **************************************

# Initialisieren aller Ausgaenge auf AUS

GPIO.output(14, False)
GPIO.output(15, False)
GPIO.output(18, False)
GPIO.output(17, False)
# GPIO.output(24, False)
GPIO.output(25, False)
GPIO.output(8, False)
GPIO.output(7, False)
GPIO.output(5, False)

# Initialisieren der Variablen

UVLampe        = False
CO2Pumpe       = False
CO2Cube        = False
CO2Ama         = False
#Bodenheizer   = False
Stabheizer     = False
Fuellpumpe     = False
Duengerpumpe   = False
zeit           = strftime("%H:%M", localtime())
alive          = False
Fuellstand     = False
Abstand        = False

# Initialisieren des Displays

lcd = lcddriver.lcd()
lcd.lcd_clear()

# Uhrzeit wie viele Sekunden
TIME_DELAY = 1
# Temperaturanzeige in Sekunden
TEMPERATUR_DELAY = 1

# Entfernungsmessung

def distanz():
    # setze Trigger auf HIGH
    GPIO.output(GPIO_TRIGGER, True)
 
    # setze Trigger nach 0.01ms aus LOW
    sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)
 
    StartZeit = time()
    StopZeit = time()
 
    # speichere Startzeit
    while GPIO.input(GPIO_ECHO) == 0:
        StartZeit = time()
 
    # speichere Ankunftszeit
    while GPIO.input(GPIO_ECHO) == 1:
        StopZeit = time()
 
    # Zeit Differenz zwischen Start und Ankunft
    TimeElapsed = StopZeit - StartZeit
    # mit der Schallgeschwindigkeit (34300 cm/s) multiplizieren
    # und durch 2 teilen, da hin und zurueck
    distanz = Ln - ((TimeElapsed * 34300) / 2)
 
    return distanz

# Auslesen der Temperatursensoren

# Temperatur 1 ermitteln und Wert value zurückgeben
def GetTemp1():
    a1 = open('/sys/bus/w1/devices/' + '28-031650f6d9ff' + '/w1_slave') # Ermittelten Sensor lesen
    Temp1 = a1.readline()

    if re.match(r"([0-9a-f]{2} ){9}: crc=[0-9a-f]{2} YES", Temp1): # Erste Zeile auf "YES" am Ende uberprufen
        Temp1 = a1.readline()
        m1 = re.match(r"([0-9a-f]{2} ){9}t=([+-]?[0-9]+)", Temp1) # Wert aus zweiter Zeile prufen 
    if m1:
        value1 = str(float(m1.group(2)) / 1000.0) # Wert nach t= auslesen und umwandeln
    a1.close()
    return value1 # Ruckgabewert "value" definieren

# Temperatur 2 ermitteln und Wert value zurckgeben
def GetTemp2():
    a2 = open('/sys/bus/w1/devices/' + '28-0416545902ff' + '/w1_slave') # Ermittelten Sensor lesen
    Temp2 = a2.readline()

    if re.match(r"([0-9a-f]{2} ){9}: crc=[0-9a-f]{2} YES", Temp2): # Erste Zeile auf "YES" am Ende uberprufen
        Temp2 = a2.readline()
        m2 = re.match(r"([0-9a-f]{2} ){9}t=([+-]?[0-9]+)", Temp2) # Wert aus zweiter Zeile prufen 
    if m2:
        value2 = str(float(m2.group(2)) / 1000.0) # Wert nach t= auslesen und umwandeln
    a2.close()
    return value2 # Ruckgabewert "value" definieren

while True: # Schleife endlos laufen lassen
    try: # Moeglichkeit Fehler abzufangen

        Abstand = round(float(distanz()),1)
        Temp1 = round(float(GetTemp1()),1) # Die Temperatur in eine Zahl wandeln....
        Temp2 = round(float(GetTemp2()),1) # Die Temperatur in eine Zahl wandeln....
        Fuellstand = str(Abstand)
        Temp_1 = str(Temp1)
        Temp_2 = str(Temp2)
        cputemp = str(round(float(open("/sys/class/thermal/thermal_zone0/temp", "r").read())/1000, 1))
        lcd.lcd_display_string("Amazonasb.:  "+Temp_1+chr(223)+"C", 1)
        lcd.lcd_display_string("NanoCube  :  "+Temp_2+chr(223)+"C", 2)
        lcd.lcd_display_string("CPU-Temp. :  "+cputemp+chr(223)+"C", 3)
        lcd.lcd_display_string("Fuellstand:  "+Fuellstand, 4)
    
    except KeyboardInterrupt: # Ausnahme STR+C festlegen
        GPIO.cleanup()
        
# Auswerten der Zeit und Schalten der Ausgaenge

# UVLampe

    if (zeit >= t1 and zeit<= t2) or (zeit >= t3 and zeit<= t4) :
        GPIO.output(14, True)
        UVLampe = False
    
    else :
        GPIO.output(14, False)
        UVLampe = True
      
# CO2Pumpe
    
    if (zeit >= t5 and zeit<= t6) :
        GPIO.output(15, True)
        CO2Pumpe = False
    
    else :
        GPIO.output(15, False)
        CO2Pumpe = True
      
# CO2

    if (zeit >= t7 and zeit <= t8) :
        GPIO.output(18, True)
        CO2Cube = False
    
    else :
        GPIO.output(18, False)
        CO2Cube = True
      
    #sleep(2)
    
    if (zeit >= t9 and zeit <= t10) :
        GPIO.output(17, True)
        CO2Ama = False
    
    else :
        GPIO.output(17, False)
        CO2Ama = True
        
# Temperatur  

#    if (Temp1 < BHL) :
#        GPIO.output(24, True)
#        Bodenheizer = False

#    if (Temp1 > BHH) :
#        GPIO.output(24, False)
#        Bodenheizer = True

    if (Temp1 < SHL) :
        GPIO.output(25, True)
        Stabheizer = False

    if (Temp1 > SHH) :
        GPIO.output(25, False)
        Stabheizer = True

#   if (temp >= TWL) and (temp <= TWH) :
#       GPIO.output(24, False)
#       GPIO.output(25, False)
#   else:
#       GPIO.output(24, True)
#       GPIO.output(25, True)

# Fuellpumpe

    if (Abstand < Ll) :
        GPIO.output(8, True)
        Fuellpumpe = False
    
    if (Abstand > Lh) :
        GPIO.output(8, False)
        Fuellpumpe = True

        
# Output von x Zeilen zum Klaeren des Bildschirms

    zaehler= 10
    while zaehler>0:
        print("*")
        zaehler-=1

# Ausgabe der Zeit

    zeit =strftime("%H:%M:%S", localtime())
    print (zeit)


# Ausgabe aller Schaltzustaende
      
    if UVLampe == False:
        print("UV-Lampe an")
    else:
        print("UV-Lampe aus")

    if CO2Pumpe == False:
        print("CO2-Pumpe an")
    else:
        print("CO2-Pumpe aus")

    if CO2Cube == False:
        print("CO2-Cube an")
    else:
        print("CO2-Cube aus")

    if CO2Ama == False:
        print("CO2-Ama an")
    else:
        print("CO2-Ama aus")


    # Temperatur ausgeben
    print(str("Temperatur 1 =") + ' %2.1f °C' % Temp1)
    print(str("Temperatur 2 =") + ' %2.1f °C' % Temp2)
    
    # Fuellstand ausgeben
    print(str("Füllstand    =") + ' %2.1f cm' % Abstand)
    
    if Fuellpumpe == False:
        print("Fuellpumpe an")
    else:
        print("Fuellpumpe aus")

#    if Bodenheizer == False:
#        print("Bodenheizer an")
#    else:
#        print("Bodenheizer aus")

    if Stabheizer == False:
        print("Stabheizer an")
    else:
        print("Stabheizer aus")


    if alive == True:
        GPIO.output (5, True)
        alive = False
        print ("x")
    else:
        GPIO.output (5, False)
        alive = True
        print ("+")
 
    sleep (0.1)  
Das eingebundene Script lcddriver sieht weifolgt aus:

Code: Alles auswählen

import sys
sys.path.append("./lib")

import i2c_lib
from time import *

# LCD Address
ADDRESS = 0x27

# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80

# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00

# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00

# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00

# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00

En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit

class lcd:
#initializes objects and lcd
    def __init__(self):
        self.lcd_device = i2c_lib.i2c_device(ADDRESS)

        self.lcd_write(0x03)
        self.lcd_write(0x03)
        self.lcd_write(0x03)
        self.lcd_write(0x02)
        
        self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
        self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
        self.lcd_write(LCD_CLEARDISPLAY)
        self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
    sleep(0.2)

#clocks EN to latch command
    def lcd_strobe(self, data):
        self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
        sleep(.0005)
        self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
        sleep(.0001)

    def lcd_write_four_bits(self, data):
        self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
        self.lcd_strobe(data)

#write a command to lcd
    def lcd_write(self, cmd, mode=0):
        self.lcd_write_four_bits(mode | (cmd & 0xF0))
        self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))
      
#turn on/off the lcd backlight
    def lcd_backlight(self, state):
        if state in ("on","On","ON"):
            self.lcd_device.write_cmd(LCD_BACKLIGHT)
        elif state in ("off","Off","OFF"):
            self.lcd_device.write_cmd(LCD_NOBACKLIGHT)
        else:
            print("Unknown State!")

#put string function
    def lcd_display_string(self, string, line):
        if line == 1:
            self.lcd_write(0x80)
        if line == 2:
            self.lcd_write(0xC0)
        if line == 3:
            self.lcd_write(0x94)
        if line == 4:
            self.lcd_write(0xD4)
        for char in string:
            self.lcd_write(ord(char), Rs)

#clear lcd and set to home
    def lcd_clear(self):
        self.lcd_write(LCD_CLEARDISPLAY)
        self.lcd_write(LCD_RETURNHOME)
Vielen Dank schonmal für Hilfe, Tipps und Ratschläge
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum wird eigentlich immer nur schlecht Code kopiert? Statt hunderte Zeiten Erklärung solltest du einfach deine Variablen gut benennen. Wie äußert sich denn das Aufhängen?
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

@ReneBe: Zu dem io-Kram kann ich nichts sagen, weil ich das noch nie gemacht habe, aber: warum machst du die Warnungen aus? Die kommen ja nicht um dich zu ärgern, sondern weisen dich darauf hin, dass du potentiell etwas falsch machst.

Dann läuft das alles über magische globale Variabeln. Das ist unwartbar und unerwartbar.
Teil das Programm in Funktionen auf, die alles was sie brauchen als Parameter erhalten und ihr Ergebnis per return zurück geben.

Wenn du eine ausführliche Berschreibung brauchst, welcher Name im Programm welche Bedeutung hat, dann machst du etwas Grundlegendes in der Benennung falsch. Namen sollen aussagekräftig und sprechend sein. Das sind einbuchstabig durchnummerierte auf keinen Fall. Es ist auch unnötig sie so kurz zu schreiben - das kostet ja nichts.
Alles wird klein_mit_unterstrich benannt, außer die Name von Klassen (PascalCase) und Konstanten (KOMPLETT_GROSS).

Dein Einstiegspunkt sieht wie üblich so aus:

Code: Alles auswählen

def main():
    # dein Programm hier

if __name__ == "__main__":
    main()
Und auf Modulebene, also uneingerückt, kommen nur die Importe, Definition von Funktionen und Klassen und KONSTANTEN.

GetTempX sollte also get_temp heißen. Und die beiden Funktionen sollten eine sein, weil sie weitestgehend identisch sind.

Das hier ist dann beim schnellen drüberschauen sofort aufgefaleln:

Code: Alles auswählen

lcd.lcd_display_string("Amazonasb.:  "+Temp_1+chr(223)+"C", 1)
# warum nicht einfach
lcd.lcd_display_string(f"Amazonasb.:  {temperatur_amazonasbecken}°C", 1)
Das ist, was mir zuerst ins Auge gefallen ist. Da liegt noch weit mehr im argen.

Und das Wichtigste zum Schluss:
Du möchtest Dinge tun, die die Umwelt- und Lebensbedingungen von Lebewesen steuern.
Dein Code erweckt bei mir den Eindruck, dass da sehr viel einfach kopiert wurde, ohne es zu hinterfragen. Warnungen sind abgeschaltet, Fehlerbehandlung ist nicht vorhanden. Das Programm läuft auf Hardware, die nicht aufallsicher ist (denn das ein Raspi nicht).
Bitte mach das nicht. Ich habe Sorge, dass du da Tiere entweder kochst oder sie erfrieren lässt.
Benutzeravatar
hyle
User
Beiträge: 96
Registriert: Sonntag 22. Dezember 2019, 23:19
Wohnort: Leipzig

Hinzufügen möchte ich noch... Sternchenimporte (from time import *) müllen den Namensraum zu. Das macht man nicht, zumal sleep eine Zeile danach expliziet importiert wird!

Und dann noch das Übliche: Statt RPi.GPIO würde ich eher gpiozero (https://gpiozero.readthedocs.io/en/stable/) empfehlen. Das ist einfacher, cooler und und aktueller.
Alles was wir sind ist Sand im Wind Hoschi.
ReneBe
User
Beiträge: 2
Registriert: Samstag 13. Februar 2021, 19:25

Hallo,

ich werde auf jeden Fall mal recherchieren, wie ich die genannten Tipps richtig umsetzen muss. Wie gesagt, ich bin Autodidakt und bin gerade erst dabei, mir das beizubringen. Mit Programmierung habe ich sonst nichts am Hut.

@Sirius3: Das ist das Problem, als Anfänger unterscheiden zu können, was gut und was schlecht ist. Das ist glaub ich, in so ziemlich jedem Bereich des Lebens so, oder? Das Aufhängen äußert sich, in dem das Script stehen bleibt. An welcher Stelle und warum, kann ich dir nicht sagen. Wenn ich wüsste, wie ich das rausfinden kann, würde ich es dir sagen. Auf jeden Fall aktualisiert sich die Bildschirmausgabe nicht mehr (bleibt stehen) und das 4x20 Display ebenfalls, die "Life"-LED blinkt auch nicht mehr.

@sparrow: Eine Sorge kann ich dir vorweg nehmen, dass ich meine Fische im Aquarium erfrieren lasse oder abkoche. Alle wichtigen Dinge zur Erhaltung der Lebensbedingungen im Aquarium laufen autark - Filter, LED-Lichtsteuerung und auch der Heizstab hat ein eingebautes Thermosthat, sodass selbst bei Nichtabschaltung des Heizstab-Relais nichts passieren kann. Diese Steuerung soll mir einfach die zahlreichen Zeitschaltuhren ersparen und bestimmte Geräte am Aquarium bei Nichtnutzung abschalten. Außerdem will ich die Schaltzustände der Relais später noch über Openhab auslesen und in mein Smarthome einbinden.

Code: Alles auswählen

lcd.lcd_display_string(f"Amazonasb.:  {temperatur_amazonasbecken}°C", 1)
Die Ausgabe in den geschweiften Klammern muss ich mir ebenfalls anschauen. Den Hintergrund kenne ich noch nicht, werde mich aber belesen. Die Ausgabe von "°C" funtkioniert leider nicht. Soviel kann ich dir schon mal verraten. Hinter dem Zaun hab ich auch schon gesessen. Da gibt das Display höchsten irgendwelche krytische Zeichen aus. Das funtkioniert bei mir nur mit "+chr(223)+"C"".

Wie gesagt, ich danke erstmal für die Tipps, werde mich weiter belesen und versuchen, es besser zu machen. Sollte ich Fortschritte gemacht haben (hoffentlich) werde ich den überarbeiteten Code nochmal einfügen.

Ich bin für weitere Tipps natürlich dankbar.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich würde das trotzdem nicht als ``chr(223)`` schreiben, sondern den Text ”normal” lesbar mit dem ° und dann eine Hilfsfunktion die dieses Zeichen dann durch das ersetzt was das Display erwartet. Das wird ja noch andere Zeichen betreffen, da kann man sich dann gleich eine Ersetzungstabelle für die `translate()`-Methode auf Zeichenketten zusammenstellen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Hier mal den Code etwas übersichtlicher:

Code: Alles auswählen

#!/usr/bin/env python3
import time
import re
from RPi import GPIO
import lcddriver
from time import sleep, localtime, strftime

AN_AUS = {
    True: "an",
    False: "aus",
}

GPIO_TRIGGER = 20
GPIO_ECHO = 21
SENSOR1 = '28-031650f6d9ff'
SENSOR2 = '28-0416545902ff'

# Ein- und Ausschaltzeiten der Lampen
UVLAMPE_ZEITEN = "04:00", "07:00", "13:00", "16:00"
CO2PUMPE_ZEITEN = "11:00", "19:00"
CO2CUBE_ZEITEN = "11:00", "16:00"
CO2AMA_ZEITEN = "11:00", "18:00"

# Fuellstand
NORMAL_LEVEL = 4.0
LEVEL_LOW = -1.0
LEVEL_HIGH = 0.5

# Temperatur-Schaltpunkte

# BHL = 22.0  # Bodenheizer Low (ein)
# BHH = 25.0  # Bodenheizer High (aus)

SHL = 23.5  # Stabheizer Low (ein)
SHH = 24.0  # Stabheizer High (aus)

TWH = 24.8  # Warnlevel Temperatur High
TWL = 22.0  # Warnlevel Temperatur Low


def distanz():
    GPIO.output(GPIO_TRIGGER, True)
    sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)
 
    # speichere Startzeit
    while GPIO.input(GPIO_ECHO) == 0:
        pass
    start_zeit = time()
 
    # speichere Ankunftszeit
    while GPIO.input(GPIO_ECHO) == 1:
        pass
    stop_zeit = time()
 
    # Zeit Differenz zwischen Start und Ankunft
    time_elapsed = stop_zeit - start_zeit
    # mit der Schallgeschwindigkeit (34300 cm/s) multiplizieren
    # und durch 2 teilen, da hin und zurueck
    distanz = NORMAL_LEVEL - ((time_elapsed * 34300) / 2)
    return distanz


def read_temperature(sensor):
    with open(f'/sys/bus/w1/devices/{sensor}/w1_slave') as data:
        temperature = data.read().rsplit('=', 1)[1]
    return float(temperature) / 1000


def main():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(14, GPIO.OUT) # UVLampe
    GPIO.setup(15, GPIO.OUT) # CO2Pumpe
    GPIO.setup(18, GPIO.OUT) # CO2Cube
    GPIO.setup(17, GPIO.OUT) # CO2Ama
    #GPIO.setup(24, GPIO.OUT) # Bodenheizer
    GPIO.setup(25, GPIO.OUT) # Stabheizer
    GPIO.setup(8, GPIO.OUT) # Fuellpumpe
    GPIO.setup(7, GPIO.OUT)  # Duengerpumpe
    GPIO.setup(5, GPIO.OUT)  # Alive
    GPIO.setup(4, GPIO.OUT)  # Temperatur out of range
    GPIO.setup(20, GPIO.OUT) # Fuellstand Trigger
    GPIO.setup(21, GPIO.IN) # Fuellstand Echo
    try:
        # Initialisieren aller Ausgaenge auf AUS
        GPIO.output(14, False)
        GPIO.output(15, False)
        GPIO.output(18, False)
        GPIO.output(17, False)
        # GPIO.output(24, False)
        GPIO.output(25, False)
        GPIO.output(8, False)
        GPIO.output(7, False)
        GPIO.output(5, False)

        # Initialisieren der Variablen
        #Bodenheizer   = False
        stabheizer     = False
        fuellpumpe     = False
        alive          = False

        # Initialisieren des Displays

        lcd = lcddriver.lcd()
        lcd.lcd_clear()

        while True: # Schleife endlos laufen lassen
            abstand = distanz()
            temperatur1 = read_temperature(SENSOR1)
            temperatur2 = read_temperature(SENSOR2)
            with open("/sys/class/thermal/thermal_zone0/temp") as input:
                cputemp = float(input.read()) / 1000
            lcd.lcd_display_string(f"Amazonasb.:  {temperatur1:.1f}°C".replace('°', chr(223)), 1) # 223
            lcd.lcd_display_string(f"NanoCube  :  {temperatur1:.1f}°C".replace('°', chr(223)), 2)
            lcd.lcd_display_string(f"CPU-Temp. :  {cputemp:.1f}°C".replace('°', chr(223)), 3)
            lcd.lcd_display_string(f"Fuellstand:  {abstand:.1f}", 4)
                    
            # Auswerten der Zeit und Schalten der Ausgaenge
            zeit = strftime("%H:%M:%S", localtime())
            uv_lampe = not (UVLAMPE_ZEITEN[0] <= zeit <= UVLAMPE_ZEITEN[1] or UVLAMPE_ZEITEN[2] <= zeit <= UVLAMPE_ZEITEN[3])
            GPIO.output(14, not uv_lampe)
            co2_pumpe = not CO2PUMPE_ZEITEN[0] <= zeit <= CO2PUMPE_ZEITEN[1]
            GPIO.output(15, not co2_pumpe)
            co2_cube = not CO2CUBE_ZEITEN[0] <= zeit <= CO2CUBE_ZEITEN[1]
            GPIO.output(18, not co2_cube)
            co2_ama = not CO2AMA_ZEITEN[0] <= zeit <= CO2AMA_ZEITEN[1]
            GPIO.output(17, not co2_ama)
                
            # Temperatur  
        #    if Temp1 < BHL:
        #        Bodenheizer = False
        #    elif Temp1 > BHH:
        #        Bodenheizer = True
        #    GPIO.output(24, not Bodenheizer)

            if temperatur1 < SHL:
                stabheizer = False
            elif temperatur1 > SHH:
                stabheizer = True
            GPIO.output(25, not stabheizer)

        #   if (temp >= TWL) and (temp <= TWH) :
        #       GPIO.output(24, False)
        #       GPIO.output(25, False)
        #   else:
        #       GPIO.output(24, True)
        #       GPIO.output(25, True)

            if abstand < LEVEL_LOW:
                fuellpumpe = False
            elif abstand > LEVEL_HIGH:
                fuellpumpe = True
            GPIO.output(8, not fuellpumpe)

            # Output von x Zeilen zum Klaeren des Bildschirms
            for _ in range(10):
                print("*")

            # Ausgabe der Zeit
            print(zeit)

            # Ausgabe aller Schaltzustaende      
            print(f"UV-Lampe {AN_AUS[not uv_lampe]}")
            print(f"CO2-Pumpe {AN_AUS[not co2_pumpe]}")
            print(f"CO2-Cube {AN_AUS[not co2_cube]}")
            print(f"CO2-Ama {AN_AUS[not co2_ama]}")

            # Temperatur ausgeben
            print(f"Temperatur 1 = {temperatur1:2.1f} °C")
            print(f"Temperatur 2 = {temperatur2:2.1f} °C")
            
            # Fuellstand ausgeben
            print(f"Füllstand    = {abstand:%2.1f} cm")
            print(f"Fuellpumpe {AN_AUS[not fuellpumpe]}")
            # print(f"Bodenheizer {AN_AUS[not Bodenheizer]}")
            print(f"Stabheizer {AN_AUS[not stabheizer]}")

            GPIO.output(5, alive)
            print("x" if alive else "+")
            alive = not alive
            sleep(0.1)  
    finally:
        GPIO.cleanup()

if __name__ == "__main__":
    main()
Problem ist die Abstandsmessung. Wenn da was schief läuft, dann hängst Du in einer Endlosschleife. Da braucht es einen Timeout.
Antworten