Globale Variablen und Funktionen
-
- Beiträge: 7
- Registriert: 29. Nov 2023 19:08
Globale Variablen und Funktionen
Ich habe einige DSL Rules angelegt und würde in diesen gerne globale Variablen und Funktionen verwenden, Wie geht das?
Zum Hintergrund: Wir befinden uns zu bestimmten Zeiten in bestimmten Räumen. Änderungen betreffen in der Regel gleich mehrere Räume.
Das habe ich durch Zustände umgesetzt: Morgens, Mittags und Abends, bei deren Wechsel Regler neu eingestellt werden. Die Zustände können automatisch nach der Zeit oder auch manuell umgeschaltet werden.
Nun gibt es zusätzlich noch Sonderzustände, wie "NichtDa" etc. Hierbei wird die Temperatur heruntergeregelt. Nach der Rückkehr sollte die Temperaturen gesetzt werden, die normalerweise eingestellt wären.
Ich würde mir nun die eingestellten Temperaturen in globalen Variablen merken und bei der Rückkehr verwenden. Um nicht massenhaft redundanten Code zu erzeugen, würde ich alles über die Variablen laufen lassen und eine Funktion schreiben, die die Regler auf die Werte der Variablen setzt.
Wie geht das in den DSL-Rules? Da werden ja einzelne Rules definiert. Wohin kommt der globale kram?
Zum Hintergrund: Wir befinden uns zu bestimmten Zeiten in bestimmten Räumen. Änderungen betreffen in der Regel gleich mehrere Räume.
Das habe ich durch Zustände umgesetzt: Morgens, Mittags und Abends, bei deren Wechsel Regler neu eingestellt werden. Die Zustände können automatisch nach der Zeit oder auch manuell umgeschaltet werden.
Nun gibt es zusätzlich noch Sonderzustände, wie "NichtDa" etc. Hierbei wird die Temperatur heruntergeregelt. Nach der Rückkehr sollte die Temperaturen gesetzt werden, die normalerweise eingestellt wären.
Ich würde mir nun die eingestellten Temperaturen in globalen Variablen merken und bei der Rückkehr verwenden. Um nicht massenhaft redundanten Code zu erzeugen, würde ich alles über die Variablen laufen lassen und eine Funktion schreiben, die die Regler auf die Werte der Variablen setzt.
Wie geht das in den DSL-Rules? Da werden ja einzelne Rules definiert. Wohin kommt der globale kram?
- udo1toni
- Beiträge: 15244
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Globale Variablen und Funktionen
Herzlich willkommen im openHAB Forum!
Globale Variablen werden innerhalb der rules-Datei definiert, in der auch alle Rules stehen, welche auf die Variablen zugreifen sollen. In UI Rules musst Du SharedCache dafür verwenden.
ABER: Schon die Idee mit den Funktionen ist vermutlich der falsche Weg. (im Sinne von umständlich, nicht wie man das in openHAB löst).
Zunächst einmal gibt es in DSL Rules keine richtigen Funktionen. Du kannst Lambdas definieren (mittels globaler Variablen...) und diese dann per funktion.apply(werteliste) aufrufen, aber wie gesagt, das ist nicht unbedingt die richtige Lösung.
Stattdessen solltest Du versuchen, eine Rule zu erstellen, welche generalisiert ist. Die Rule kann dann z.B. auf die Member einer Group triggern und abhängig vom Itemnamen andere Items aus anderen Groups manipulieren. Beispiel:
Ich habe knx RTR (RaumTemperaturRegler) welche als Status ein Byte senden, wobei Bit 0 "Komfort", Bit 1 "Standby", Bit 2 "Nacht" und Bit 3 "Frostschutz" bedeuten. Weitere höherwertig Bits stehen für Heizen und Kühlen und noch irgendwas anderes
Gesteuert wird aber mit den Werten 1 bis 4 (von 1 = Komfort bis 4 = Frostschutz). Die Rückmeldung für den Zustand ist also eine andere als der Befehl, dafür brauche ich eine Rule:
Sobald eine Änderung des Zustands gemeldet wird, löst die Rule aus, Es wird der aktuelle Zustand ermittelt, anschließend wird das zugehörige Item für die Steuerung auf diesen Zustand geschaltet. Es ist unerheblich, wie viele RTR ich habe, ich muss nur jeweils zwei Items haben, eines "ankommend" und ein zweites "abgehend", die den beiden Gruppen gHeat_Mode und gHeat_Set angehören, mit der Maßgabe, dass jeweils der erste Namensteil des Itemnamens identisch ist, bis zum ersten Unterstrich im Itemnamen, meinetwegen Wohnzimmer_Mode und Wohnzimmer_SetMode wäre so ein Itempaar. Die implizite Variable triggeringItem enthält ein Objekt, welches eine lokale Kopie des triggernden Items enthält (weil über Member of getriggert wurde). triggeringItem.name enthält also z.B. dann den String Wohnzimmer_Mode, aus dem der erste Teil in der Variablen iName landet.
Anschließend wird das passende Item aus der andere Gruppe herausgesucht und schlussendlich wird der neue Status in dieses Item geschrieben.
Ich brauche exakt diese eine Rule für wie viele RTR auch immer, ganz ohne Funktionen (in diesem Fall sogar ohne globale Variable)
Eine Abbildung der Tageszeit (Morgens, Mittags, Abends) böte sich als Item an, dann kann man bequem in jeder Rule darauf zugreifen, genau wie der Abwesend Status (den man vielleicht auch automatisch ermitteln kann, z.B. anhand aller im WLAN eingeloggten Smartphones, In Reichweite befindliches Fahrzeug, ausgelöste Sensoren an Türen usw.)
Globale Variablen werden innerhalb der rules-Datei definiert, in der auch alle Rules stehen, welche auf die Variablen zugreifen sollen. In UI Rules musst Du SharedCache dafür verwenden.
ABER: Schon die Idee mit den Funktionen ist vermutlich der falsche Weg. (im Sinne von umständlich, nicht wie man das in openHAB löst).
Zunächst einmal gibt es in DSL Rules keine richtigen Funktionen. Du kannst Lambdas definieren (mittels globaler Variablen...) und diese dann per funktion.apply(werteliste) aufrufen, aber wie gesagt, das ist nicht unbedingt die richtige Lösung.
Stattdessen solltest Du versuchen, eine Rule zu erstellen, welche generalisiert ist. Die Rule kann dann z.B. auf die Member einer Group triggern und abhängig vom Itemnamen andere Items aus anderen Groups manipulieren. Beispiel:
Ich habe knx RTR (RaumTemperaturRegler) welche als Status ein Byte senden, wobei Bit 0 "Komfort", Bit 1 "Standby", Bit 2 "Nacht" und Bit 3 "Frostschutz" bedeuten. Weitere höherwertig Bits stehen für Heizen und Kühlen und noch irgendwas anderes

