Seite 1 von 3

[Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 18. Jul 2020 09:41
von JDog1895
Guten Morgen,

heute wende ich mich wieder an Euch, weil ich mal wieder Probleme mit einer Regel habe.

Vorab:
Ich habe als Heizkörperthermostat Geräte von CometDECT. Ich kann diese steuern.
Im Sommer ist der Heizkörper ausgeschaltet. Der "RadiatorMode" ist OFF und "SetTemp" steht auf 6.0.
Ist im Winter eine Temperatur von 21 Grad gegeben, so ist der "RadiatorMode" auf ON und "SetTemp" steht auf 21.0.

Was funktioniert:
Ist 21 Grad als Temperatur eingestellt, ich öffne das Fenster, dann geht die Heizung aus und beim schließen des Fensters wird die Temperatur wiederhergestellt.
Ich muss den Temperaturwert in eine Variable speichern, da ich nicht mit previousState arbeiten kann. Das liegt daran, dass beim Abschalten der Heizung die Temperatur auf 6.0 gestellt wird und der previousState dann nicht mehr 21.0, sondern 6.0 wiederherstellt.

Was nicht funktioniert:
Wenn die Heizung abgeschaltet ist, soll das Thermostat kein OFF-Command und auch keinen gespeicherten Temperaturwert erhalten. Gerade im Hinblick darauf, dass man 6.0 zwar senden kann, dies aber automatisch in 8.0 als Minimumtemperatur geändert wird und die Heizung dann nicht mehr OFF ist.

Code: Alles auswählen

// Wird das Wohnzimmerfenster geöffnet, so schaltet die Heizung ab und der letzte Wert wird wiederhergestellt.

var Number savedTemp = null

rule "Heizventil schließen bei offenem Fenster -Wohnzimmer-"

when Item XiaomiDoorSensorWohnzimmerIsOpen changed      //Wenn sich das Fenster öffnet oder schließt

then

        if(XiaomiDoorSensorWohnzimmerIsOpen.state == OPEN) {    
                logInfo("Testing", "Aktueller Status Heizung: " + HeizungWohnzimmerRadiatorMode.state)
                logInfo("Testing", "Aktueller Wert: " + HeizungWohnzimmerSetTemp.state)
                if (HeizungWohnzimmerSetTemp == "6.0"){
                   logInfo("Testing", "Die Heizung ist ausgeschaltet.")
                savedTemp = 0}
                else {
                   savedTemp = HeizungWohnzimmerSetTemp.state as Number
                   sendCommand(HeizungWohnzimmerRadiatorMode, "OFF")
                }
        }
        if(XiaomiDoorSensorWohnzimmerIsOpen.state == CLOSED) {
                if (savedTemp == 0) {
                    logInfo("Testing", "Die Heizung ist ausgeschaltet. Dies bleibt auch so.")}
                else {
                logInfo("Testing", "Letzter Status Heizung: " + HeizungWohnzimmerRadiatorMode.state)
                logInfo("Testing", "Letzter Wert: " + savedTemp) 
                HeizungWohnzimmerSetTemp.sendCommand(savedTemp)}
                
        }
end
Im Log sieht es so aus:

Code: Alles auswählen

2020-07-18 09:23:13.833 [INFO ] [lipse.smarthome.model.script.Testing] - Aktueller Status Heizung: OFF

2020-07-18 09:23:13.839 [INFO ] [lipse.smarthome.model.script.Testing] - Aktueller Wert: 6.0 °C

==> /var/log/openhab2/events.log <==

2020-07-18 09:23:13.864 [ome.event.ItemCommandEvent] - Item 'HeizungWohnzimmerRadiatorMode' received command OFF

2020-07-18 09:23:13.866 [nt.ItemStatePredictedEvent] - HeizungWohnzimmerRadiatorMode predicted to become OFF

2020-07-18 09:24:09.025 [vent.ItemStateChangedEvent] - XiaomiDoorSensorWohnzimmerIsOpen changed from OPEN to CLOSED

2020-07-18 09:24:09.063 [INFO ] [lipse.smarthome.model.script.Testing] - Letzter Status Heizung: OFF

2020-07-18 09:24:09.071 [INFO ] [lipse.smarthome.model.script.Testing] - Letzter Wert: 6.0 °C

==> /var/log/openhab2/events.log <==

2020-07-18 09:24:09.095 [ome.event.ItemCommandEvent] - Item 'HeizungWohnzimmerSetTemp' received command 6.0 °C

2020-07-18 09:24:09.098 [nt.ItemStatePredictedEvent] - HeizungWohnzimmerSetTemp predicted to become 6.0 °C

2020-07-18 09:24:09.132 [vent.ItemStateChangedEvent] - HeizungWohnzimmerRadiatorMode changed from OFF to ON

2020-07-18 09:24:20.936 [vent.ItemStateChangedEvent] - HeizungWohnzimmerSetTemp changed from 6.0 °C to 8.0 °C
Ich habe im Abstand von mehreren Tagen immer mal wieder den Code gesichtet, aber ich finde den Fehler nicht.
Es wäre schön, wenn mir jemand einen Tipp geben könnte, woran es hakt.

Viele Grüße
Matthias

[Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 18. Jul 2020 11:54
von udo1toni
Also, abgesehen davon, dass die Rule etwas von hinten durch die Brust ins Auge arbeitet, hast Du ein if-Statement, bei dem Du auf das Item zugreifst, statt auf den Status des Items (beim Öffnen des Fensters). Damit wird also immer der else-Teil ausgeführt.

Es geht um diese Zeile:

Code: Alles auswählen

if (HeizungWohnzimmerSetTemp == "6.0"){
Stattdessen muss da

Code: Alles auswählen

if (HeizungWohnzimmerSetTemp.state == 6){
stehen.

Im Übrigen wäre es vermutlich sinnvoller, mit Persistence und historicState zu arbeiten. Du kannst dann entweder den Zeitstempel beim Öffnen des Fensters in einer Variablen merken und später verwenden, oder (das ist allerdings auch etwas komplizierter) Du liest den Zeitpunkt der letzten Fenster Öffnung ebenfalls aus der Persistence aus und nutzt diesen Zeitstempel dann, um die Solltemperatur zu ermitteln.

Gesendet von iPad mit Tapatalk

Re: [Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 18. Jul 2020 21:55
von peter-pan
...vielleicht noch ein kleiner Tipp. Ich vermute mal, dass du das Item mit Quantity/UoM angelegt hast, etwa so:

Code: Alles auswählen

Number:Temperature  radiator_valve_03_Set   "Thermostat ELW Wohnen Richtwert [%.1f %unit%]" <heating1> (UG_WohnenEssen,gRFritz_03,gRtSoll)               { channel="avmfritz:FRITZ_DECT_301:7490:099950152273:set_temp" }
Dann sollte dein Vergleich noch etwas erweitert werden

Code: Alles auswählen

if( (radiator_valve_03_Set.state as Number).floatValue > 6) {

Re: [Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 10. Jan 2021 23:16
von Eleven
Hallo und guten Abend,
ich würde mich hier gerne einklinken. Ich habe mit Hilfe vom Forum eine Rule erstellt, welche beim öffnen des Fensters die/den jeweiligen Heizkörper auf einer vordefinierte Temperatur regelt. Sobald ich das Fenster schließe wird der Heizkörper wieder eine vordefinierte Temperatur gestellt. Ich möchte nun, das beim schließen des Fensters wieder die Temperatur hergestellt wird, welche vor dem öffnen eingestellt war. Ich hatte es schonmal mit "previousState" probiert, allerdings habe ich es einfach nicht hinbekommen.

Hier mal die rule für ein Fenster:

Code: Alles auswählen

var Timer fenstertimer = null    
val Number tempComfort = 23.0
val Number tempOff = 8.0

rule "Heizung Bad unten"
when
    Item BDU_Fenster_Status changed                             // Triggere wenn der Fensterkontakt geschaltet hat
then
    if(BDU_Fenster_Status.state != CLOSED) {                    // Fenster offen oder nicht initialisiert?
        BDU_Heizung_SetTemp.sendCommand(tempOff)  
        logInfo("Heizung", "Fenster im Bad unten geöffnet und Heizkörper abgedreht")
        fenstertimer = createTimer(now.plusMinutes(10), [|      // Starte Timer für Meldung
            sendPushoverMessage(pushoverBuilder("Info, Fenster Bad unten 10 Min. geöffnet").withDevice("iPhoneXR"))
            fenstertimer = null 
        ])                                                      // Lambda in die Funktion verschoben, Lesbarkeit des Codes
    } else {                                                    // Fenster ist geschlossen!
        BDU_Heizung_SetTemp.sendCommand(tempComfort)
        logInfo("Heizung", "Fenster im Bad unten geschlossen und Heizkörper aufgedreht")
        if(fenstertimer !== null) {                             // Timer läuft?
            fenstertimer.cancel                                 // Timer abbrechen
            fenstertimer = null 
        }
    }
end
Könnt ihr mir weiterhelfen?
Grüße Eleven

Re: [Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 11. Jan 2021 00:16
von udo1toni
Es gibt dafür verschiedene Möglichkeiten. Die "billige" Variante: Du legst einfach eine globale Variable (pro Temperaturwert, der gemerkt werden soll) an und rettest den Temperaturwert in diesem Zwischenspeicher. Nachteil: Wenn openHAB bei geöffnetem Fenster neu gestartet wird, weiß openHAB nicht mehr, welche Temperatur beim Öffnen eingestellt war, denn die Variable wird neu initialisiert. Leider wird die globale Variable auch beim erneuten Einlesen der Datei initialisiert, sogar, wenn Du nur den Zeitstempel der Datei änderst, aber auch wenn Du nur etwas an einer Rule änderst.
Trotzdem als Beispiel:

Code: Alles auswählen

var Timer fenstertimer = null    
val Number tempComfort = 23.0
val Number tempOff = 8.0
var Number tempBDU = 23.0               // Nur ein Default Wert. Beim Öffnen des Fensters wird der Wert überschrieben.

rule "Heizung Bad unten"
when
    Item BDU_Fenster_Status changed                             // Triggere wenn der Fensterkontakt geschaltet hat
then
    if(BDU_Fenster_Status.state != CLOSED) {                    // Fenster offen oder nicht initialisiert?
        tempBDU = BDU_Heizung_SetTemp.state as Number    // Temperatur retten
        BDU_Heizung_SetTemp.sendCommand(tempOff)  
        logInfo("Heizung", "Fenster im Bad unten geöffnet und Heizkörper abgedreht")
        fenstertimer = createTimer(now.plusMinutes(10), [|      // Starte Timer für Meldung
            sendPushoverMessage(pushoverBuilder("Info, Fenster Bad unten 10 Min. geöffnet").withDevice("iPhoneXR"))
        ])                                                      // Lambda in die Funktion verschoben, Lesbarkeit des Codes
    } else {                                                    // Fenster ist geschlossen!
        BDU_Heizung_SetTemp.sendCommand(tempBDU)          // geretteten Wert zurückschreiben.
        logInfo("Heizung", "Fenster im Bad unten geschlossen und Heizkörper aufgedreht")
        fenstertimer?.cancel                                 // Timer abbrechen, falls aktiv
    }
end
Es ist nicht notwendig, kompliziert nach === null zu prüfen, der ? Operator erledigt das wesentlich eleganter.

Die bessere Alternative führt über die Persistence. Weil ich jetzt Feierabend habe, bleibe ich ein konkretes Codebeispiel schuldig, aber ich erkläre es zumindest. Du brauchst für jede Temperatur eine Persistence. Zusätzlich brauchst Du ein DateTime Item pro Temperatur, die wiederhergestellt werden soll. Auch dieses Item muss persistiert werden, und zwar mit mapDB (oder einer anderen Persistence, welche DateTime nativ unterstützt).

Wenn die Temperatur abgesenkt wird, merkst Du Dir im zugehörigen Item den Zeitpunkt (unbedingt bevor die Temperatur abgesenkt wird!). Wenn nun openHAB zwischendurch neu gestartet wird, stellt die Persistence Strategy restoreOnStartup den aktuellen Wert dieses Datetime Items wieder her. Damit ist der große Fehler oben Geschichte.
Wird das Fenster geschlossen, lässt Du per temperaturItem.sendCommand(temperaturItem.historicState(DateTimeItem.state as DateTimeType)) den alten Wert wiederherstellen. Kann gut sein, dass der Aufruf leicht anders ist, aber so ungefähr sollte es funktionieren.

Re: [Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 11. Jan 2021 18:06
von Eleven
Vielen Dank für deine schnelle Antwort.
Ich würde schon gerne die Lösung mit der Persistence umsetzen. Ich nutze schon für einige Aktoren die Restore on Startup Funktion, allerdings verstehe ich die Umsetzung nicht ganz!
Jeder Heizkörper bekommt 2 Persistence-Einträge. Einmal das item mit der aktuellen Ist-Temperatur und ein neu erstelltes Item, welches die Uhrzeit speichert bevor die Temperatur durch das öffnen des Fensters herabgesetzt wird. Sollte das System jetzt neu gestartet werden wird anhand des Zeit-Items die Temperatur zu der gespeicherten Uhrzeit am Thermostat wieder hergestellt? Habe ich das richtig verstanden?

Nun stelle ich mir die Frage wie das konfiguriert wird? Kannst du mir hierbei behilflich sein?

Vielen Dank schonmal im Voraus.
Leibe Grüße eleven

Re: [Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 11. Jan 2021 18:49
von udo1toni
Nein, es wird der Zeitstempel wiederhergestellt. Die Temperatur wird in dem Moment wieder hoch gesetzt, wo erkannt wird, dass das Fenster geschlossen wurde, und zwar von der Rule, die das entsprechende Kommando sendet. Natürlich muss die Solltemperatur genauso persistiert sein, und zwar unbedingt mindestens mit everyChange (alles andere on top ist dann egal, wichtig ist, dass die Änderungen unmittelbar gesichert werden).

Re: [Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 11. Jan 2021 18:57
von Eleven
Und wie generiere den Zeitstempel, bzw. wie konfiguriere ich das die Zeit gespeichert wird bevor sich die Temperatur verändert hat?

Re: [Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 11. Jan 2021 20:09
von udo1toni
Das müsste mit MeinDateTimeItem.postUpdate(now.toLocalTime) gehen.

Re: [Rule] Heizung steuern bei Änderung des Fenstersensors

Verfasst: 11. Jan 2021 20:36
von Eleven
Ich habe jetzt mal etwas herumprobiert. Ich habe angefangen für den Zeitstempel ein DateTime item anzulegen.

Code: Alles auswählen

DateTime                AZ_Zeitstempel                      "Zeitstempel: [%1$tm/%1$td %1$tH:%1$tM]"                         <calendar>
Im Anschluss habe einen Eintrag in der map.db für den Zeitstempel sowie die Solltemperatur des Heizkörpers eingerichtet:

Code: Alles auswählen

Strategies {
  default = everyUpdate
}

Items {
  AZ_Heizung_SetTemp : strategy = everyChange
  AZ_Zeitstempel : strategy = everyChange
}
Dann habe ich versucht den Zeitstempel bei öffnen des Fensters in die vorhandene Rule einzubauen und und nach dem schließen des Fensters diesen abzurufen.

Code: Alles auswählen

rule "Heizung Arbeitszimmer"
when
    Item AZ_Fenster_Status changed                             //	Triggere wenn der Fensterkontakt geschaltet hat
then
    if(AZ_Fenster_Status.state != CLOSED) {                    // Fenster offen oder nicht initialisiert?
        postUpdate(AZ_Zeitstempel, new DateTimeType()) // erstelle Zeitstempel
        AZ_Heizung_SetTemp.sendCommand(tempOff)  
        logInfo("Heizung", "Fenster im Arbeitszimmer geöffnt und Heizkörper abgedreht")
        fenstertimer = createTimer(now.plusMinutes(10), [|      // Starte Timer für Meldung
            sendPushoverMessage(pushoverBuilder("Info, Fenster Arbeitszimmer 10 Min. geöffnet").withDevice("iPhoneXR"))
            fenstertimer = null 
        ])                                                      // Lambda in die Funktion verschoben, Lesbarkeit des Codes
    } else {                                                    // Fenster ist geschlossen!
        AZ_Heizung_SetTemp.sendCommand(AZ_Heizung_SetTemp.historicState(AZ_Zeitstempel.state as DateTimeType)) 
        //AZ_Heizung_SetTemp.sendCommand(tempComfort)
        logInfo("Heizung", "Fenster im Arbeitszimmer geschlossen und Heizkörper aufgedreht") 
        if(fenstertimer !== null) {                             // Timer läuft?
            fenstertimer.cancel                                 // Timer abbrechen
            fenstertimer = null 
        }
    }
end
Bei dem Befehl für das schließen komme ich nicht weiter.

Code: Alles auswählen

AZ_Heizung_SetTemp.sendCommand(AZ_Heizung_SetTemp.historicState(AZ_Zeitstempel.state as DateTimeType)) 
vscode zeigt mir für diesen Eintrag zwei Fehlermeldungen an:

Type mismatch: cannot convert from HistoricItem to Command
Type mismatch: cannot convert from DateTimeType to AbstractInstant

Was mache ich falsch?
Der Zeitstempel wird auf jeden Fall gesetzt. Reicht es aus, das ich diesen vor dem Eintrag der Temperaturveränderung gesetzt habe?
Sind die Persistencen richtig eingerichtet?


Grüße Eleven