Hallo,
ich benötige mal Eure Hilfe, denn ich steht hier auf dem Schlauch....
Ich möchte 5 Schaltzustände erzeugen. Die Steuergröße ist eine sich verändernder Fußpunkt einer Heizkurve, die zur Verfügung steht.
(Der Fußpunkt wird aus dem Wärmebedarf basierend auf der Temp-Differenz zwischen Soll- und Ist-Temperatur ermittelt. Je höher der Wärmebedarf, also je größer der Unterschied zwischen Soll- und Ist-Temperatur, desto höher der Fußpunkt)
Die Schaltzustände:
- Tag_high
- Tag_med
- Tag_low
- Nacht
- Frostschutz
Ja nach Fußpunkt sollen die Schaltzustände aktiviert werden:
- Tag_high ein: Fußpunkt >= 24°C
- Tag_med ein: Fußpunkt >= 22°C
- Tag_low ein: Fußpunkt >= 20°C
- Nacht ein : Fußpunkt >= 17°C
- Frostschutz: Fußpunkt < 17°C
Damit im Grenzbereich zwischen 2 Temperaturschwellen die Schaltzustände nicht ständig wechseln, soll das "Abschalten" immer 1°C unterhalb des Einschaltschwelle erfolgen.
- Tag_high aus: Fußpunkt >= 23°C
- Tag_med ein: Fußpunkt >= 21°C
- Tag_low ein: Fußpunkt >= 19°C
- Nacht ein : Fußpunkt >= 16°C
- Frostschutz: Fußpunkt < 16°C
Über den Schaltzustand sollen den Pumpen, etc gesteuert werden.
Die Fragen an Euch ist, wie die Logik in Python aussehen kann / muss, damit die Schaltzustände "errechnet" werden.
Danke für die Hilfe.
Mehrfache Hysterese programmieren
-
- User
- Beiträge: 219
- Registriert: Donnerstag 21. Juli 2011, 07:01
- Wohnort: Stade / Hamburg
- Kontaktdaten:
hm, vielleicht verstehe ich die Frage nicht. Aber die Logik steht doch schon da. Und das errechnen ist doch nur ein Abgleich des aktuellen Wertes mit dem aktuellen Schaltzustand (-1/+1) und dann dem Wechsel des Zustands. Das ganze in einer sich wiederholenden Schleife ggf. mit Wartezeit zwischen den einzelnen Abgleichen.
Ansätze:
- Variablen
- Vergleichsoperatoren
- Abfragen
- Endlosschleife
Poste hier doch gerne deinen Ansatz, gerne auch in Pseudocode. Dann können wir besser sehen, wo es noch fehlt und gezielter helfen.
Ansätze:
- Variablen
- Vergleichsoperatoren
- Abfragen
- Endlosschleife
Poste hier doch gerne deinen Ansatz, gerne auch in Pseudocode. Dann können wir besser sehen, wo es noch fehlt und gezielter helfen.
So, ich habe mich mal versucht.
Das ganze ist eine Logik für smarthomeNG, ein smarthome Metagateway auf Python-Basis.
Geht das eleganter?
Das ganze ist eine Logik für smarthomeNG, ein smarthome Metagateway auf Python-Basis.
Code: Alles auswählen
#!/usr/bin/env python3
# heizung_vorlauf.py
# 4-Stufen-Steuerung des Vorlaufes in Abhängigkeit vom berechneten Fusspunkt
# Ausgelöst durch "Fusspunkt" und 'Außentemperatur'
#Deklaration lokaler Variablen
# at; ! Aussentemperatur in °C
# fp; ! berechneter max. Fusspunkt in °C
# tag_mittel ! Tagesdurchschittstemperatur
logger.info("Logik HeizungVorlauf ausglöst durch:" + trigger['by'] )
# Aussentemperaturen einlesen
at = sh.rpi1wire.temp_1()
tag_mittel = sh.rpi1wire.temp_1.tagesmittel_gleitend()
#logger.info("Außentemperatur: " + str(at))
#Systemvariable einlesen
if (at < 20.0) or (tag_mittel < 11.0):
fp = sh.heizung.vorlauf.fusspunkt()
logger.info("Fußpunkt gesetzt auf " + str(fp))
else:
fp = 14.0
if not hasattr(logic, 'fp_alt'):
logic.fp_alt = fp
richtung = round(fp - logic.fp_alt, 2) #richtung gibt an, ob der neue Fußpunkt höher ist als der alte; sinken die Wert oder steigen sie
logger.info("Richtung " + str(richtung))
#Konstanten (Schaltschwellen)
nachtaus = 15.0
tagminaus = 18.5
tagnormaus = 20.5
tagmaxaus = 22.5
nachtein = 16.5
tagminein = 19.5
tagnormein = 21.5
tagmaxein = 23.5
#Stufen
if (richtung >= 0) and (fp >= tagmaxein) or ((richtung < 0) and (fp > tagmaxaus)):
zustand = 'tag_max'
elif ((richtung >= 0) and (fp >= tagnormein)) or ((richtung < 0) and (fp > tagnormaus)):
zustand = 'tag_med'
elif (richtung >= 0) and (fp >= tagminein) or ((richtung < 0) and (fp > tagminaus)):
zustand = 'tag_min'
elif (richtung >= 0) and (fp >= nachtein) or ((richtung < 0) and (fp > nachtaus)):
zustand = 'nacht'
else:
zustand = 'frost'
logger.info("Zustand gesetzt auf " + str(zustand))
#Aktionen
if zustand == 'tag_max':
sh.heizung.vorlauf.nacht(0)
sh.heizung.vorlauf.tag_min(0)
sh.heizung.vorlauf.tag_med(0)
sh.heizung.vorlauf.tag_max(1)
logger.info("Tag_Max aktiviert")
elif zustand == 'tag_med':
sh.heizung.vorlauf.nacht(0)
sh.heizung.vorlauf.tag_min(0)
sh.heizung.vorlauf.tag_med(1)
sh.heizung.vorlauf.tag_max(0)
logger.info("Tag_Med aktiviert")
elif zustand == 'tag_min':
sh.heizung.vorlauf.nacht(0)
sh.heizung.vorlauf.tag_min(1)
sh.heizung.vorlauf.tag_med(0)
sh.heizung.vorlauf.tag_max(0)
logger.info("Tag_Min aktiviert")
elif zustand == 'nacht':
sh.heizung.vorlauf.nacht(1)
sh.heizung.vorlauf.tag_min(0)
sh.heizung.vorlauf.tag_med(0)
sh.heizung.vorlauf.tag_max(0)
logger.info("Nacht aktiviert")
elif zustand == 'frost':
sh.heizung.vorlauf.nacht(0)
sh.heizung.vorlauf.tag_min(0)
sh.heizung.vorlauf.tag_med(0)
sh.heizung.vorlauf.tag_max(0)
logger.info("Frostschutz aktiviert")
else:
none
logic.fp_alt = fp
logger.info("Fußpunkt_alt gesetzt auf " + str(logic.fp_alt))
@sisamiwe: Skripte, in denen etliche Variablen aus dem Nichts kommen, sind mir suspect. Wenn Du Deine Variablen sinnvoll benennen würdest, müßtest Du nicht in einem Kommentar erklären, was ›at‹ oder ›fp‹ bedeuten.
Bei den if-Bedingungen sind etliche Klammern zu viel und ein paar zuwenig.
Wenn man die ganzen Konstanten in eine passende Struktur packt, dann ist die if-Kaskade ein Zweizeiler.
Statt den else-Block eines if-Switches, der nie Auftreten sollte mit einem NameError abbrechen zu lassen, sollte das ein AssertionError sein: »assert False, "sollte nicht auftreten"«.
Alternativ kann man das auch vereinfachen zu:
Bei den if-Bedingungen sind etliche Klammern zu viel und ein paar zuwenig.
Wenn man die ganzen Konstanten in eine passende Struktur packt, dann ist die if-Kaskade ein Zweizeiler.
Statt den else-Block eines if-Switches, der nie Auftreten sollte mit einem NameError abbrechen zu lassen, sollte das ein AssertionError sein: »assert False, "sollte nicht auftreten"«.
Alternativ kann man das auch vereinfachen zu:
Code: Alles auswählen
sh.heizung.vorlauf.nacht(zustand == 'nacht')
sh.heizung.vorlauf.tag_min(zustand == 'tag_min')
sh.heizung.vorlauf.tag_med(zustand == 'tag_med')
sh.heizung.vorlauf.tag_max(zustand == 'tag_max')
logger.info("%s aktiviert", zustand)
@Sirius3
Erstmal danke für Deine Rückmeldung.
Ich habe die Logik überarbeitet und die Variablen besser benannt.
Der letzte Teil der Logik ist das Setzen des Schaltaktors, also die Zuschaltung der Widerstande 1 - 4 (habe ich auch besser benannt) in Abhängigkeit vom Zustand aus er Logik.
Du sagt, dass man die if Abfrage in einem 2-Zeiler ausdrücken könnte? Wie könnte das aussehen?
Erstmal danke für Deine Rückmeldung.
Ich habe die Logik überarbeitet und die Variablen besser benannt.
Der letzte Teil der Logik ist das Setzen des Schaltaktors, also die Zuschaltung der Widerstande 1 - 4 (habe ich auch besser benannt) in Abhängigkeit vom Zustand aus er Logik.
Du sagt, dass man die if Abfrage in einem 2-Zeiler ausdrücken könnte? Wie könnte das aussehen?
Code: Alles auswählen
#!/usr/bin/env python3
# heizung_vorlauf.py
# 4-Stufen-Steuerung des Vorlaufes in Abhängigkeit vom berechneten Fusspunkt
# Ausgelöst durch "Fusspunkt" und Außentemperatur
logger.info("Logik HeizungVorlauf ausglöst durch:" + trigger['by'] )
# Aussentemperaturen einlesen
aussentemp_aktuell = sh.rpi1wire.temp_1()
aussentep_tagesmittel = sh.rpi1wire.temp_1.tagesmittel_gleitend()
fusspunkt = sh.heizung.vorlauf.fusspunkt()
# Prüfung ob Heizung aufgrund Aussentemperatur gebraucht wird
if (aussentemp_aktuell < 20.0) or (aussentep_tagesmittel < 11.0):
heizung = true
# Prüfung, ob persistente Variablen vorhanden, wenn nicht setzen dieser
if not hasattr(logic, 'fusspunkt_alt'):
logic.fusspunkt_alt = fusspunkt
# Prüfung, ob neuer Fußpunkt größer oder kleiner ist, um die Verlaufsrichtung des Fußpunkts festzustellen
richtung = round(fusspunkt - logic.fusspunkt_alt, 1)
logger.info("Richtung " + str(richtung))
#Konstanten (Schaltschwellen)
nachtaus = 15.0
tagminaus = 18.5
tagnormaus = 20.5
tagmaxaus = 22.5
nachtein = 16.5
tagminein = 19.5
tagnormein = 21.5
tagmaxein = 23.5
#Stufen
if (heizung == 'true') and ((richtung >= 0) and (fusspunkt >= tagmaxein)) or ((richtung < 0) and (fusspunkt > tagmaxaus)):
zustand = 'tag_max'
elif (heizung == 'true') and ((richtung >= 0) and (fusspunkt >= tagnormein)) or ((richtung < 0) and (fusspunkt > tagnormaus)):
zustand = 'tag_med'
elif (heizung == 'true') and ((richtung >= 0) and (fusspunkt >= tagminein)) or ((richtung < 0) and (fusspunkt > tagminaus)):
zustand = 'tag_min'
elif (heizung == 'true') and ((richtung >= 0) and (fusspunkt >= nachtein)) or ((richtung < 0) and (fusspunkt > nachtaus)):
zustand = 'nacht'
else:
zustand = 'frost'
logger.info("Zustand gesetzt auf " + str(zustand))
#Aktionen
if zustand == 'tag_max':
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(1)
logger.info("Tag_Max aktiviert")
elif zustand == 'tag_med':
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(0)
logger.info("Tag_Med aktiviert")
elif zustand == 'tag_min':
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(0)
sh.heizung.vorlauf.widerstand1(0)
logger.info("Tag_Min aktiviert")
elif zustand == 'nacht':
sh.heizung.vorlauf.widerstand1(1)
sh.heizung.vorlauf.widerstand1(0)
sh.heizung.vorlauf.widerstand1(0)
sh.heizung.vorlauf.widerstand1(0)
logger.info("Nacht aktiviert")
elif zustand == 'frost':
sh.heizung.vorlauf.widerstand1(0)
sh.heizung.vorlauf.widerstand1(0)
sh.heizung.vorlauf.widerstand1(0)
sh.heizung.vorlauf.widerstand1(0)
logger.info("Frostschutz aktiviert")
logic.fp_alt = fp
logger.info("Fußpunkt_alt gesetzt auf " + str(logic.fp_alt))
@sisamiwe: Programmieren ist nicht raten. Warum wird` heizung` einmal der Wert der nicht definierten Variable `true` zugewiesen und dann mit dem String 'true' verglichen? Ersteres sollte der boolsche Wert True sein, bei zweiterem braucht man gar keinen Vergleich, weil heizung ja schon ein Wahrheitswert ist. fusspunkt wurde nicht überall verbessert.
Was ist eigentlich `sh` für ein Objekt? Warum setzt Du jetzt `sh.heizung.vorlauf.widerstand1` vier mal hintereinander?
Was ist eigentlich `sh` für ein Objekt? Warum setzt Du jetzt `sh.heizung.vorlauf.widerstand1` vier mal hintereinander?