Gesteuert wird aber mit den Werten 1 bis 4 (von 1 = Komfort bis 4 = Frostschutz). Die Rückmeldung für den Zustand ist also eine andere als der Befehl, dafür brauche ich eine Rule:
Code: Alles auswählen
rule "Betriebsart RTR"
when
Member of gHeat_Mode changed
then
var Integer newMode = 2
val mode = (triggeringItem.state as DecimalType).toBigDecimal.toBigInteger
val iName = triggeringItem.name.split("_").get(0).toString
logDebug("rtr","Name is: {}, Mode is: {}",iName,mode)
switch (mode) {
case mode.testBit(0) : newMode = 1
case mode.testBit(2) : newMode = 3
case mode.testBit(3) : newMode = 4
}
var myItem = gHeat_Set.members.filter[ f | f.name.startsWith(iName) ].head
var Integer oldMode = 0
if(myItem.state instanceof Number) oldMode = (myItem.state as Number).intValue
if(oldMode != newMode) {
logDebug("rtr","Name is: {}, oldMode is: {}, newMode is: {}",myItem.name,oldMode,newMode)
myItem.postUpdate(newMode)
}
end
Anschließend wird das passende Item aus der andere Gruppe herausgesucht und schlussendlich wird der neue Status in dieses Item geschrieben.
Ich brauche exakt diese eine Rule für wie viele RTR auch immer, ganz ohne Funktionen (in diesem Fall sogar ohne globale Variable)
Eine Abbildung der Tageszeit (Morgens, Mittags, Abends) böte sich als Item an, dann kann man bequem in jeder Rule darauf zugreifen, genau wie der Abwesend Status (den man vielleicht auch automatisch ermitteln kann, z.B. anhand aller im WLAN eingeloggten Smartphones, In Reichweite befindliches Fahrzeug, ausgelöste Sensoren an Türen usw.)
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet
-
- Beiträge: 7
- Registriert: 29. Nov 2023 19:08
Re: Globale Variablen und Funktionen
Vielen Dank für die ausführliche Antwort. Zustände wie NichtDa, Heizungstests etc erfordern eine Sonderrolle. Werden sie ausgeschaltet, hängt die Temperatur vom Hauptzustand ab. Ich würde deshalb gerne einen Schattenmechanismus haben, bei dem die Werte zunächst in globale Variablen geschrieben werden. Falls kein Sonderzustand aktiv ist, werden sofort die Regler gesetzt. Ansonsten sollte das Deaktivieren die Übernahme der Sonderwerte in die Regler bewirken. Hier wäre eine Funktion WriteTemperaturefromVratiables ganz nützlich.
Da meine Javascript-Kenntnisse oberflächlich sind, würde ich das gerne möglichst in DSLRules realisieren, da ich dann selbst keine Eventmechanismen zu schreiben brauche. Bislang nutze ich einfach Rules mit "excecute a given script",
Die Frage ist nun, wie realisiert man die globalen Funktionen und Variablen bei Verwendung der Rules. Ich vermute mal, dass alles was in "excecute a given script" stehlt, lokal ist.
Es wäre auch praktisch, wenn der Fokus nicht auf den Reglern, sondern auf den Zuständen liegt, da dann Änderungen der Wohlfühltemperaturen an einer Stelle vorgenommen werden können.
Da meine Javascript-Kenntnisse oberflächlich sind, würde ich das gerne möglichst in DSLRules realisieren, da ich dann selbst keine Eventmechanismen zu schreiben brauche. Bislang nutze ich einfach Rules mit "excecute a given script",
Die Frage ist nun, wie realisiert man die globalen Funktionen und Variablen bei Verwendung der Rules. Ich vermute mal, dass alles was in "excecute a given script" stehlt, lokal ist.
Es wäre auch praktisch, wenn der Fokus nicht auf den Reglern, sondern auf den Zuständen liegt, da dann Änderungen der Wohlfühltemperaturen an einer Stelle vorgenommen werden können.
- udo1toni
- Beiträge: 15244
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Globale Variablen und Funktionen
Die einfachste Lösung dafür dürfte sein, den Sollwert in ein zweites Item zu schreiben, aus dem dann der Wert bei Bedarf übernommen wird.
Ein anderer Ansatz wäre, die jeweiligen Sollwerte als Metadaten ins Item zu schreiben. Je nach Zustand werden dann die Werte aus den Metadaten übernommen.
Nachteilig daran ist, dass die DSL mit Metadaten nicht umgehen kann, das ginge also nur über eine andere Script Engine, wie z.B. JavaScript
Ich habe z.B. eine Sitemap für mein Haus. Dort habe ich eine Seite, auf der alle RTR abgebildet sind, dort kann ich alle RTR zentral (aber einzeln) steuern. Weiterhin habe ich Raumansichten, in jedem Raum mit RTR taucht also genau der passende RTR auf, den ich auch dort steuern kann. Automatikprogramme steuern ohnehin alle Gebäudeteile ohne Einschränkungen nach meinen Vorgaben.
Ein anderer Ansatz wäre, die jeweiligen Sollwerte als Metadaten ins Item zu schreiben. Je nach Zustand werden dann die Werte aus den Metadaten übernommen.
Nachteilig daran ist, dass die DSL mit Metadaten nicht umgehen kann, das ginge also nur über eine andere Script Engine, wie z.B. JavaScript

Wie meinen? Das Eine hat doch mit dem Anderen gar nichts zu tun?
Ich habe z.B. eine Sitemap für mein Haus. Dort habe ich eine Seite, auf der alle RTR abgebildet sind, dort kann ich alle RTR zentral (aber einzeln) steuern. Weiterhin habe ich Raumansichten, in jedem Raum mit RTR taucht also genau der passende RTR auf, den ich auch dort steuern kann. Automatikprogramme steuern ohnehin alle Gebäudeteile ohne Einschränkungen nach meinen Vorgaben.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet
-
- Beiträge: 7
- Registriert: 29. Nov 2023 19:08
Re: Globale Variablen und Funktionen
Es geht mir um Komfort und Einfachheit. Deshalb wollte ich alle Temperaturen in die Zustandsregeln schreiben.
Wenn ich Deinen Ansatz Recht verstehe, würde man bei Deinem Ansatz den Reglern den Zustand mitteilen und die würden die Temperatur wählen. Das wollte ich vermeiden
Wenn ich Deinen Ansatz Recht verstehe, würde man bei Deinem Ansatz den Reglern den Zustand mitteilen und die würden die Temperatur wählen. Das wollte ich vermeiden
-
- Beiträge: 7
- Registriert: 29. Nov 2023 19:08
Re: Globale Variablen und Funktionen
Kann ich trotz der Verwendung von den Regeln statt Javascript irgendwie eine Globale Funktion platzieren? Würde massig redundanten Code sparen
- udo1toni
- Beiträge: 15244
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Globale Variablen und Funktionen
Nein, mein Ansatz ist, eine Rule anzulegen, die die Sollwerte nach Vorgabe setzt. Dabei orientiert sie sich an den Vorgaben und tut dies für alle Räume, für die dies angefordert wird.
Es braucht keinerlei redundanten Code dafür, nur etwas Erfahrung im Umgang mit openHAB. Siehe obiges Beispiel, eine Rule für beliebig viele RTR (und es ist wirklich exakt diese eine Rule, nicht etwa zig Kopien dieser Rule)
Es braucht keinerlei redundanten Code dafür, nur etwas Erfahrung im Umgang mit openHAB. Siehe obiges Beispiel, eine Rule für beliebig viele RTR (und es ist wirklich exakt diese eine Rule, nicht etwa zig Kopien dieser Rule)
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet
-
- Beiträge: 7
- Registriert: 29. Nov 2023 19:08
Re: Globale Variablen und Funktionen
Um die Redundanz deutlich zu machen, hier mal der Code einer Rule:
Es gibt eine zweifach Redundanz. Zum einen funktioniert die Übertragung zur Livisi Zentrale nicht zuverlässig, Das System wird ja leider nicht mehr gewartet und ist nicht dafür gedacht, mehrere Änderungen in kurzer Zeit über die Api vorzunehmen. Zum Anderen kommt zukünftig der der SchattenSchattenmechanismus, bei dem im Falle eines Sonderzustands die Temperaturen erst in Variablen gesetzt werden und später übertragen werden.
Was mir ganz wichtig ist, dass die Tempearturen für alle Regler in den Regeln für den Zustandswechsel zusammenhängend für alle Regler vorgenommen wird. Meine Vorgehensweise wäre
1) Temparaturen in globale Variablen (Items) zu schreiben
2) Gleich oder nach Ende des Sonderzustands zweifach an Livisi zu übertragen.
Ich suche eine Funktion, die die globalen Variablen an alle Regler herausschreibt.
Ergänzend muss ich sagen, dass ich Openhab praktisch nicht als Oberfläche, sondern als automatische Scripting Engine nutze. Die manuelle Steuerung erfolgt über Alexa.
Code: Alles auswählen
configuration: {}
triggers:
- id: "1"
configuration:
itemName: VariableActuatorMorgens_Status
state: ON
type: core.ItemStateChangeTrigger
conditions:
- inputs: {}
id: "2"
configuration:
itemName: VariableActuatorWeggehen_Status
state: ON
operator: "!="
type: core.ItemStateCondition
actions:
- inputs: {}
id: "2"
configuration:
type: application/vnd.openhab.dsl.rule
script: >+2
VariableActuatorAbends_Status.sendCommand("OFF")
Thread::sleep(500);
VariableActuatorNachmittags_Status.sendCommand("OFF")
Thread::sleep(500);
Wohnzimmer_Solltemperatur.sendCommand("20");
Thread::sleep(500);
Bibliothek_Solltemperatur.sendCommand("18");
Thread::sleep(500);
RSTHeizkorperthermostat1Schlafzimmer_Solltemperatur.sendCommand("20");
Thread::sleep(500);
RSTSpielzimmerDaddelbar_Solltemperatur.sendCommand("18");
Thread::sleep(500);
RST_HeizkorperthermostatKuecheNeu_Solltemperatur.sendCommand("18");
Thread::sleep(500);
RSTHeizkorperthermostatToiletteToilette_Solltemperatur.sendCommand("9");
Thread::sleep(500);
RSTHeizkorperthermostat1Bad_Solltemperatur.sendCommand("18");
Thread::sleep(500);
VariableActuatorAbends_Status.sendCommand("OFF")
Thread::sleep(500);
VariableActuatorNachmittags_Status.sendCommand("OFF")
Thread::sleep(500);
Wohnzimmer_Solltemperatur.sendCommand("20");
Thread::sleep(500);
Bibliothek_Solltemperatur.sendCommand("18");
Thread::sleep(500);
RSTHeizkorperthermostat1Schlafzimmer_Solltemperatur.sendCommand("20");
Thread::sleep(500);
RSTSpielzimmerDaddelbar_Solltemperatur.sendCommand("18");
Thread::sleep(500);
RST_HeizkorperthermostatKuecheNeu_Solltemperatur.sendCommand("18");
Thread::sleep(500);
RSTHeizkorperthermostatToiletteToilette_Solltemperatur.sendCommand("9");
Thread::sleep(500);
RSTHeizkorperthermostat1Bad_Solltemperatur.sendCommand("18");
Thread::sleep(500);
type: script.ScriptAction
Was mir ganz wichtig ist, dass die Tempearturen für alle Regler in den Regeln für den Zustandswechsel zusammenhängend für alle Regler vorgenommen wird. Meine Vorgehensweise wäre
1) Temparaturen in globale Variablen (Items) zu schreiben
2) Gleich oder nach Ende des Sonderzustands zweifach an Livisi zu übertragen.
Ich suche eine Funktion, die die globalen Variablen an alle Regler herausschreibt.
Ergänzend muss ich sagen, dass ich Openhab praktisch nicht als Oberfläche, sondern als automatische Scripting Engine nutze. Die manuelle Steuerung erfolgt über Alexa.
- udo1toni
- Beiträge: 15244
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Globale Variablen und Funktionen
Warum hältst Du so krampfhaft an Variablen fest? Aber meinetwegen...
Globale Variablen (so wie Du sie suchst) gehen nur über Textdateien. Du musst die Rules in Dateien anlegen, die sich im Verzeichnis $OPENHAB_CONF/rules/ befinden müssen. Keine Unterverzeichnisse, Dateiname enthält bitte keine Sonderzeichen und endet mit .rules
Alle Dateien, die auf global definierte Variablen zugreifen sollen müssen sich in der selben Datei befinden.
Beispiel:
Du hast eine Gruppe gSolltemperatur, in der sich alle Items befinden, an die Du eine Solltemperatur senden möchtest.
Code:
Da VariableActuatorAbends_Status und VariableActuatorNachmittags_Status mutmaßlich nicht an Livisi Channel gebunden sind, braucht es hier vermutlich weder ein sendCommand() noch ein Thread.sleep()
Es wäre sinnvoll, zunächst die Itemnamen zu vereinfachen. Ein typisches Schema wäre Raum_Funktion, wobei Raum eventuell auch noch einen Zähler enthalten kann, wenn mehrere gleichartige Geräte innerhalb des selben Raums vorhanden sind (also z.B. mehrere Heizkörperthermostate, die individuell angesteuert werden müssen)
Da das zweimalige Schreiben aller Werte vergleichsweise umständlich ist, habe ich oben der Einfachheit halber ebenfalls auf Redundanz gesetzt
aber Du siehst, dass es sich nur um vier doppelte Zeilen handelt.
Der Punkt ist aber, die selbe (!) Rule kann sich zusätzlich noch um alle anderen Temperaturen kümmern.
Ein Punkt dabei wäre, statt einzelner Switch Items für den Zustand Morgens, Abends, Nachmittags lieber ein String oder Number Item zu verwenden, damit sparst Du noch weiteren Code. Entweder Morgens oder Abends oder Nachmittags, keiner der Zustände kann zeitgleich auftreten, also braucht es auch nur ein Item dafür, z.B. Tageszeit (ein weiterer Tipp wäre, unnötige Informationen ebenfalls zu vermeiden, also z.B. auf Begriffe wie Variable und Status zu verzichten. Und die Tageszeit ist vermutlich auch keine Eigenschaft eines Aktuators.
In einer ersten Optimierung ergäbe sich also:
Nun Stelle Dir aber bitte vor, Du hast weitere (ungebundene) Items für die verschiedenen Temperaturen (pro Raum, versteht sich), und zwar folgenderrmaßen:
gSolltemperatur ist die übergeordnete Gruppe (alle nachfolgenden Items befinden sich in dieser Gruppe) pro Raum mehrere Items in der Form
Wohnzimmer_Solltemperatur, Wohnzimmer_SollMorgen, Wohnzimmer_SollMittag, Wohnzimmer_SollAbend, Wohnzimmer_SollSchatten
Nun die Rule dazu:
Du hast nun keine globalen Variablen mehr, sondern speicherst die konkreten Sollwerte in Items. Weil alle Items in der selben Gruppe liegen, muss die Gruppe beim Zugriff jeweils gefiltert werden, wahlweise kann man hier auch mit getrennten Gruppen arbeiten, das spielt aber unterm Strich keine Rolle. Wichtig ist nur, dass die Itemnamen passend gewählt sind. Die Solltemperaturen pro Zustand müssen nur einmalig festgelegt werden, dazu nutzt Du eine Persistence, um den letzten Wert beim Neustart des Systems wiederherzustellen (MapDB ist da das beste). Du kannst auch in der UI passende Ansichten gestalten, um die Solltemperaturen bei Bedarf anzupassen.
Alternativ definierst Du eine Rule, welche beim Systemstart die Sollwerte aus einer HashMap in die passenden Items schreibt.
Globale Variablen (so wie Du sie suchst) gehen nur über Textdateien. Du musst die Rules in Dateien anlegen, die sich im Verzeichnis $OPENHAB_CONF/rules/ befinden müssen. Keine Unterverzeichnisse, Dateiname enthält bitte keine Sonderzeichen und endet mit .rules
Alle Dateien, die auf global definierte Variablen zugreifen sollen müssen sich in der selben Datei befinden.
Beispiel:
Du hast eine Gruppe gSolltemperatur, in der sich alle Items befinden, an die Du eine Solltemperatur senden möchtest.
Code:
Code: Alles auswählen
// Globale Variablen und Konstanen müssen vor der ersten Rule definiert werden!
val HashMap<String,Number> sollMorgen = new HashMap [ "Wohnzimmer" -> 20 ,
"Bibliothek" -> 18 ,
"RSTHeizkorperthermostat1Schlafzimmer" -> 20 ,
"RSTSpielzimmerDaddelbar" -> 18 ,
"RST_HeizkorperthermostatKuecheNeu" -> 18 ,
"RSTHeizkorperthermostatToiletteToilette" -> 9 ,
"RSTHeizkorperthermostat1Bad" -> 18 ]
rule "Werte Schreiben"
when
Item VariableActuatorMorgens_Status changed to ON
then
if(VariableActuatorWeggehen_Status.state == ON) // falls abwesend
return; // Rule abbrechen
VariableActuatorAbends_Status.postUpdate(OFF) // Status der anderen Items setzen
VariableActuatorNachmittags_Status.postUpdate(OFF)
gSolltemperatur.members.forEach[i| // für jeden Gruppenangehörigen
val myWert = sollMorgen.get(i.name.split("_").get(0)) // den passenden Wert auslesen
i.sendCommand(myWert) // schreiben
Thread.sleep(500) // Pause einlegen
]
gSolltemperatur.members.forEach[i| // und noch ein zweites Mal
val myWert = sollMorgen.get(i.name.split("_").get(0))
i.sendCommand(myWert)
Thread.sleep(500)
]
end
Es wäre sinnvoll, zunächst die Itemnamen zu vereinfachen. Ein typisches Schema wäre Raum_Funktion, wobei Raum eventuell auch noch einen Zähler enthalten kann, wenn mehrere gleichartige Geräte innerhalb des selben Raums vorhanden sind (also z.B. mehrere Heizkörperthermostate, die individuell angesteuert werden müssen)
Da das zweimalige Schreiben aller Werte vergleichsweise umständlich ist, habe ich oben der Einfachheit halber ebenfalls auf Redundanz gesetzt

Der Punkt ist aber, die selbe (!) Rule kann sich zusätzlich noch um alle anderen Temperaturen kümmern.
Ein Punkt dabei wäre, statt einzelner Switch Items für den Zustand Morgens, Abends, Nachmittags lieber ein String oder Number Item zu verwenden, damit sparst Du noch weiteren Code. Entweder Morgens oder Abends oder Nachmittags, keiner der Zustände kann zeitgleich auftreten, also braucht es auch nur ein Item dafür, z.B. Tageszeit (ein weiterer Tipp wäre, unnötige Informationen ebenfalls zu vermeiden, also z.B. auf Begriffe wie Variable und Status zu verzichten. Und die Tageszeit ist vermutlich auch keine Eigenschaft eines Aktuators.
In einer ersten Optimierung ergäbe sich also:
Code: Alles auswählen
// Globale Variablen und Konstanen müssen vor der ersten Rule definiert werden!
val HashMap<String,Number> sollMorgen = new HashMap [ "Wohnzimmer" -> 20 ,
"Bibliothek" -> 18 ,
"Schlafzimmer" -> 20 ,
"Daddelbar" -> 18 ,
"Kueche" -> 18 ,
"Toilette" -> 9 ,
"Bad" -> 18 ]
val HashMap<String,Number> sollAbend = new HashMap [ "Wohnzimmer" -> 20 ,
"Bibliothek" -> 18 ,
"Schlafzimmer" -> 20 ,
"Daddelbar" -> 18 ,
"Kueche" -> 18 ,
"Toilette" -> 9 ,
"Bad" -> 18 ]
val HashMap<String,Number> sollMittag = new HashMap [ "Wohnzimmer" -> 20 ,
"Bibliothek" -> 18 ,
"Schlafzimmer" -> 20 ,
"Daddelbar" -> 18 ,
"Kueche" -> 18 ,
"Toilette" -> 9 ,
"Bad" -> 18 ]
rule "Werte Schreiben"
when
Item Tageszeit changed
then
if(Abwesend.state == ON) // falls abwesend
return; // Rule abbrechen
switch(newState) {
case "Morgens" : {
gSolltemperatur.members.forEach[i| // für jeden Gruppenangehörigen
val myWert = sollMorgen.get(i.name.split("_").get(0)) // den passenden Wert auslesen
i.sendCommand(myWert) // schreiben
Thread.sleep(500) // Pause einlegen
]
gSolltemperatur.members.forEach[i| // und noch ein zweites Mal
val myWert = sollMorgen.get(i.name.split("_").get(0))
i.sendCommand(myWert)
Thread.sleep(500)
]
}
case "Mittags" : {
gSolltemperatur.members.forEach[i| // für jeden Gruppenangehörigen
val myWert = sollMittag.get(i.name.split("_").get(0)) // den passenden Wert auslesen
i.sendCommand(myWert) // schreiben
Thread.sleep(500) // Pause einlegen
]
gSolltemperatur.members.forEach[i| // und noch ein zweites Mal
val myWert = sollMittag.get(i.name.split("_").get(0))
i.sendCommand(myWert)
Thread.sleep(500)
]
}
case "Abends" : {
gSolltemperatur.members.forEach[i| // für jeden Gruppenangehörigen
val myWert = sollAbend.get(i.name.split("_").get(0)) // den passenden Wert auslesen
i.sendCommand(myWert) // schreiben
Thread.sleep(500) // Pause einlegen
]
gSolltemperatur.members.forEach[i| // und noch ein zweites Mal
val myWert = sollAbend.get(i.name.split("_").get(0))
i.sendCommand(myWert)
Thread.sleep(500)
]
}
end
gSolltemperatur ist die übergeordnete Gruppe (alle nachfolgenden Items befinden sich in dieser Gruppe) pro Raum mehrere Items in der Form
Wohnzimmer_Solltemperatur, Wohnzimmer_SollMorgen, Wohnzimmer_SollMittag, Wohnzimmer_SollAbend, Wohnzimmer_SollSchatten
Nun die Rule dazu:
Code: Alles auswählen
rule "Werte Schreiben"
when
Item Tageszeit changed
then
if(Abwesend.state == ON) // falls abwesend
return; // Rule abbrechen
var strQuelle = "SollWeg"
switch(newState) {
case "Morgens" : strQuelle = "SollMorgen"
case "Mittags" : strQuelle = "SollMittag"
case "Abends" : strQuelle = "SollAbend"
}
// Werte zwischenspeichern
gSolltemperatur.members.filter[i|i.name.endsWith("SollSchatten")].forEach[| // nimm alle Items für den Schattenwert
val myWert = gSolltemperatur.members.filter[i.name.split("_").get(0) && i.name.endsWith(strQuelle)].head // suche den neuen Sollwert heraus
i.postUpdate(myWert) // speichere den Schattenwert
]
// Befehle senden
gSolltemperatur.members.filter[i|i.name.endsWith("Solltemperatur")].forEach[i| // für jede Solltemperatur
val myWert = gSolltemperatur.members.filter[i|i.name.endsWith("SollSchatten")].head // den passenden Wert auslesen
i.sendCommand(myWert) // schreiben
Thread.sleep(500) // Pause einlegen
]
gSolltemperatur.members.filter[i|i.name.endsWith("Solltemperatur")].forEach[i| // für jede Solltemperatur
val myWert = gSolltemperatur.members.filter[i|i.name.endsWith("SollSchatten")].head // den passenden Wert auslesen
i.sendCommand(myWert) // schreiben
Thread.sleep(500) // Pause einlegen
]
end
Alternativ definierst Du eine Rule, welche beim Systemstart die Sollwerte aus einer HashMap in die passenden Items schreibt.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet
-
- Beiträge: 7
- Registriert: 29. Nov 2023 19:08
Re: Globale Variablen und Funktionen
Kann ich das auch mit den Skripten von einfachen Rules hinbekommen? So ähnlich wie Bat-Dateien in Windows? Jeder Raum hat übrigens nur eine Heizung.
Ich dachte mir, ich könnte irgendwo eine fest codierte Copy-Funktion ohne Parameter hinschreiben und die eigentlichen Daten mit den Rules in OH setzen und von dort aus die Funktion aufrufen.
Ich dachte mir, ich könnte irgendwo eine fest codierte Copy-Funktion ohne Parameter hinschreiben und die eigentlichen Daten mit den Rules in OH setzen und von dort aus die Funktion aufrufen.