Probleme mit DSL Rule „if then else“

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

fmmephisto

Probleme mit DSL Rule „if then else“

Beitrag von fmmephisto »

Hallo zusammen!

Ich bin es mal wieder.

Nun versuche ich es mal mit DSL und habe folgende Rule in der UI erstellt.
Um es einfach mir auch einfach zu machen, sage ich ersteimal: wenn ein Switch OFF ist soll er bei der Rule auf ON gesetzt werden,
Wenn er ON ist, soll er OFF gesetzt werden. Also eine einfache if then else-Rule.

Leider funktioniert die Rule nicht. Ich versuche jetzt seit 4 Stunden, diese Rule per JavaScript und per DSL ans laufen zu bekommen. Leider funktioniert diese Rule in OH3 einfach nicht und ich habe wirklich schon 4 STunden auch hier im Forum gesucht, im Internet…

Ich bekomme diese einfache if then Anweisung nicht hin, ob wohl die Anweisungen auch genau wie in den Beispielen aussehen.

In DSL habe ich es nun so probiert:

Code: Alles auswählen

 if (Voralarm_aktiviert.state == "OFF") then
  Voralarm_aktiviert = "ON"
else
  Voralarm_aktiviert = "OFF"
end
Oder auch mal so:

Code: Alles auswählen

 if (Voralarm_aktiviert.state == "OFF") then
  Voralarm_aktiviert.state = "ON"
else
  Voralarm_aktiviert.state = "OFF"
end
Oder auch so:

Code: Alles auswählen

 if (Voralarm_aktiviert.state == "OFF") then
  Voralarm_aktiviert = ON
else
  Voralarm_aktiviert = OFF
end
Oder so

Code: Alles auswählen

 if (Voralarm_aktiviert.state == "OFF") then
  Voralarm_aktiviert.state = ON
else
  Voralarm_aktiviert.state = OFF
end
Wie baut man so eine Formel auf?

Danke im Voraus und einen schönen Abend.

Gruß
Frank
von udo1toni » 18. Jan 2023 23:18
Es gibt in der DSL kein then, jedenfalls nicht als Bestandteil des if. Grundsätzlich:
Es gibt zwei Möglichkeiten, eine DSL Rule zu schreiben, per UI oder per Textdatei.
Die Textdatei muss im Ordner $OPENHAB_CONF/rules/ abgelegt werden und der Dateiname muss auf .rules enden, also z.B. meine.rules.
An dem s am Ende des Dateinamens kann man schon eine Besonderheit festmachen, denn dieses s bedeutet: mehrere. Im rules-Ordner können beliebig viele Dateien liegen, in einer .rules Datei können beliebig viele Rules liegen.
Dabei hat jede Rule einen Rahmen:

Code: Alles auswählen

rule "Name der Rule"      // Der Name muss eindeutig im System sein, Das Wort "rule" markiert den Beginn einer Rule
when                      // Das Schlüsselwort leitet die Definition der Trigger ein
// hier stehen die Trigger, 
// die zum Ausführen der Rule führen
then                      // Das Schlüsselwort beendet den Definitionsbereich der Trigger und markiert den Beginn des Code-Blocks
// hier steht der Code
end                       // Das Schlüsselwort markiert das Ende des Codeblocks und das Ende der Rule
Diese Zeilen sind NICHT Teil des ausführbaren Codes.

Wenn Du eine DSL Rule über die UI eingibst, darf keines der obigen Schlüsselworte in dem Code auftauchen!!!

Weiterhin ist die DSL objektorientiert. Ein Item ist also ein Objekt mit Methoden und Eigenschaften. .state ist eine Eigenschaft, sie ist nur lesbar.
Um ein Item auf einen bestimmten Status zu setzen, benötigst Du die passende Methode, .postUpdate(). Um über ein Item einen Befehl zu senden, benötigst Du eine andere Methode, .sendCommand.

Da die DSL auf XTend (und damit auf Java) aufbaut, funktioniert das if-else so:

Code: Alles auswählen

if(Voralarm_aktiviert.state == OFF)
    Voralarm_aktiviert.postUpdate(ON)
else
    Voralarm_aktiviert.postUpdate(OFF)
eleganter:

Code: Alles auswählen

Voralarm_aktiviert.postUpdate(if(Voralarm_aktiviert.state == ON) OFF else ON)
Ist aber nicht so gut lesbar :)
Beide Codeschnipsel kannst Du direkt über die UI so eingeben und als DSL-Code laufen lassen.
Zu bemerken wäre noch, dass es sich bei ON und OFF um den Datentyp OnOffType handelt, also NICHT um Strings. Deshalb wird der Vergleich

Code: Alles auswählen

if(Voralarm_aktiviert.state == "OFF")
auch niemals wahr werden, denn OFF ist nicht das gleiche wie "OFF". korrekt wäre es so:

Code: Alles auswählen

if(Voralarm_aktiviert.state.toString == "OFF")
Leider ist openHAB teilweise sehr restriktiv und an anderen Stellen dafür nachlässig, was die Datentypen betrifft. Das führt dazu, dass manchmal Dinge an einer Stelle funktionieren, an anderer Stelle aber nicht, obwohl sie auf den ersten Blick fast identisch sind.
Gehe zur vollständigen Antwort

fmmephisto

Re: Probleme mit DSL Rule „if then else“

Beitrag von fmmephisto »

In java habe ich das hier ausprobiert:

Code: Alles auswählen

 if (items.Voralarm_aktiviert.Status = 'OFF') {
  events.postUpdate('Voralarm_aktiviert', ON);
} else {
  events.postUpdate('Voralarm_aktiviert', OFF);
} 
Es klappt, dass bei OFF der Schalter auf ON gesetzt wird.
Aber wenn er ON ist geht er nicht mehr auf OFF.

Auch diese Variante geht nicht:

Code: Alles auswählen

 if (items.Voralarm_aktiviert.Status = 'OFF') {
  events.sendCommand('Voralarm_aktiviert', ON);
} else {
  events.SendCommand('Voralarm_aktiviert', OFF);
} 
Warum funktioniert immer nur die IF-Condition und die ELSE wird nie ausgeführt?

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

Re: Probleme mit DSL Rule „if then else“

Beitrag von udo1toni »

Es gibt in der DSL kein then, jedenfalls nicht als Bestandteil des if. Grundsätzlich:
Es gibt zwei Möglichkeiten, eine DSL Rule zu schreiben, per UI oder per Textdatei.
Die Textdatei muss im Ordner $OPENHAB_CONF/rules/ abgelegt werden und der Dateiname muss auf .rules enden, also z.B. meine.rules.
An dem s am Ende des Dateinamens kann man schon eine Besonderheit festmachen, denn dieses s bedeutet: mehrere. Im rules-Ordner können beliebig viele Dateien liegen, in einer .rules Datei können beliebig viele Rules liegen.
Dabei hat jede Rule einen Rahmen:

Code: Alles auswählen

rule "Name der Rule"      // Der Name muss eindeutig im System sein, Das Wort "rule" markiert den Beginn einer Rule
when                      // Das Schlüsselwort leitet die Definition der Trigger ein
// hier stehen die Trigger, 
// die zum Ausführen der Rule führen
then                      // Das Schlüsselwort beendet den Definitionsbereich der Trigger und markiert den Beginn des Code-Blocks
// hier steht der Code
end                       // Das Schlüsselwort markiert das Ende des Codeblocks und das Ende der Rule
Diese Zeilen sind NICHT Teil des ausführbaren Codes.

Wenn Du eine DSL Rule über die UI eingibst, darf keines der obigen Schlüsselworte in dem Code auftauchen!!!

Weiterhin ist die DSL objektorientiert. Ein Item ist also ein Objekt mit Methoden und Eigenschaften. .state ist eine Eigenschaft, sie ist nur lesbar.
Um ein Item auf einen bestimmten Status zu setzen, benötigst Du die passende Methode, .postUpdate(). Um über ein Item einen Befehl zu senden, benötigst Du eine andere Methode, .sendCommand.

Da die DSL auf XTend (und damit auf Java) aufbaut, funktioniert das if-else so:

Code: Alles auswählen

if(Voralarm_aktiviert.state == OFF)
    Voralarm_aktiviert.postUpdate(ON)
else
    Voralarm_aktiviert.postUpdate(OFF)
eleganter:

Code: Alles auswählen

Voralarm_aktiviert.postUpdate(if(Voralarm_aktiviert.state == ON) OFF else ON)
Ist aber nicht so gut lesbar :)
Beide Codeschnipsel kannst Du direkt über die UI so eingeben und als DSL-Code laufen lassen.
Zu bemerken wäre noch, dass es sich bei ON und OFF um den Datentyp OnOffType handelt, also NICHT um Strings. Deshalb wird der Vergleich

Code: Alles auswählen

if(Voralarm_aktiviert.state == "OFF")
auch niemals wahr werden, denn OFF ist nicht das gleiche wie "OFF". korrekt wäre es so:

Code: Alles auswählen

if(Voralarm_aktiviert.state.toString == "OFF")
Leider ist openHAB teilweise sehr restriktiv und an anderen Stellen dafür nachlässig, was die Datentypen betrifft. Das führt dazu, dass manchmal Dinge an einer Stelle funktionieren, an anderer Stelle aber nicht, obwohl sie auf den ersten Blick fast identisch sind.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

fmmephisto

Re: Probleme mit DSL Rule „if then else“

Beitrag von fmmephisto »

Danke.... :-)
Das hat jetzt funktioniert.

Ich werde damit mal weiter experimentieren, ob ich damit dann auch irgendwann Texte damit reinbekomme und wieder rausbekomme.

Gibt es eine Übersicht, welche Eigenschaften welche Items haben können?

Und den Unterschied zwischen postUpdate und sendCommand habe ich trotz 100facher Erklärung hier im Forum auch noch nicht verstanden.
Ich kann den Status "OFF und ON" z. b. über postUpdate und über sendCommand setzen. Aber wann nutzt man was?

Kannst du das mal Kinder und Vorstandstauglich erklären? Weil: ich kann den Trigger abfragen "nach Update" und "nach Change".
Nach update ist nach postupdate und nach change ist nach sencommand.
Ergebnis ist das gleiche und ich sehe keinen Unterschied.

oh73
Beiträge: 302
Registriert: 7. Mär 2021 14:49
Answers: 1

Re: Probleme mit DSL Rule „if then else“

Beitrag von oh73 »

postUpdate und sendCommand,

ich halte das für mich so, das wenn ich was schalten will, Schalter aus oder ein = Commando =
sendCommand.
will ich ein String oder Nummer Item was ändern, nehme ich postUpdate.
OH 4.3.0 auf HP 26o G1 Dm Mini Pc mit MX_Linux

fmmephisto

Re: Probleme mit DSL Rule „if then else“

Beitrag von fmmephisto »

oh73 hat geschrieben: 19. Jan 2023 10:28 postUpdate und sendCommand,

ich halte das für mich so, das wenn ich was schalten will, Schalter aus oder ein = Commando =
sendCommand.
will ich ein String oder Nummer Item was ändern, nehme ich postUpdate.
Das ist eine gute Erklärung. Damit kann ich was anfangen. Danke Dir.

fmmephisto

Re: Probleme mit DSL Rule „if then else“

Beitrag von fmmephisto »

udo1toni hat geschrieben: 18. Jan 2023 23:18 Es gibt in der DSL kein then, jedenfalls nicht als Bestandteil des if. Grundsätzlich:
Es gibt zwei Möglichkeiten, eine DSL Rule zu schreiben, per UI oder per Textdatei.
Die Textdatei muss im Ordner $OPENHAB_CONF/rules/ abgelegt werden und der Dateiname muss auf .rules enden, also z.B. meine.rules.
An dem s am Ende des Dateinamens kann man schon eine Besonderheit festmachen, denn dieses s bedeutet: mehrere. Im rules-Ordner können beliebig viele Dateien liegen, in einer .rules Datei können beliebig viele Rules liegen.
Dabei hat jede Rule einen Rahmen:

Code: Alles auswählen

rule "Name der Rule"      // Der Name muss eindeutig im System sein, Das Wort "rule" markiert den Beginn einer Rule
when                      // Das Schlüsselwort leitet die Definition der Trigger ein
// hier stehen die Trigger, 
// die zum Ausführen der Rule führen
then                      // Das Schlüsselwort beendet den Definitionsbereich der Trigger und markiert den Beginn des Code-Blocks
// hier steht der Code
end                       // Das Schlüsselwort markiert das Ende des Codeblocks und das Ende der Rule
Diese Zeilen sind NICHT Teil des ausführbaren Codes.

