Es gibt ein paar grundsätzliche Fehler in Deiner Rule, ein paar unschöne Details und ein paar Stellen, an denen der Code eventuell inkompatibel sein kann. Der Reihe nach...
Grundsätzliche Fehler: Der Vergleich === ist hier verkehrt. Eigentlich dürfte das noch nie korrekt funktioniert haben.
Bedeutung:
- = -> Wertzuordnung. a = b -> a nimmt den Wert von b an (soweit möglich...)
- == -> Vergleich auf Gleichheit. a == b -> wahr, falls der Wert in a dem Wert in b entspricht, z.B. a = 3 -> a == 3 liefert wahr
- === -> Vergleich auf Identität. a === b -> wahr, wenn a mit b identisch ist.
Dieser Vergleich ist gewöhnlich nur mit null sinnvoll (bitte nicht mit NULL verwechseln) a === null -> wahr, falls der Variablen a noch kein Wert zugewiesen wurde, denn dann zeigt der Zeiger der Variablen a auf null (ein definierter Platz im Speicher, extra für diesen Zweck)
Unschöne Details:
Du triggerst die Rule mit
changed, nutzt aber anschließend
Temperature_GEG_Living.state als Wert. Das mag zu über 99 % gut gehen, kann aber auch schief gehen. Besser ist es, die implizite Variable
newState zu verwenden.
Action
sendCommand(Itemname, Wert): kann man machen, ist aber nicht gut. Besser: Methode
Itemname.sendCommand(Wert). Der Unterschied ist hier (in dieser Rule) nicht wichtig, an anderen Stellen führt die Action aber zu Problemen, welche mit der Methode nicht auftreten. Allgemein wird die Methode empfohlen.
Casting ohne vorherige Prüfung (
as DecimalType): Kann man machen, kann aber schief gehen. Fehlerquelle besser abfangen.
Diverse Contact Items: Hier böte sich eine Zusammenfassung in einer Gruppe an. Mutmaßlich handelt es sich um alle Fenster eines Raumes, man könnte also ein GroupItem definieren:
und man weist jedes der Contact Items (des Wohnzimmers) dieser Gruppe zu. Anschließend muss man nur dieses eine Item auf den Zustand OPEN/CLOSED prüfen.
Anordnung der Befehle ungünstig, dadurch viel unnötiger oder gar gedoppelter Code.
Die Einrückungen sind teilweise "falsch" (siehe unten)
Mögliche Inkompatibilität:
Wie sind die Items definiert? Insbesondere interessant bei den Items, in denen die Temperaturwerte gespeichert sind. Falls Du hier inzwischen
QuantityType Items verwendest (
Number:Temperature), ist das schon mal der wichtigste Punkt. Wenn das Item den Status
21.5 liefert, ist das etwas anderes als der Status
21.5 °C. Da lohnt ein kurzer Blick ins log (Suche nach einem changed Ereignis der Items).
So sähe Deine Rule "besser" aus:
Code: Alles auswählen
rule "Heizung Wohn- und Esszimmer"
when
Item Temperature_GEG_Living changed
then
if(!(newState instanceof Number)) { // Sensorwert prüfen
logWarn("heating","Temperature_GEG_Living liefert keine gültige Zahl!")
return; // Ausführung abbrechen
}
var Number Ist_EG_Living = (newState as Number).floatValue // Wert als Zahl ohne Einheit zuweisen
if(!(Sollwerte_Living.state instanceof Number)) { // Sollwert prüfen
logWarn("heating","Sollwerte_Living liefert keine gültige Zahl!")
return; // Ausführung abbrechen
}
var Number Soll_EG_Living = (Sollwerte_Living.state as Number).floatValue // Default Verhalten kein Urlaub
if(Urlaubsreise.state == ON) { // Falls Urlaub aktiv Sollwert ändern
if(Sollwerte_Living_Urlaub.state instanceof Number) // Aber nur, wen ndas auch geht...
Soll_EG_Living = (Sollwerte_Living_Urlaub.state as Number).floatValue
else
logWarn("heating","Urlaub aktiv, aber Sollwert ungültig! Nutze normalen Sollwert.")
}
if(gWindow_GEG_Living.state == OPEN) { // mindestens einer der Kontakte meldet OPEN
Heating_GEG_Living.sendCommand(OFF)
return;
}
if(Shutter_ALLG_Heizung_Sommerbetrieb.state == ON) { // Heizung ist aus
Heating_GEG_Living.sendCommand(OFF)
return;
}
if((Urlaubsreise.state == OFF && Heizschalter_Living.state == ON) || Urlaubsreise.state == ON) { // (Anwesend und Raumheizung an) oder Abwesend
if(Ist_EG_Living < Soll_EG_Living - 0.5) // Soll um mindestens 0.5 unterschritten
Heating_GEG_Living.sendCommand(ON)
else if(Ist_EG_Living > Soll_EG_Living) // Soll überschritten
Heating_GEG_Living.sendCommand(OFF)
} else // Anwesend aber Raumheizung aus
Heating_GEG_Living.sendCommand(OFF)
end
Die Einrückungen sind optional, sie haben keinerlei Einfluss auf die Ausführung des Codes, verbessern aber die Lesbarkeit. Wichtig ist aber, die Einrückungen immer konsistent auszuführen, also alle Befehle einer Ebene sollten auch gleich eingerückt sein.
Die Kommentare helfen, (viel) später noch zu verstehen, was der Code machen soll.
Bei erkanntem Fehler kommt keine NullPointerException, sondern eine vernünftige Meldung.
Mit dem verfrühten Abbruch der Ausführung (return;) wird die Tiefe der Schachtelung minimiert -> bessere Lesbarkeit des Codes.
Mutmaßlich hast Du so eine oder so eine ähnliche Rule für jeden Raum. Sinnvoller wäre es, die Rule für alle Räume gemeinsam zu haben. D.h. Du hast nur eine Rule, diese kümmert sich dann um alle Räume, wobei der Code nicht viel länger werden muss, wichtig ist dann aber, dass die Items gut strukturiert sind (scheint schon der Fall zu sein) und alle "gleichartige" Items gruppiert sind. Die Rule triggert dann auf die Änderung eines Gruppenmembers der Temperaturen. Die Rule bestimmt, um welchen Raum es sich handelt (geht ja aus dem Namen des triggernden Items hervor) und sucht sich daraufhin alle Items zusammen, welche im Durchlauf verwendet werden müssen. Das sind im Zweifel nur ein paar Zeilen Code zusätzlich in dieser einen Rule, aber das ist dann auch die einzige Rule (also jedem Menge Ersparnis durch Wegfall der anderen Rules)
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet