Skript-Sprache für wiederverwendbare Regeln

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
Proton
Beiträge: 93
Registriert: 10. Okt 2022 12:13
Answers: 4
Wohnort: Oberbergisches

Skript-Sprache für wiederverwendbare Regeln

Beitrag von Proton »

Hallo,

ich habe im Hause mehrere Dimmer, die alle auf die gleiche Weise reagieren sollen, deswegen habe ich versucht mich mit Wiederverwendbarkeit von Regeln auseinanderzusetzen, aber je mehr ich gelesen habe, desto mehr Fragen wurden aufgeworfen.

Bisher habe ich meine Regeln in Rules DSL geschrieben bzw. habe ich Skripte damit geschrieben und diese in den UI-Regeln aufgerufen.
Ich habe gelesen, dass es einen Unterschied beim event-Objekt macht, ob die Regel ui- oder file-basiert ist, aber nur wenn die Regel nicht über ein Event ausgelöst wurde, falls ich das richtig verstanden habe. Gibt es noch andere Gründe die für den file-basierten Ansatz sprechen?

Hier schreibt jemand, dass man nicht das alte DSL verwenden soll, sondern lieber Jython, was aber offensichtlich deprecated ist.
Zu Rules DSL gab es aber wenigstens ein Tutorial wie man wiederverwendbaren Code schreibt.
Ist DSL wirklich veralten und zu vermeiden? Wenn ja, gehe ich recht in der Annahme, dass man dann JavaScript Scripting bevorzugen sollte? Und gibt es dafür auch eine Anleitung, die ich nur noch nicht gefunden habe?

Schönen Gruß
von udo1toni » 18. Jan 2024 00:14
Ja klar, gerne.

Die Items (ein Paar als Beispiel):

Code: Alles auswählen

Number NEGBad_OpMode "Betriebsart ist"  <heating> (gNEGBad,gHeat_Mode) ["Status"]  {channel="knx:device:bridge:GiraTSplus1_1_120:opMode"}
Number NEGBad_OpSet  "Betriebsart soll" <heating> (gNEGBad,gHeat_Set)  ["Control"] {channel="knx:device:bridge:GiraTSplus1_1_120:opSet"}
Die anderen Items unterscheiden sich dann im Namen nur durch den ersten Teil, das Label ist ein anderes und natürlich die verlinkten Channel :)
Die 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)
    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
Man kann schön sehen, dass in der Rule nur die Group Items verwendet werden, dadurch kann die Rule für mehrere gleiche Items verwendet werden.

Sobald ein Status geändert wird - egal ob nun durch einen manuellen Eingriff am RTR oder durch openHAB selbst - wird die Rule getriggert. Der neue Modus wird nach BigInteger konvertiert, denn BigInteger hat eine Methode testBit(). Der erste Teil des Itemnamens wird ermittelt. Der aus dem gemeldeten Modus abgeleitete Wert für das Item in der UI wird ermittelt, das Item, welches in der UI verwendet wird wird ermittelt, falls dieses einen gültigen Status hat, wird der mit dem Soll verglichen und gegebenenfalls geändert. das heißt, am Ende der Rule hat das Item in der UI den korrekten Status, es wird aber nur dann aktiv angesteuert, wenn das auch notwendig ist.
Gehe zur vollständigen Antwort

Benutzeravatar
udo1toni
Beiträge: 15244
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Skript-Sprache für wiederverwendbare Regeln

Beitrag von udo1toni »

Tatsächlich ist die DSL die einzige Scriptsprache, welche im Core verankert ist. Sie ist damit die einzige Scriptsprache, welche auf jeden Fall zur Verfügung steht.
Vor dem Wechsel von openHAB2 auf openHAB3 gab es Äußerungen, dass die DSL wegen Abhängigkeiten nicht weiter gepflegt werden könne, deshalb gab es (auch von mir) die Warnung, dass die DSL irgendwann mal weg fällt. Das ist nicht mehr aktuell, die DSL ist nicht deprecated :) und wird es mutmaßlich auch nicht werden.
Was allerdings mutmaßlich mit OH5 kommen wird, ist, dass die DSL optional wird, das heißt, sie wird aus dem Core herausgelöst und steht anschließend wie alle anderen Scriptsprachen auch als Addon zur Verfügung.

Es gibt bis auf ein Detail keine Unterschiede zwischen Text-basierten Rules (*.rules Dateien) und UI-basiserten DSL Rules, dieses Detail ist die Definition von Rule-übergreifenden Variablen und Konstanten (globale... obwohl das nicht korrekt ist...)
In Textdateien kann man vor der ersten Rule Variablen und Konstanten definieren, welche dann in allen Rules dieser Datei verwendet werden können und die ihren zugewiesenen Wert auch über den Lauf einer Rule hinaus beibehalten.
In UI Rules gibt es dafür den GlobalCache und den PrivateCache (beide kann man aber auch in den Textdateien verwenden, ist halt etwas umständlicher)

Solange Du mit der DSL fein bist, bleibe dabei. :)