Wenn Du eine DSL Rule über die UI eingibst, darf keines der obigen Schlüsselworte in dem Code auftauchen!!!

Weiterhin ist die DSL objektorientiert. Ein Item ist also ein Objekt mit Methoden und Eigenschaften. .state ist eine Eigenschaft, sie ist nur lesbar.
Um ein Item auf einen bestimmten Status zu setzen, benötigst Du die passende Methode, .postUpdate(). Um über ein Item einen Befehl zu senden, benötigst Du eine andere Methode, .sendCommand.

Da die DSL auf XTend (und damit auf Java) aufbaut, funktioniert das if-else so:

Code: Alles auswählen

if(Voralarm_aktiviert.state == OFF)
    Voralarm_aktiviert.postUpdate(ON)
else
    Voralarm_aktiviert.postUpdate(OFF)
eleganter:

Code: Alles auswählen

Voralarm_aktiviert.postUpdate(if(Voralarm_aktiviert.state == ON) OFF else ON)
Ist aber nicht so gut lesbar :)
Beide Codeschnipsel kannst Du direkt über die UI so eingeben und als DSL-Code laufen lassen.
Zu bemerken wäre noch, dass es sich bei ON und OFF um den Datentyp OnOffType handelt, also NICHT um Strings. Deshalb wird der Vergleich

Code: Alles auswählen

if(Voralarm_aktiviert.state == "OFF")
auch niemals wahr werden, denn OFF ist nicht das gleiche wie "OFF". korrekt wäre es so:

Code: Alles auswählen

if(Voralarm_aktiviert.state.toString == "OFF")
Leider ist openHAB teilweise sehr restriktiv und an anderen Stellen dafür nachlässig, was die Datentypen betrifft. Das führt dazu, dass manchmal Dinge an einer Stelle funktionieren, an anderer Stelle aber nicht, obwohl sie auf den ersten Blick fast identisch sind.
Das war die erste Erklärung, mit der ich meine erste Rule in VSC erstellt habe und die auch in OH3 sehen kann.
Und das Beste ist: die Rule funktioniert auch.
Nun versuche ich mich mal mit dem Timer.... :-)
Danke.

BOP
Beiträge: 197
Registriert: 23. Sep 2018 19:43
Answers: 1

Re: Probleme mit DSL Rule „if then else“

Beitrag von BOP »

Ich benutze immer sendCommand. Außer, ich möchte/muss ein Item schalten, welches an einem Channel hängt, der sich nicht schalten lässt. Also z.B. das Signal eines Bewegungssensors. Dann benutze ich .postUpdate.
Denn das ist der Unterschied. .sendCommand sendet den Befehl über den Channel (an das Gerät). .postUpdate tut das nicht. Beide schalten aber das Item. Deswegen merkt man bei den Rules auch keine Unterschiede. Das Item wird (um)geschaltet und die Rule triggert.

EDIT: Zum Timer. Da gibt es ein Beispiel in der Doku: https://www.openhab.org/docs/configurat ... tml#timers

fmmephisto

Re: Probleme mit DSL Rule „if then else“

Beitrag von fmmephisto »

Das werde ich jetzt wohl auch so machen. Beim testen heute ist mir aufgefallen, dass es einfacher ist, immer sendCommand zu nutzen.. Ausser wenn es halt nicht geht... sowhat....
So hab ich es nun auch verstanden.

Das mit dem Timer aus dem Beispiel der Doku habe ich nicht verstände, weil doch sehr kompliziert. Macht nichts, auch ohne es vom Grundsatz zu verstehen, warum man da was macht, habe ich für mich eine Vorlage erstellt, wie ich meine Timer einsetze und sie auch funktionieren.
Wenn ich etwa 5 Sekunden warten will bis was passiert, bekomme ich das hin.
Problem ist halt nur: Wenn irgendein Timer 1 Minute läuft, bis was anderes danach passieren soll, aber in der Zwischenzeit ein Schalter betätigt wird, der eine Lampe für 5 Sekunden anmachen soll..... Dann brauche ich zwei Timer gleichzeitig.... Der eine läuft 1 Minute..... und nach sagen wir mal 10 Sekunden soll ein weiterer Timer in einer anderen Rule für 5 Sekunden gestartet werden!!!! Dadurch dass ich vorher abfrage: wenn schon ein Timer läuft, starte den neuen Timer mit den 5 Minuten gar nicht.

Werde mal versuchen, die Timervariablen anders zu benennen. Damit sollte es ja möglich sein, dass mehrere Timer zur gleichen Zeit laufen. Oder?

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

Re: Probleme mit DSL Rule „if then else“

Beitrag von udo1toni »

Der Status des Items soll den Zustand eines externen Geräts widerspiegeln. Nehmen wir mal eine schaltbare Steckdose als externes Gerät an. Du kannst die Steckdose ein- und ausschalten, mehr nicht (soll ja möglichst einfach sein) Das bedeutet für openHAB: Du musst einen Befehl senden können, um die Steckdose zu schalten.
Auf der anderen Seite willst Du aber den Zustand der Steckdose kennen, und zwar möglichst den echten Zustand, also den von der Steckdose gemeldeten Zustand.

Ich versuche es mal mit einer Art Tabelle:

Code: Alles auswählen

                        sendCommand postUpdate
UI                           X          -     
Channel (kommend)            -          X
Channel (gehend)             X          -
Rule triggert received    command     update
              changed        -         (X)
Wann immer Du in der UI eine Item manipulierst, löst das ein sendCommand aus.
Wann immer ein Channel etwas empfängt,ist das ein Update des Status
Wann immer Du einen Channel steuern möchtest, musst Du sendCommand verwenden.
Rules triggern gezielt, je nachdem, welchen Trigger Du verwendest.
Changed wird natürlich nur getriggert, wenn das postUpdate zu einer Änderung des Status geführt hat.

So.
Und weil das allzu einfach war: Das Default Verhalten von openHAB ist, dass jedes sendCommand automatisch ein postUpdate nach sich zieht.
openHAB setzt also automatisch den neuen Status im Item (um diesen neuen Status möglichst schnell anzuzeigen). Man kann dieses Verhalten aber abschalten (Parameter autoupdate = false in den Metadaten des Items).

Das Verhalten ist also als Default:
  1. sendCommand(ON)
  2. postUpdate(ON)
  3. (gleichzeitig) Channel sendet Kommando ON
  4. Steckdose schaltet
  5. Steckdose sendet Zustand ON
  6. ON wird als neuer Zustand geladen
Und mit autoupdate=false:
  1. sendCommand(ON)
  2. Channel sendet Kommando ON
  3. Steckdose schaltet
  4. Steckdose sendet Zustand ON
  5. Status ON wird übernommen
Im ersten Fall ist also die Reaktionszeit "optimiert", allerdings kann die Annahme des neuen Status auch gehörig schief gehen, insbesondere bei Dimmern, das führt dann zu mehrfachen Updates und springenden Schiebestellern in der UI.

Der größte Unterschied zwischen postUpdate und sendCommand ist also die Auswirkung zum einen auf einen verbundenen Channel (postUpdate->keine Auswirkung; sendCommand->steuert Channel) und zum anderen auf die Rules (abhängig vom Trigger)

Man sollte es sich nicht zu einfach mit der Verwendung von sendCommand machen und darüber postUpdate vergessen, es sind zwei grundverschiedene Befehle, die nur durch das Default Verhalten scheinbar die gleiche Wirkung haben.
Schaltet man das autoupdate aus, tritt der Unterschied klar zutage: sendCommand wirkt auf verlinkte Channel, postUpdate wirkt ausschließlich auf das Item selbst.

Und weil es noch nicht kompliziert genug ist... Es gibt Ausnahmen vom Standardverhalten, abhängig von der Konfiguration der verlnkten Channel und eines eventuell gesetzten Profiles (dabei geht es vor allem um die Möglichkeit, ankommende Updates als Befehl zu werten, damit man z.B. mit einem WLAN Schalter ohne eine Rule zu verwenden z.B. ein Homematic Licht schalten kann).
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten