Timer in einer Rule mit Gruppen

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Absinthe
Beiträge: 78
Registriert: 16. Jan 2022 13:30

Timer in einer Rule mit Gruppen

Beitrag von Absinthe »

Hallo zusammen,

ich habe mir eine Rule geschrieben, die mir eine Info schickt, wenn ein Thermostat aus einer Gruppe einen gewissen Wert überschreitet.

Die Rule schickt mir dann eine Pushnachricht mit dem auslösenden Item aus der Gruppe und die Uhrzeit der Messung. Problem dabei ist, wenn ein Item auslöst erhalte ich mit jeder Temperaturänderung eine Nachricht aus dem Raum. Waren in den letzten 10 Minuten 200 Nachrichten ;)

Ich würde nun gerne einen Timer in die Rule einbauen, der für das "auslösende" Item läuft, nicht aber für die anderen noch nicht ausgelösten Items gilt. Also das Item meldet die Temperatur und ist dann für 15 Minuten gesperrt. Die anderen Items in der Gruppe lösen dennoch die Rule weiterhin aus, solange diese sich nicht in dem 15 Minuten-Modus befinden. Ich hoffe es wird klar, worauf ich hinauswill.

Jemand eine clevere Idee, wie sich dies umsetzen lässt?

Schöne Grüße
OpenHAB 4.1.1
in einem Docker-Container
auf einer Synology DS1515+

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

Re: Timer in einer Rule mit Gruppen

Beitrag von udo1toni »

Du kannst das natürlich auch mit den eingebauten Timern lösen. Allerdings wirst Du dann entweder eine Hashmap verwenden müssen oder sehr umständlich programmieren. Es gibt aber auch einen sehr einfachen Weg, der sich hier geradezu aufdrängt, denn es geht ja nur um einen Timeout.
Das Zauberwort heißt expiration Time (ok, zwei Worte)
Du legst eine zweite Gruppe an. Typ ist egal. Du legst pro Temperatur-Item ein Switch Item an, so dass Du jeweils Itempaare hast. Der Name des Switch Items muss sich aus dem Namen des Temperatur-Items ableiten lassen (und umgekehrt). Z.B. so:

Wohnzimmer_Temperatur (Member Deiner Temperatur-Gruppe)
Wohnzimmer_tempswitch (Member der neuen Gruppe)

Wichtig ist auch, dass die Namen konsistent aufgebaut sind, im Beispiel oben also der Raumname der identifizierende Teil ist und als erstes kommt, ohne das verwendete Trennzeichen (der Unterstrich).

Alle Switch Items bekommen als Eigenschaft einen Expiration Timer angelegt (geht über die Item Metadaten). Dabei legst Du fest, dass der Zustand des Items mittels postUpdate zu OFF wechseln soll. Commands und Updates sollen unberücksichtigt bleiben.

Nun kannst Du die Rule so aufbauen:

Code: Alles auswählen

rule "Temperatur Alarm"
when
    Member of gTemperaturen changed
then
    val String strPart = triggeringItem.name.split("_").get(0)
    val mySwitch = gTempswitches.members.filter[i|i.name.startsWith(strPart)].head
    if(mySwitch.state == OFF && (triggeringItem.state as Number).floatValue > 22) {
        // Alarm-Meldung generieren
        mySwitch.postUpdate(ON)
    }
end
Die Rule "merkt" sich also, dass sie Alarm für das Schwesteritem gegeben hat, indem sie den Schalter auf ON setzt. Über die Expiration setzt openHAB den Status wieder zurück auf OFF.

Man kann wie gesagt mit einer Hashmap auch passende Timer anlegen und im Timer auch wieder löschen lassen, so dass die Rule auf die Existenz der Timer testen kann. Das ist aber ungleich schwerer zu programmieren (geht, aber eben nicht einfach so).
Da Items nichts kosten :) sollte man sie ausgiebig nutzen.
Du kannst sogar in der UI abbilden, welche Alarme in den letzten x Minuten aktiv waren (Zeige Liste der Items aus der Gruppe gTempswitches mit dem Zustand ON).
Du kannst die Tot-Zeiten pro Item unterschiedlich setzen... und bestimmt geht noch mehr, was mir jetzt nicht einfällt.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Absinthe
Beiträge: 78
Registriert: 16. Jan 2022 13:30

Re: Timer in einer Rule mit Gruppen

Beitrag von Absinthe »

Hallo @udo1toni,

vielen, vielen, vielen Dank für Deine ausführliche Antwort! Großartig!!!! :o

Die Idee mit den Experation Timern ist mir auch gekommen. Ich hatte nur wenig Lust, für jedes Item ein Schwesteritem anzulegen.

Die Namensaufbau ist weitestgehend konsistent. Hier am Beispiel der Küche zuerst das Stockwerk, dann Raum und anschließend die Funktion. Immer getrennt mit einem Unterstrich.

Item: EG_Kueche_Temperatur
Schwesteritem könnte: EG_Kueche_Temperatur__ExTimer (Als Trennzeichen zwei Unterstriche)

--> Könnte dies so funktionieren?

-------

Frage: Ist es in OH3 möglich, dass ich in die RRD4j (Persistence Service) den Zeitstempel des letzten Nachrichten Versandes schreiben lasse und diesen dann aufrufe und vergleiche, ob dies länger als 15 Minuten her ist?


Grüße
OpenHAB 4.1.1
in einem Docker-Container
auf einer Synology DS1515+

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

Re: Timer in einer Rule mit Gruppen

Beitrag von udo1toni »

Ausgerechnet RRD4J muss zwingend mindestens mit der Strategie everyMinute gefüllt werden :) Und es nutzt ja nichts, den Zeitstempel zu notieren, Du musst zusätzlich auch noch wissen, welche Nachricht versandt wurde.
Namen der Items: Das Problem mit dem Unterstrich zwischen Stockwerk und Raumname ist halt: reicht der Raumname alleine aus, um das Item eindeutig zu identifizieren? der Indikator muss am Stück stehen, sonst werden die Formeln zur Berechnung des Namens schnell sehr komplex. Wenn alle Temperatur-Items sich zwischen erstem und zweiten Unterstrich stark genug unterscheiden, kannst Du natürlich auch diesen Teil betrachten. In der Rule muss es dann halt etwas anders heißen:

Code: Alles auswählen

rule "Temperatur Alarm"
when
    Member of gTemperaturen changed
then
    val String strPart = triggeringItem.name.split("_").get(1) // der zweite Teilstring
    val mySwitch = gTempswitches.members.filter[i|i.name.contains(strPart)].head // Teilstring ist enthalten
    if(mySwitch.state == OFF && (triggeringItem.state as Number).floatValue > 22) {
        // Alarm-Meldung generieren
        mySwitch.postUpdate(ON)
    }
end
Wie gesagt kannst Du mit einer Hashmap arbeiten, aber der Aufwand ist ungleich höher, ich rate zum Anlegen der Items. Tipp hierzu: das geht auch über eine Textdatei, notfalls kannst Du sogar die Textdatei importieren, so dass die Items anschließend ganz normal in der UI editierbar sind.

Ich bin mir gerade nicht sicher, wie man expire über die Tags steuert, aber evtl so:

Code: Alles auswählen

Switch Kueche_ExTimer "ExTimer Küche" (gTempswitches) {expire="15m,state=OFF"}
Du legst einfach eine Zeile für jede Temperatur an. Entweder speicherst Du die Datei dann unter dem vollständigen Namen /etc/openhab/items/extimer.items ab (Name selbst ist natürlich frei, Speicherort und Endung aber nicht), dann sollten alle eingetragenen Items sofort auftauchen, oder Du nimmst die Datei und lädst sie über Add Items from textual deinition in openHAB rein.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Absinthe
Beiträge: 78
Registriert: 16. Jan 2022 13:30

Re: Timer in einer Rule mit Gruppen

Beitrag von Absinthe »

Hallo @udo1toni,

Vielen Dank, ich hab's zum Laufen gebracht. Bei den Temperaturanzeigen funktioniert dies über das zweite Wort. Etwas tricky, da man aufpassen muss, dass das Timer Item mit dem zweiten Wort des "Geber"-Items startet.

Leider habe ich eine gleiche Logik bei dem Bewegungsmeldern angewendet. Hier wiederholt sich allerdings das zweite Wort und ist nicht einzigartig.

Hier habe ich:

EG_Flur_BWM
OG_Flur_BWM
KG_Flur_BWM

Eine Idee, wie ich dies lösen könnte? Mir würde nur einfallen, hier die Trennung über zwei Unterstriche zu machen?!
OpenHAB 4.1.1
in einem Docker-Container
auf einer Synology DS1515+

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

Re: Timer in einer Rule mit Gruppen

Beitrag von udo1toni »

Wenn Du Gruppen in dieser Form nutzt, musst Du bei der Namensgebung der Items konsistent sein. In diesem Fall müsstest Du notfalls dafür sorgen, dass die drei Flure nicht mehr einfach Flur heißen, sondern z.B. (auch wenn es redundant ist) FlurEG, FlurOG und FlurKG, ergibt dann EG_FlurEG_BWM usw. und alles ist wieder gut.
Es kommt auch etwas darauf an, ob Du den Unterstrich hier nur eingebaut hast, um die Begriffe optisch zu trennen, dann wäre mein Rat, auf den Unterstrich in dieser Form zu verzichten. In openHAB wird allgemein mit CamelCase gearbeitet, nicht mit Unterstrich_statt_Leerzeichen.

Oder Du nutzt die kompletten Itemnamen, die sind ja auf jeden Fall unterschiedlich. Die Itemnamen der Hilfsswitches werden dadurch halt länger. Die Rule sähe dann so aus:

Code: Alles auswählen

rule "Temperatur Alarm"
when
    Member of gTemperaturen changed
then
    val mySwitch = gTempswitches.members.filter[i|i.name.startsWith(triggeringItem.name)].head
    if(mySwitch.state == OFF && (triggeringItem.state as Number).floatValue > 22) {
        // Alarm-Meldung generieren
        mySwitch.postUpdate(ON)
    }
end
Also sogar kürzer als vorher, dafür muss das Hilfsitem dann halt den kompletten Namen des Temperaturitems tragen, plus eine Erweiterung.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Absinthe
Beiträge: 78
Registriert: 16. Jan 2022 13:30

Re: Timer in einer Rule mit Gruppen

Beitrag von Absinthe »

Hallo @udo1toni

Noch einmal vielen Dank! Es klappt und tut was es soll. Auch die verkürzte Rule ;)

Nur eines ist seltsam. Die Rule erzeugt einen Fehler und ich komme diesem nicht auf den Grund...

Im Log steht: 2022-09-02 22:31:25.886 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Test_7' failed: cannot invoke method public abstract org.openhab.core.types.State org.openhab.core.items.Item.getState() on null

Eine Idee woher das kommen könnte? Ist dies vllt. die Gruppe als solche?

Witziger (IRONIE) Nebeneffekt ist, dass sich durch diesen Fehler anscheinend nach mehreren Stunden irgendwann OH3 daran so verschluckt, dass es komplett sich aufhängt und nur ein Neustart Abhilfe schafft...
OpenHAB 4.1.1
in einem Docker-Container
auf einer Synology DS1515+

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

Re: Timer in einer Rule mit Gruppen

Beitrag von udo1toni »

Dann ist einer der Fühler defekt. Das Item, welches die Rule ausgelöst hat, hat keinen gültigen Zahlenwert als Status, weshalb der anschließende Vergleich scheitert.
Wir können dafür Sorge tragen, dass es keine hässliche Fehlermeldung gibt. :)

Code: Alles auswählen

rule "Temperatur Alarm"
when
    Member of gTemperaturen changed
then
    if(!(newState instanceof Number)) {
        logWarn("tempalarm","Rule durch {} getriggert. Der Wert {} ist keine gültige Zahl!",triggeringItem.name,newState)
        return;
    }
    val mySwitch = gTempswitches.members.filter[i|i.name.startsWith(triggeringItem.name)].head
    if(mySwitch.state == OFF && (newState as Number).floatValue > 22) {
        // Alarm-Meldung generieren
        mySwitch.postUpdate(ON)
    }
end
Auf diese Weise bekommst Du eine sinnvolle Meldung, aus der Du ablesen kannst, welches Item der Übertäter war und welchen Status es beim Triggern hatte.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Absinthe
Beiträge: 78
Registriert: 16. Jan 2022 13:30

Re: Timer in einer Rule mit Gruppen

Beitrag von Absinthe »

Das ist jetzt echt seltsam.

Die Meldung kommt immer noch im log.

Dein Logeintrag aus der Rule wird allerdings nicht ausgelöst.

Hier mal die Rule, so wie ich diese im Openhab stehen habe...

Code: Alles auswählen

configuration: {}
triggers:
  - id: "2"
    configuration:
      groupName: Group_Temperatur
    type: core.GroupStateUpdateTrigger
conditions: []
actions:
  - inputs: {}
    id: "1"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-
        
        var String ItemNameHot = triggeringItem.label.toString

        if(!(newState instanceof Number)) { logWarn("tempalarm","Rule durch {} getriggert. Der Wert {} ist keine gültige Zahl!",triggeringItem.name,newState) return;}

        val mySwitch = Group_Temperatur_ExpirationTimer_2.members.filter[i|i.name.startsWith(triggeringItem.name)].head

        if(mySwitch.state == OFF && ((triggeringItem.state as DecimalType).intValue > 20)){

        val mailActions = getActions("mail","mail:smtp:Mail_SMTP")

        val success = mailActions.sendMail("Mail-Adresse@irgendwas.com", "Testing - OPENHAB", "Raumtemperatur ist über "+(triggeringItem.state as DecimalType).doubleValue+"°. Ausgelöst hat Raumtemperaturmelder: "+ItemNameHot+". Status vom: "+new DateTimeType().format("%1$td.%1$tm.%1$ty %1$tH:%1$tM"))

        val actions = getActions("pushover", "pushover:pushover-account:Gruppenname")
                
        actions.sendHtmlMessage("<font color='orange'>openHab - Testing</font>", "Raumtemperatur ist über "+(triggeringItem.state as DecimalType).doubleValue+"°. Ausgelöst hat Raumtemperaturmelder: "+ItemNameHot+". Status vom: "+new DateTimeType().format("%1$td.%1$tm.%1$ty %1$tH:%1$tM"))

        mySwitch.postUpdate(ON)

        }
    type: script.ScriptAction

Ist hier irgendwo noch ein Fehler drin, der diesen Logeintrag erklären würde?
OpenHAB 4.1.1
in einem Docker-Container
auf einer Synology DS1515+

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

Re: Timer in einer Rule mit Gruppen

Beitrag von udo1toni »

Ja, groupStateUpdateTrigger ist etwas anderes als groupStateChangeTrigger.

Verwende nach Möglichkeit nicht DecimalType, sondern Number
Da Du den konkreten Wert ausgeben möchtest und das sogar mehrfach tust, bietet es sich an, diesen in eine lokale Konstante auszulagern.
Außerdem ist ein Zahlenwert etwas anderes als ein String. Du verkettest hier Zahlen mit Strings. Das kann gutgehen (openHAB versucht an vielen Stellen automatisch, die Funktion .toString aufzurufen), kann aber auch schief gehen.

Versuche es mal so: (ich habe den yaml Rahmen der Einfachheit halber weg gelassen).

Code: Alles auswählen

if(!(newState instanceof Number)) {
    logWarn("tempalarm","Rule durch {} getriggert. Der Wert {} ist keine gültige Zahl!",triggeringItem.name,newState) 
    return;
}
val Number nValue = (newState as Number)

val mySwitch = Group_Temperatur_ExpirationTimer_2.members.filter[i|i.name.startsWith(triggeringItem.name)].head
if(mySwitch.state == OFF && nValue.intValue > 20) {
    val mailActions = getActions("mail","mail:smtp:Mail_SMTP")
    val pushoverActions = getActions("pushover", "pushover:pushover-account:Gruppenname")
    val String strMessage = "Raumtemperatur ist über " + nValue.doubleValue.toString + "°C. Ausgelöst hat Raumtemperaturmelder " + triggeringItem.label + ". Status vom: "+new DateTimeType().format("%1$td.%1$tm.%1$ty %1$tH:%1$tM")
    val success = mailActions.sendMail("Mail-Adresse@irgendwas.com", "Testing - OPENHAB", strMessage)
    pushoverActions.sendHtmlMessage("<font color='orange'>openHab - Testing</font>", strMessage)
    mySwitch.postUpdate(ON)
}
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Antworten