Was die "Wiederverwendbarkeit" betrifft, so gibt es in der DSL "offiziell" keine Funktionen, was eine Voraussetzung für modulbasierte Programme wäre.
Allerdings kann man Rules so gestalten, dass sie für mehrere Items verwendet werden können. Ich habe z.B. neun Raumtemperaturregler, welche ihre Betriebsart als Bitmuster melden (1,2,4,8 + 16 oder 32, je nachdem ob Kühlen oder Heizen aktiv), während die Wahl der Betriebsart über eine Zahl 1 - 4 erfolgt. deshalb muss ich die Rückmeldung "umrechnen", was ich mit einer Rule erledige. Die Rule bezieht sich dabei nicht auf zwei bestimmte Items, sondern auf Gruppen, in denen die Items zusammengefasst sind. Aus dem Namen des Items, welches die Rule ausgelöst hat, wird dann errechnet, welches Item gesteuert werden muss. Ich brauche also nur eine Rule für alle neun RTR, und wenn ich noch weitere RTR dazu bekäme, müsste ich lediglich die entsprechenden Items den Gruppen zuordnen (natürlich müssen die Itemnamen passend gewählt sein...)

Eine andere Option wäre die Verwendung von Lambdas, welche man als Funktions"ersatz" verwenden kann.

Es ist vor allem die Frage, was Deine Rule konkret macht, wie man diese am besten gestaltet, damit sie unabhängig von bestimmten Items wird.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Proton
Beiträge: 93
Registriert: 10. Okt 2022 12:13
Answers: 4
Wohnort: Oberbergisches

Re: Skript-Sprache für wiederverwendbare Regeln

Beitrag von Proton »

Hallo Udo,
vielen Dank für die ausführliche Antwort!
Mir ging es vornehmlich um die Zukunftssicherheit und wenn diese durch das Herauslösen gesichert ist, dann bleibe ich bei DSL, da das Java am nächsten kommt, womit ich mich auskenne.

In dem Tutorial steht "Lambdas have some severe limitations and should be avoided unless no other approach will work", von daher wurde ich von diesen Abstand nehmen sofern möglich.

Die Räume mit den Dimmern bekommen Präsenzsenoren und die Regel sollen abhängig von der Helligkeit entscheiden ob die Dimmer überhaupt eingeschaltet werden und abhängig von einem anderen Kriterium (vorerst wird es wohl Zeit basiert sein), wie hell die Dimmer leuchten sollen.

Wie du das bei deinen RTR umgesetzt hast, habe ich ehrlich gesagt noch nicht ganz verstanden, deswegen wäre es super, wenn du den Quelltext hier herein kopieren könntest.

Vielen Dank und schönen Gruß

Benutzeravatar
udo1toni
Beiträge: 15244
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Skript-Sprache für wiederverwendbare Regeln

Beitrag von udo1toni »

Ja klar, gerne.

Die Items (ein Paar als Beispiel):

Code: Alles auswählen

Number NEGBad_OpMode "Betriebsart ist"  <heating> (gNEGBad,gHeat_Mode) ["Status"]  {channel="knx:device:bridge:GiraTSplus1_1_120:opMode"}
Number NEGBad_OpSet  "Betriebsart soll" <heating> (gNEGBad,gHeat_Set)  ["Control"] {channel="knx:device:bridge:GiraTSplus1_1_120:opSet"}
Die anderen Items unterscheiden sich dann im Namen nur durch den ersten Teil, das Label ist ein anderes und natürlich die verlinkten Channel :)
Die 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)
    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
Man kann schön sehen, dass in der Rule nur die Group Items verwendet werden, dadurch kann die Rule für mehrere gleiche Items verwendet werden.

Sobald ein Status geändert wird - egal ob nun durch einen manuellen Eingriff am RTR oder durch openHAB selbst - wird die Rule getriggert. Der neue Modus wird nach BigInteger konvertiert, denn BigInteger hat eine Methode testBit(). Der erste Teil des Itemnamens wird ermittelt. Der aus dem gemeldeten Modus abgeleitete Wert für das Item in der UI wird ermittelt, das Item, welches in der UI verwendet wird wird ermittelt, falls dieses einen gültigen Status hat, wird der mit dem Soll verglichen und gegebenenfalls geändert. das heißt, am Ende der Rule hat das Item in der UI den korrekten Status, es wird aber nur dann aktiv angesteuert, wenn das auch notwendig ist.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Proton
Beiträge: 93
Registriert: 10. Okt 2022 12:13
Answers: 4
Wohnort: Oberbergisches

Re: Skript-Sprache für wiederverwendbare Regeln

Beitrag von Proton »

Hallo Udo,
danke für die Nachricht, leider komme ich erst jetzt dazu mir das ganze auch mal anzuschauen.
Ich denke ich habe nicht ganz verstanden wie deine RTR funktionieren, deswegen konzentriere ich mich mal auf die Sachen, von denen ich glaube sie verstanden zu haben bzw. die Teile die für mich relevanten sind.
1. Gruppe für die Dimmer (gDimmer)
2. Gruppe für die Sensoren (gSensoren)
3. Items entsprechend benennen und den jeweiligen Gruppen hinzufügen badezimmer_dimmer und badezimmer_sensor
Die Regel würde jedes Mal angestoßen werden, wenn ein Sensor seinen Zustand ändert

Code: Alles auswählen

    // Hier würde dann als Wert "badezimmer" ermittelt werden
    val iName = triggeringItem.name.split("_").get(0)

    // Über den Wert aus iName wird dann das entsprechende Element aus der Gruppe ermittelt
    var myItem = gDimmer.members.filter[ f | f.name.startsWith(iName) ].head
    // hier müssten dann die Bedingungen überprüft werden was mit dem Dimmer gemacht werden soll
Kommt das ungefähr hin?

Schönen Gruß

Benutzeravatar
udo1toni
Beiträge: 15244
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Skript-Sprache für wiederverwendbare Regeln

Beitrag von udo1toni »

Ja, genau.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten