1. Fehler: Der Itemname
GF_3LivingRoom_Battery ist doppelt vergeben

2. Fehler: Du vergleichst die Status zweier Items miteinander. Das geht so aber nicht.
Der Hintergrund ist: Ein Status ist ein Status, kein Text, keine Zahl.
openHAB versucht, anhand des Kontext automatisch die Datentypen zu konvertieren, hier gibt es aber keinen Kontext (beide Seiten sind schwach typisiert), entsprechend weiß openHAB nicht, was es tun soll.
Es reicht, openHAB einen bestimmten Datentyp aufzuzwingen (an dieser Stelle per Type Casting):
Code: Alles auswählen
rule "Temperaturregelung Wohnzimmer"
when
Item GF_011LivingRoom_Temperature changed
then
if ((GF_LivingRoom_Temperature.state as Number) < (GF_11LivingRoom_SetPoint.state as Number)) { // Hier kannst du den Regler aktivieren, um die Heizung zu erhöhen
GF_LivingRoom_Target.sendCommand(5.0) // Beispielwert, um die Heizung zu aktivieren
} else if ((GF_LivingRoom_Temperature.state as Number) > (GF_11LivingRoom_SetPoint.state as Number)) { // Hier kannst du den Regler deaktivieren, um die Heizung zu senken
GF_LivingRoom_Target.sendCommand(5.0) // Beispielwert, um die Heizung zu deaktivieren
}
end
Das ist aber nicht "schön".
3. Fehler: Die Target-Werte sollten sich vermutlich unterscheiden

4. "Fehler": Du verwendest das
Item changed Ereignis, greifst aber auf
Item.state zu, statt die implizite lokale Konstante
newState zu nutzen.
Streng genommen ist das kein Fehler, aber es gibt Unsicherheiten, weil nicht garantiert werden kann, dass der Status des Items zum Zeitpunkt der Ausführung der Rule noch dem Wert entspricht, der zum Triggern der Rule geführt hat. newState hingegen enthält genau diesen Wert.
Außerdem ist der Code, wie oben erwähnt, nicht "schön.
Besser:
Code: Alles auswählen
rule "Temperaturregelung Wohnzimmer"
when
Item GF_011LivingRoom_Temperature changed
then
if(!(newState instanceof Number)) return; // kein gültiger Wert? Dann Abbruch
if(!(GF_11LivingRoom_SetPoint.state instanceof Number)) return; // kein gültiger Wert? Dann Abbruch
val nIst = (newState as Number).floatValue // Istwert in lokale Konstante überführen
val nSoll = (GF_11LivingRoom_SetPoint.state as Number).floatValue // Sollwert in lokale Konstante überführen
if (nIst < nSoll - 0.1) // Vergleich kleiner mit Hysterese
GF_LivingRoom_Target.sendCommand(nSoll) // Falls unterschritten, Sollwert übernehmen
else if (nIst > nSoll + 0.1) // Vergleich größer mit Hysterese
GF_LivingRoom_Target.sendCommand(5) // Falls überschritten, 5 übernehmen
end
Die Regelung hat eine Hysterese eingebaut (+/- 0.1), um allzu hektisches Verhalten zu verhindern.
Ich vermute allerdings, das Du nicht nur ein Wohnzimmer hast. Daraus ergibt sich der Verdacht

dass Du mehrere weitgehend identische Rules hast, für jeden Raum eine Rule, und natürlich entsprechend viele Items.
Die saubere Variante wäre hier, die Rule so anzulegen, dass sie sich um alle Items kümmern kann. Das sind nur leicht andere Codezeilen, wenn die Itemnamen besser gewählt sind und man noch ein paar Group Items ergänzt.
Aber zunächst noch mal zu den Items: Wenn Du eine aktuelle Version von openHAB einsetzt, verpasst Du eine Chance

nämlich, dass openHAB sich um die Einheiten selbst kümmert. Das läuft unter der Abkürzung UoM (Unit of Measurement, bzw. QuantityType). Damit das korrekt funktioniert, müssen ein paar Randbedingungen erfüllt sein, insbesondere muss das verlinkte Addon den Wert korrekt übergeben (das sollte inzwischen mit praktisch jedem Addon funktionieren, welches auch nur entfernt dafür geeignet ist). Weiterhin muss der Itemtyp korrekt gewählt sein und die Metadaten des Items sollten ebenfalls passend gesetzt sein. Z.B. Temperatur. Statt alt
Code: Alles auswählen
Number GF_LivingRoom_Temperature "Wohnzimmer Heizung[%.1f °C]" <temperature> (GF_LivingRoom, gTemperature) {channel="homematic:HmIP-eTRV-B:3014F711A061A7DBE997618D:002018A997433D:1#ACTUAL_TEMPERATURE"}
neu
Code: Alles auswählen
Number:Temperature GF_LivingRoom_Temperature "Wohnzimmer Heizung" <temperature> (GF_LivingRoom, gTemperature) {channel="homematic:HmIP-eTRV-B:3014F711A061A7DBE997618D:002018A997433D:1#ACTUAL_TEMPERATURE",stateDescription=""[pattern="%.1f °C"],unit="°C"}
Die
stateDescription beschreibt, wie ein Wert dargestellt werden soll, das pattern entspricht dem, was man früher im Label übergeben hat.
Die
unit legt fest, in welchem Format der Wert im Item gehalten wird, hier also in °C. Man könnte z.B. auch K oder °F angeben, dann wird openHAB den Wert entsprechend umrechnen, bevor es den Wert im Item ablegt. Diesen Parameter darf man nur einmal einstellen, weil er Auswirkungen auf die Persistence hat. Verändert man nachträglich die unit, so ist die Historie des Items fehlerhaft und Charts zeigen in der Folge falsche Wertverläufe an.
Das gilt sinngemäß auch für alle anderen numerischen Items (mit passenden QuantityTypes und units).
Wenn Du mehrere gleichartige Geräte hast (hier Thermostate und Heizkörperventile) und diese über Rules verknüpfen willst, solltest Du die Namen so gestalten, dass man Beziehungen untereinander aus dem Namen ableiten kann (hier z.B.
GF_LivingRoom_Temperature,
GF_LivingRoom_Target und
GF_LivingRoom_SetPoint, die 11 sollte da weg.)
Wenn Du dann noch jeweils ein Group Item pro Typ anlegst (also z.B.
gTempIs,
gTarget,
gSetPoint) kannst Du die Rule von oben so abwandeln:
Code: Alles auswählen
rule "Temperaturregelung"
when
Member of gTempIs changed
then
if(!(newState instanceof Number)) return; // kein gültiger Wert? Dann Abbruch
val strInstance = triggeringItem.name.split("_").get(1) // Teilstring zwischen 1. und 2. Unterstrich
val Target = gTarget.members.filter[i|i.name.contains(strInstance)].head // Target ermitteln
val SetPoint = gSetPoint.members.filter[i|i.name.contains(strInstance)].head // SetPoint ermitteln
if(!(SetPoint.state instanceof Number)) return; // kein gültiger Wert? Dann Abbruch
val nIst = (newState as Number).floatValue // Istwert in lokale Konstante überführen
val nSet = (SetPoint.state as Number).floatValue // Sollwert in lokale Konstante überführen
var nSoll = 5.0 // Default Frostschutz
if(nIst < nSet - 0.1) nSoll = nSet // Falls Ist kleiner Set, Soll=Set
if((Target.state as Number) != nSoll) // Falls Target von Soll abweicht
Target.sendCommand(nSoll) // Sollwert übernehmen
end
Im Vergleich zur alten Rule enthält diese Rule nur zwei zusätzliche Zeilen, um die Items zu ermitteln, die benötigt werden. Diese Rule steuert aber ALLE Räume, zu denen die drei Items in den drei Gruppen existieren. Wichtig ist nur, dass der Teilstring für alle Items eindeutig und jeweils identisch ist. Die Rule muss nicht mehrfach angelegt werden, der Aufwand lohnt sich also schon bei zwei zu steuernden Räumen.
Außerdem sendet diese Rule den Steuerbefehl nur bei Bedarf, nicht bei jedem Durchlauf außerhalb des Hysteresefensters (das könnte man natürlich oben auch einbauen...).
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet