Seite 1 von 1

OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 16. Mär 2021 20:00
von stonev
Hallo,
ich steige gerade um von OH2.5 auf OH3. Das meiste läuft und so bin ich nun bei Rules angekommen (habe komplett neu aufgesetzt und alles neu über das UI angelegt).

Nun habe ich aber eine Rule mit einem Timer, die unter OH2.5 mit globalen Variabeln funktioniert hat:

Code: Alles auswählen

var Timer interval_timer = null
 
rule "Ventilation"

var Integer ventilation_interval = (Garage_Ventilation_Intervall.state as DecimalType).intValue
...

ventilation_timer = createTimer(now.plusMinutes(ventilation_interval), [|
	sendCommand(Ventilator_Garage, OFF)
	ventilation_timer = null ]

Da unter OH3 keine globalen Variabeln über UI nutzbar sind, stehe ich auf dem Schlauch. Ich weiß, man kann die alte Rules Datei nutzen und es so machen wie früher. Ich habe aber schon andere Rules per UI erstellt. Ein Mixbetrieb ist vermutlich aber nicht möglich. Außerdem sieht die Zukunft wie ich gelesen habe die Lösung mit Dateien nicht vor. Wenn möglich, würde ich daher jetzt auch alles konform anlegen.

Folgendes habe ich probiert:
In der UI eine Rule angelegt und unter Action DSL-Script gewählt:

Code: Alles auswählen

var Timer interval_timer = null
var Integer ventilation_interval = (Garage_Ventilation_Intervall.state as DecimalType).intValue
...

ventilation_timer = createTimer(now.plusMinutes(ventilation_interval), [|
	sendCommand(Ventilator_Garage, OFF)
	ventilation_timer = null ]
Das funktioniert erwartungsgemäß nicht und im Log steht ein Error:

Code: Alles auswählen

Cannot refer to the non-final variable ventilation_timer inside a lambda expression;
Ich darf die Variable "ventilation_timer" nicht innerhalb der Lmba verwenden, was imho nur geht, wenn sie Global definiert wäre.

Ich habe also versucht ein Dummy item als Globale Variable zu mißbrauchen:

Code: Alles auswählen

var Integer ventilation_interval = (Garage_Ventilation_Intervall.state as DecimalType).intValue
...

ventilation_timer = createTimer(now.plusMinutes(ventilation_interval), [|
	sendCommand(Ventilator_Garage, OFF)
	postUpdate(intervall_timer, "") ]
Das item "intervall_timer" habe ich zunächst als Typ "Number" definiert, was aber zu folgender Fehlermeldung führt:

Code: Alles auswählen

Type mismatch: cannot convert from Timer to NumberItem;
Gleiches passiert mit analoger Fehlmeldung, wenn ich dem Item den Typ "DateTime" oder "String" gebe.

Hier sind also die Formate "Timer" und des Items nicht kompatibel.

Ich habe den ganzen Tag jetzt damit verbracht, viel gelesen und probiert - aber eine Lösung ist nicht dabei entstanden.
Gibt es vielleicht irgendeinen Workaround dafür?

Grundsätzlich soll es ja künftig Richtung Javascript gehen, aber da kenn ich mich noch gar nicht mit aus. Das ist eher mal ein separates Projekt, aber nicht zugleich mit dem Umzug auf OH3...

Re: OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 16. Mär 2021 20:09
von BOP
stonev hat geschrieben: 16. Mär 2021 20:00 Ein Mixbetrieb ist vermutlich aber nicht möglich.
Doch, das geht.
Gibt es vielleicht irgendeinen Workaround dafür?
Du könntest ein Expire Item dafür benutzen.

Re: OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 16. Mär 2021 21:50
von stonev
BOP hat geschrieben: 16. Mär 2021 20:09
stonev hat geschrieben: 16. Mär 2021 20:00 Ein Mixbetrieb ist vermutlich aber nicht möglich.
Doch, das geht.
Das ist schon mal beruhigend.
BOP hat geschrieben: 16. Mär 2021 20:09 Du könntest ein Expire Item dafür benutzen.
Die Option "Expire" kann ich meines Wissens nur direkt in der Konfiguration des Items setzen. Und zwar fest.
Ich will aber den Timer über ein Frontend einstellen, einem Item zuordnen und dessen Wert der Variablen "ventilation_interval" übergeben, welche in der Rule die Dauer des Timers vorgibt. Ich kann mir nicht vorstellen, wie ich das mit Expire hinbekomme.

Ich habe hier auch nur einen Ausschnitt der Rule, um es nicht zu überfrachten. Nach dem der Ventilator für x Minuten eingeschaltet war, soll anschließend auch eine (einstellbare) Pause von x Minuten stattfinden.

Re: OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 16. Mär 2021 22:44
von udo1toni
Ich kann in der Zwischenzeit etwas Entwarnung geben, was die rules betrifft. Es gibt eine Aussage im englischen Forum, dass die Unterstützung für *.rules Dateien nicht entfernt werden soll. Das heißt, man kann einfach die alten Rules weiter verwenden (mit Anpassungen natürlich, Stichwort vor allem JavaTime statt Joda Time).

Re: OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 17. Mär 2021 08:49
von stonev
Über die Thematik "JavaTime statt Joda Time" bin ich gestern Abend noch gestolpert.
Ich nehme an, das ist auch der Grund, warum ich ich ein Item vom Typ DateTime nicht als Variable für den Timer nehmen kann. Das Item macht dann vermutlich JavaTime und der Timer aus der alten DSL Rule Joda Time.

Ich werde dazu heute nochmal ein wenig lesen. Es drängen sich zwei Fragen auf:
1. Kann man in DSL Rule JavaTime verwenden?
2. Muss ich ggf. in der alten DSL Rule bzgl. JavaTime etwas anpassen, damit sie als Datei unter OH3 funktioniert?
3. Kann man ggf. bei meiner Variante (Item als globale Variable) von Joda Time auf JavaTime übersetzen?

Ich finde diese ganzen neuen Dinge in OH3 ja schon echt toll. Ich verstehe nur nicht, warum ein Timer so kompliziert ist. Ist ja kein seltener Anwendungsfall. Wird unter OH3 vermutlich nur mit Javascript funktionieren.

Edit:
zu 3. gibt es einen ausführlichen Thread https://community.openhab.org/t/datetim ... 3-x/107197.
Das Item hat das Format DateTime und nicht JavaTime. Man kann aber mit Hilfsvariablen die Formate übertragen.
Mal sehen, ob mich das weiter bringt.
O. a. Thread lässt allerdings den Unterschied JodaTime zu JavaTime ein wenig im Dunkeln.

Re: OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 17. Mär 2021 19:30
von udo1toni
stonev hat geschrieben: 17. Mär 2021 08:49 Ich nehme an, das ist auch der Grund, warum ich ich ein Item vom Typ DateTime nicht als Variable für den Timer nehmen kann. Das Item macht dann vermutlich JavaTime und der Timer aus der alten DSL Rule Joda Time.
Jjjj... Nein.

Du definierst in Deiner Rule drei Variablen, die die Aufgabe eines Items übernehmen. Diese Variablen sind dann vom Typ DateTime Item. das sollte auch funktionieren, allerdings wird das Schlüsselwort vermutlich falsch sein.
stonev hat geschrieben: 17. Mär 2021 08:49 Ich werde dazu heute nochmal ein wenig lesen. Es drängen sich zwei Fragen auf:
1. Kann man in DSL Rule JavaTime verwenden?
2. Muss ich ggf. in der alten DSL Rule bzgl. JavaTime etwas anpassen, damit sie als Datei unter OH3 funktioniert?
3. Kann man ggf. bei meiner Variante (Item als globale Variable) von Joda Time auf JavaTime übersetzen?

Ich finde diese ganzen neuen Dinge in OH3 ja schon echt toll. Ich verstehe nur nicht, warum ein Timer so kompliziert ist. Ist ja kein seltener Anwendungsfall. Wird unter OH3 vermutlich nur mit Javascript funktionieren.

Edit:
zu 3. gibt es einen ausführlichen Thread https://community.openhab.org/t/datetim ... 3-x/107197.
Das Item hat das Format DateTime und nicht JavaTime. Man kann aber mit Hilfsvariablen die Formate übertragen.
Mal sehen, ob mich das weiter bringt.
O. a. Thread lässt allerdings den Unterschied JodaTime zu JavaTime ein wenig im Dunkeln.
Die Unterschiede Joda Time vs. JavaTime sind an vielen Stellen eher subtil. Letztlich unterscheiden sich die Schlüsselworte und einzelne Funktionen stehen nicht oder nur in veränderter Form zur Verfügung. Beispielsweise gibt es in Joda Time .plusMillis(), in JavaTime gibt es stattdessen nur .plusNanos() (Nanosekunden sind natürlich genauer... in 99% der Fälle wird das aber komplett oversized sein, nicht nur in Bezug auf openHAB, wo es in 100% der Fälle oversized ist). Es fehlt eine Funktion .getMinuteOfDay oder etwas vergleichbares, was bedeutet, dass man .getHour() und .getMinute() verwenden muss, also zwei Aufrufe statt einem... JavaTime ist halt in Java 11 mit dabei, damit ist Joda Time dann obsolet und muss nicht extra importiert werden.

Ansonsten muss man halt ZonedDateTime.now schreiben statt now, getHour statt getHourOfDay usw. Aber das sind ja nur kleine Anpassungen, lästig, aber machbar.
Schade ist, dass es keine tabellarische Darstellung gibt Joda <-> JavaTime (zumindest für die gebräuchlichsten Funktionen), also im englischen Forum. Andererseits könnte ich das auch zusammentragen und selbst einen Eintrag verfassen, aber ich bin halt auch faul...

Re: OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 17. Mär 2021 21:32
von udo1toni
Ach... nicht tabellarisch, aber eine gute Zusammenfassung verschiedener Aspekte: https://stackoverflow.com/questions/246 ... -joda-time
Das ist allerdings auch schon etwas älter...

Re: OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 18. Mär 2021 19:37
von BOP
stonev hat geschrieben: 16. Mär 2021 21:50 Die Option "Expire" kann ich meines Wissens nur direkt in der Konfiguration des Items setzen. Und zwar fest.
Du kannst ja ein Dummy-Item anlegen, welches du dann in (d)einer Rule ON schaltest. In einer anderen Rule fragst du dann den Übergang nach OFF ab und verrichtest die Tätigkeiten, die bei Ablauf des Timers durchgeführt werden sollen.

Ist auch nur eine Idee. Ich selber benutze weiterhin die *.rules-Dateien.

Re: OH3 - Rule via UI erstellen mit Timer - Problem Globale Variabeln

Verfasst: 22. Mär 2021 21:54
von stonev
Guten Abend,
hat etwas gedauert, aber ich habe mein Problem nun gelöst und will das hier nicht vorenthalten.
Nach vielem probieren hatte ich ein DSL Script, das mit items als globalen Variabelen funktionierte. So richtig elegant sah das aber nicht aus.
Also habe ich mal einen Javascriptexkurs gestartet (was ich eigentlich erstmal nicht wollte) und es hat sich gelohnt.

Die Eingangs dargestellte Rule sieht nun wie folgt aus:

Code: Alles auswählen

var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
var ZonedDateTime = Java.type("java.time.ZonedDateTime");  
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.Examples");

// Initialisierung der Timervariablen. Falls sie keinen Wert hat, wird der Wert "null" gesetzt
this.LueftungTimer = (this.LueftungTimer === undefined) ? null : this.LueftungTimer;

var dauer = itemRegistry.getItem("GarageRule_Ventilation_Intervall").getState();

//die Funktion übernimmt die Rolle von Lambda:
function Lueften() {
  logger.info("Lüftungsintervall beendet. Beginn der Lüftungspause von " + pause + " Minuten.");
  events.sendCommand("Ventilator_Garage", "OFF");
  this.LueftungTimer = null;
}
...
//Aufruf des Timers, sobalt der abgelaufen ist, wird die Funktion "Lueften" ausgeführt:
this.LueftungTimer = ScriptExecution.createTimer(ZonedDateTime.now().plusMinutes(dauer), Lueften);
...
Und sollte es jemanden Interessieren, hier die vollständige Rule mit weiteren Funktionen (Lüften nach Abgleich absoluter Feuchtigkeit Innen-/Außen). Definierte Lüftungspause nach dem Lüften. Manuelles Einschalten etc. :

Code: Alles auswählen

var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
var ZonedDateTime = Java.type("java.time.ZonedDateTime");  
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.Examples");
this.LueftungTimer = (this.LueftungTimer === undefined) ? null : this.LueftungTimer;
this.PausenTimer = (this.PausenTimer === undefined) ? null : this.PausenTimer;

var daueran = itemRegistry.getItem("GarageRule_Dauerlueftung_manuell").getState();
var humout = itemRegistry.getItem("Aussensensoren_AbsoluteLuftfeuchteAussen").getState();
var humin = itemRegistry.getItem("Sensoren_Garage_AbsoluteLuftfeuchteGarage").getState();
var mingap = itemRegistry.getItem("GarageRule_absFeuchte_Diff").getState();
var dauer = itemRegistry.getItem("GarageRule_Ventilation_Intervall").getState();
var pause = itemRegistry.getItem("GarageRule_Ventilation_Pause").getState();
var ventilator = itemRegistry.getItem("Ventilator_Garage").getState();

logger.info("Logik Ventilatorsteuerung gestartet. Absolute Luftfeuchte beträgt Innen: " + humin + " Außen: " + humout)

function Pause() {
  logger.info("Lüftungspause beendet. Automatik aktiv...");
  this.PausenTimer = null;
}

function Lueften() {
  logger.info("Lüftungsintervall beendet. Beginn der Lüftungspause von " + pause + " Minuten.");
  events.sendCommand("Ventilator_Garage", "OFF");
  this.LueftungTimer = null;
  this.PausenTimer = ScriptExecution.createTimer(ZonedDateTime.now().plusMinutes(pause), Pause);
}

if(daueran == "ON") {
  if(ventilator == "OFF") events.sendCommand("Ventilator_Garage", "ON");
  logger.info("Ventilatorsteuerung: manuelle Dauerlüftung eingeschaltet.");
  this.LueftungTimer = null
  this.PausenTimer = null
} else if(humin - humout < mingap) {
    events.sendCommand("Ventilator_Garage", "OFF");
    logger.info("Ventilatorsteuerung: Lüftung aus, da Luftfeuchte Außen höher als Innen.");
	this.LueftungTimer = null
    this.PausenTimer = null
} else if(humin - humout >= mingap) {
    if(dauer > "0" && this.LueftungTimer === null && this.PausenTimer === null) {
      logger.info("Ventilatorsteuerung if works");
      if(ventilator == "OFF") events.sendCommand("Ventilator_Garage", "ON");
      this.LueftungTimer = ScriptExecution.createTimer(ZonedDateTime.now().plusMinutes(dauer), Lueften);
      logger.info("Ventilatorsteuerung: Lüftung an für " + dauer + " Minuten.");
    } 
} else if(dauer == "0") {
    if(ventilator == "ON") {
      events.sendCommand("Ventilator_Garage", "OFF");
      logger.info("Ventilatorsteuerung ausgeschaltet.","Intervaldauer beträgt: " + dauer + " Minuten.");
    }
  }
Hier noch der complette Code der Rule inkl. Trigger:

Code: Alles auswählen

triggers:
  - id: "1"
    configuration:
      itemName: Aussensensoren_AbsoluteLuftfeuchteAussen
    type: core.ItemStateChangeTrigger
  - id: "2"
    configuration:
      itemName: Sensoren_Garage_AbsoluteLuftfeuchteGarage
    type: core.ItemStateChangeTrigger
  - id: "3"
    configuration:
      itemName: GarageRule_absFeuchte_Diff
    type: core.ItemStateChangeTrigger
  - id: "4"
    configuration:
      itemName: GarageRule_Ventilation_Intervall
    type: core.ItemStateChangeTrigger
  - id: "5"
    configuration:
      itemName: GarageRule_Ventilation_Pause
    type: core.ItemStateChangeTrigger
  - id: "6"
    configuration:
      itemName: GarageRule_Dauerlueftung_manuell
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "7"
    configuration:
      type: application/javascript
      script: >
        var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
        var ZonedDateTime = Java.type("java.time.ZonedDateTime");  
        var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.Examples");

        this.LueftungTimer = (this.LueftungTimer === undefined) ? null : this.LueftungTimer;
        this.PausenTimer = (this.PausenTimer === undefined) ? null : this.PausenTimer;

        var daueran = itemRegistry.getItem("GarageRule_Dauerlueftung_manuell").getState();
        var humout = itemRegistry.getItem("Aussensensoren_AbsoluteLuftfeuchteAussen").getState();
        var humin = itemRegistry.getItem("Sensoren_Garage_AbsoluteLuftfeuchteGarage").getState();
        var mingap = itemRegistry.getItem("GarageRule_absFeuchte_Diff").getState();
        var dauer = itemRegistry.getItem("GarageRule_Ventilation_Intervall").getState();
        var pause = itemRegistry.getItem("GarageRule_Ventilation_Pause").getState();
        var ventilator = itemRegistry.getItem("Ventilator_Garage").getState();

        logger.info("Logik Ventilatorsteuerung gestartet. Absolute Luftfeuchte beträgt Innen: " + humin + " Außen: " + humout)
        
        function Pause() {
          logger.info("Lüftungspause beendet. Automatik aktiv...");
          this.PausenTimer = null;
        }
        function Lueften() {
          logger.info("Lüftungsintervall beendet. Beginn der Lüftungspause von " + pause + " Minuten.");
          events.sendCommand("Ventilator_Garage", "OFF");
          this.LueftungTimer = null;
          this.PausenTimer = ScriptExecution.createTimer(ZonedDateTime.now().plusMinutes(pause), Pause);
        }
        if(daueran == "ON") {
          if(ventilator == "OFF") events.sendCommand("Ventilator_Garage", "ON");
          logger.info("Ventilatorsteuerung: manuelle Dauerlüftung eingeschaltet.");
          this.LueftungTimer = null
          this.PausenTimer = null
        } else if(humin - humout < mingap) {
            events.sendCommand("Ventilator_Garage", "OFF");
            logger.info("Ventilatorsteuerung: Lüftung aus, da Luftfeuchte Außen höher als Innen.");
        	this.LueftungTimer = null
            this.PausenTimer = null
        } else if(humin - humout >= mingap) {
            if(dauer > "0" && this.LueftungTimer === null && this.PausenTimer === null) {
              logger.info("Ventilatorsteuerung if works");
              if(ventilator == "OFF") events.sendCommand("Ventilator_Garage", "ON");
              this.LueftungTimer = ScriptExecution.createTimer(ZonedDateTime.now().plusMinutes(dauer), Lueften);
              logger.info("Ventilatorsteuerung: Lüftung an für " + dauer + " Minuten.");
            } 
        } else if(dauer == "0") {
            if(ventilator == "ON") {
              events.sendCommand("Ventilator_Garage", "OFF");
              logger.info("Ventilatorsteuerung ausgeschaltet.","Intervaldauer beträgt: " + dauer + " Minuten.");
            }
          }
    type: script.ScriptAction
Hilfreiche Links:
https://community.openhab.org/t/oh-3-ex ... les/108526
https://medium.com/smartsmarthome/how-t ... 4ec0797d13

...und ja, meine Namensgebungen für Variablen und Items folgen keiner Logik :D