Alarmanlage - Meldung nach Wartezeit

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
Answers: 0

Alarmanlage - Meldung nach Wartezeit

Beitrag von Absinthe »

Hallo zusammen,

nachdem ich nun nach tatkräftiger Hilfe von udo1toni ( ;) ) endlich meine Regel mit Timern hinbekommen habe, wollte ich mich an eine kleine nervige Sache mit meiner "Alarmanlage" machen.

Ausgangslage ist: Der Bewegungsmelder im Flur meldet einen Alarm, wenn 1. die "Alarmanlage" angeschaltet ist UND 2. wenn mein Handy nicht mit dem WLAN verbunden ist. Das klappt soweit zuverlässig und sehr gut.

Nervig dabei ist allerdings, dass wenn ich nach Hause komme, dass ich jedes mal einen Alarm auslöse, da das Handy etwas zeit braucht, um sich mit dem WLAN zu verbinden und auch, dass der Status im OH3 ankommt.

Meine Lösung wäre ein Timer in die Rule einzubauen, der eine Minuten die Rule "aufhält" und dann erst startet... Wenn ich dann zuhause bin, soll der Timer einfach abgebrochen werden und die Regel beendet.

Code: Alles auswählen

configuration: {}
triggers:
  - id: "1"
    configuration:
      groupName: Group_Bewegungsmelder
      state: ON
    type: core.GroupStateChangeTrigger
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >
        
        var Timer   tAlarm = null 

        var Integer iAlarm = 1    

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

        tAlarm = createTimer(ZonedDateTime.now.plusMinutes(iAlarm), [| 

        if(mySwitch.state == OFF && (Haus_Alarmanlage_Manuell.state == ON || Group_Anwesenheitsstatus.state == OFF)){ 

        var String ItemNameON = triggeringItem.label.toString 

        val String strMessage = "NACHRICHT"

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

        val success = mailActions.sendMail("test@test.de", "Nachricht von Zuhause",strMessage) 

        val actions = getActions("pushover", "pushover:pushover-account:test") 

        actions.sendPriorityMessage(strMessage,"Nachricht von zuhause",1) 

        mySwitch.postUpdate(ON) } else {
            tAlarm = null
        }  ])  
    type: script.ScriptAction

Klappt nur leider nicht und ich bekomme ich Log einen Fehler...

Im Log steht:
Cannot refer to the non-final variable tAlarm inside a lambda expression;
Grüße

P.S.: Gundlegend hat mich dieser Post auf die Idee gebracht: viewtopic.php?p=46630&hilit=timer+in+einer+rule#p46630
von udo1toni » 3. Okt 2022 12:41
Absinthe hat geschrieben: 2. Okt 2022 23:59 das bedeutet, dass ich keine Variablen innerhalb der Rule aufmachen sollte, wenn ich eine Mischung aus UI-Rule und DSL-Code betreibe?
Nein. Du kannst Variablen und Konstanten nach Belieben anlegen. Nur kannst Du keine globalen Variablen anlegen.

Streng genommen sind die globalen Variablen in *.rules Dateien auch nicht wirklich global. Sie sind auf die Rules beschränkt, welche sich in der gleichen Datei befinden.
Typischer Workaround: Du nutzt statt einer globalen Variablen ein Item. Das funktioniert für Werte, die übergeben werden sollen, aber leider nicht für den Timer, eine Timer Variable enthält einen Zeiger auf einen Eintrag im openHAB Scheduler.
Solange Du eine Variable nur innerhalb einer Rule verwenden willst, gibt es auch die Möglichkeit, den Wert vom letzten Durchlauf erneut zu laden (wobei ich mir nicht sicher bin, ob das in der DSL funktioniert, oder doch nur mit ECMA Code).
Das Item wäre z.B. ein Weg, die bereits generierte Alarmmeldung für den Versand zwischenzuspeichern.

Zwei Rules sollten reichen. Es gäbe dafür verschiedene Ansätze, z.B. auch mit einem weiteren Switch Item (im Beispiel AlarmTimer), welches per expiration Timer ein postUpdate(OFF) sendet.

Rules:

Code: Alles auswählen

configuration: {}
triggers:
  - id: "1"
    configuration:
      groupName: Group_Bewegungsmelder
      state: ON
    type: core.GroupStateChangeTrigger
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >
        val mySwitch = Group_Bewegungsmelder_ExpirationTimer.members.filter[i|i.name.startsWith(triggeringItem.name)].head 
        if(mySwitch.state == OFF && (Haus_Alarmanlage_Manuell.state == ON || Group_Anwesenheitsstatus.state == OFF)){ 
            var String ItemNameON = triggeringItem.label.toString 
            val String strMessage = "ACHTUNG: Bewegung erkannt durch " + ItemNameON
            myMessage.postUpdate(strMessage)
            AlarmTimer.postUpdate(ON)
            mySwitch.postUpdate(ON) 
        }
    type: script.ScriptAction


configuration: {}
triggers:
  - id: "1"
    configuration:
      ItemName: AlarmTimer
      state: OFF
    type: core.GroupStateChangeTrigger
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >
        if(Haus_Alarmanlage_Manuell.state == ON || Group_Anwesenheitsstatus.state == OFF){ 
            val strMessage = myMessage.state.toString
            val mailActions = getActions("mail","mail:smtp:Mail_SMTP") 
            val pushActions = getActions("pushover", "pushover:pushover-account:test") 
            mailActions.sendMail("test@test.de", "Nachricht von Zuhause",strMessage) 
            pushActions.sendPriorityMessage(strMessage,"Nachricht von zuhause",1) 
            myMessage.postUpdate("")
        }
    type: script.ScriptAction
Das sind natürlich zwei getrennte Rules, die auch als getrennte Rules über die UI angelegt werden müssen.
Das String Item myMessage speichert die Alarmmeldung, das Item AlarmTimer wird beim Auftreten des Alarms gesetzt, nach Ablauf der hinterlegten Zeit löst es durch das postUpdate(OFF) die zweite Rule aus, welche dann nochmals die Bedingungen abprüft.

In einer DSL Text Rule ginge das alle wesentlich eleganter :) wobei das natürlich auch Geschmackssache ist:

Code: Alles auswählen

var Timer tAlarm = null                                                                // Zeiger auf Scheduler Eintrag
var String strAlarmItem = ""                                                           // Speicher für gemeldete Items

rule "Alarm melden"
when
    Member of Group_Bewegungsmelder changed to ON or
    Item Haus_Alarmanlage_Manuell changed to OFF or
    Item Group_Anwesenheitsstatus changed to ON
then
    if(Haus_Alarmanlage_Manuell.state == OFF && Group_Anwesenheitsstatus.state == ON) { // Falls deaktiviert
        tAlarm?.cancel                                                                  // lösche Timer, falls vorhanden
        tAlarm = null                                                                   // lösche den Zeiger
        strAlarmItem = ""                                                               // entferne den Itemnamen
        return;                                                                         // und brich die Rule ab.
    }
    if(triggeringItem === null) {                                                       // Rule wurde nicht durch Member getriggert
        return;
    }
    val mySwitch = Group_Bewegungsmelder_ExpirationTimer.members.filter[i|
                       i.name.startsWith(triggeringItem.name)
                   ].head
    if(mySwitch.state != OFF){                                                          // wurde bereits alarmiert?
        return;                                                                         // dann Abbruch
    }
    mySwitch.postUpdate(ON)                                                             // Alarmfrequenz begrenzen
    if(strAlarmItem != "")                                                              // Falls schon ein Alarm besteht
       strAlarmItem  = strAlarmItem + ", "                                              // ergänze die Aufzählung
    strAlarmItem  = strAlarmItem + triggeringItem.label                                 // Itemnamen zwischenspeichern
    if(tAlarm !== null)                                                                 // Falls Timer bereits läuft
        return;                                                                         // nicht erneut erzeugen
    tAlarm = createTimer(now.plusSeconds(60),[|                                         // Lege Timer an
        val String strMessage = "ACHTUNG: Bewegung erkannt durch " + strAlarmItem       // Meldetext festlegen
        val mailActions = getActions("mail","mail:smtp:Mail_SMTP")                      // Handle für Mail holen
        val pushActions = getActions("pushover", "pushover:pushover-account:test")      // Handle für Push holen
        mailActions.sendMail("test@test.de", "Nachricht von Zuhause",strMessage)        // Mail versenden
        pushActions.sendPriorityMessage(strMessage,"Nachricht von zuhause",1)           // Push versenden
        strAlarmItem = ""                                                               // Itemnamen entfernen
        tAlarm = null                                                                   // und Zeiger auf Scheduler entfernen
    ])
end
Sieht schlimm aus...
Diese Rule kann allerdings schon etwas mehr :)
Zunächst löst die Rule nicht nur aus, wenn einer der Bewegungsmelder ausgelöst hat, sondern auch, wenn die Schalter für die Scharf Schaltung deaktiviert wurden.

Wird die Rule ausgelöst, so prüft der Code zunächst, ob der Alarm deaktiviert ist. Ist das der Fall, so wir ein eventuell laufender Timer abgebrochen und die Variablen geleert. Anschließend wird die Rule sofort abgebrochen. Das heißt, wenn Du nach Hause kommst, wird der Alarmzustand in dem Moment beendet, wo Dein Smartphone erkannt wurde, nicht erst, wenn der Timer abläuft.

Im nächsten Schritt prüft die Rule, ob triggeringItem null ist. Ist das der Fall, so wurde die Rule durch einen der Schalter ausgelöst und es gibt nichts zu tun (es gab ja keinen Alarm, sondern nur eine Deaktivierung eines Schalters, der andere ist aber noch aktiv, sonst wäre die Rule schon abgebrochen).
Jetzt steht also fest, dass ein Bewegungsmelder ausgelöst hat und auch alarmiert werden soll. Aber darf der Alarm überhaupt weitergereicht werden? das wird nun geprüft, über die zugehörigen Expiration Items, wie gehabt. Ist also der zugehörige Switch ON, kann die Rule wieder abgebrochen werden.
Nun steht endgültig fest, dass es sich um einen zu meldenden Vorfall handelt.

Es könnte nun aber sein, dass bereits ein anderer Alarm auf die Meldung wartet! Dem trägt die Rule Rechnung, indem sie prüft, ob in der Variablen, in der das Itemlabel des Alarms gehalten wird schon etwas steht. Ist das der Fall, so ergänzt sie den String einfach. Auf diese Weise geht kein Name verloren-
Sollte nun der Timer schon existieren, kann die Rule beendet werden.

Nur, wenn noch kein Timer existiert (tAlarm === null) wird der Timer angelegt und die Rule ist fertig.

Wenn der Timer abläuft, werden ohne Wenn und Aber die Meldung raus gegeben und die Variablen geleert.

Einrückungen im Code dienen nur der Lesbarkeit :)

EDIT: Semikolon hinter return ergänzt...
Gehe zur vollständigen Antwort
OpenHAB 4.1.1
in einem Docker-Container
auf einer Synology DS1515+

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

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von udo1toni »

Ja, leider kannst Du keine globalen Variablen über die UI definieren.

Außerdem kannst Du innerhalb des Timers nicht einfach auf Variablen zugreifen, die außerhalb des Timers definiert wurden (es sei denn, sie sind global definiert). Das betrifft vermutlich auch die Variable mySwitch (müsste man halt ausprobieren)

Die erste Frage, die mir in den Sinn kommt: warum braucht Dein Smartphone so lang, sich im WLAN anzumelden? :D

Die andere Sache wäre die Verzögerung. Ich denke, es wäre sinnvoller, das andersrum anzugehen:
Schritt 1: Alarm wird erkannt und auch unmittelbar gemeldet (in dem Sinne, dass eine Aktion ausgelöst wird).
Schritt 1a: Die ausgelöste Aktion ist, einen Timer zu starten, der die notwendigen Informationen bekommt (also z.B. welcher Alarm hat ausgelöst)
Schritt 2: wenn der Timer aus Schritt 1a abläuft, wird der Alarm verschickt, falls niemand zuhause ist.

Wie sah denn das funktionierende Script ohne Timer aus? Ich kann mich gar nicht daran erinnern, eine Alarmanlage gebaut zu haben...
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
Answers: 0

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von Absinthe »

Hallo udo1toni,

das bedeutet, dass ich keine Variablen innerhalb der Rule aufmachen sollte, wenn ich eine Mischung aus UI-Rule und DSL-Code betreibe? Schade - ist sehr praktisch ;)

Gibt es da einen guten "Work-Around"?

Ich vermute, dass es einfach ein paar Sekunden braucht, bis sich das iPhone im "Standby" in meiner Hosentasche mit dem heimischen WLAN beim heimkommen verbindet und auch das ITEM im OH den entsprechenden Status annimmt. Daher auch der Gedanke, diese Zeit mittels Timer zu überbrücken...

Der Code sah nicht viel anders aus... Ich habe die Idee aus dem Beitrag mit der Gartenbewässung "geklaut" :o

Code: Alles auswählen

configuration: {}
triggers:
  - id: "1"
    configuration:
      groupName: Group_Bewegungsmelder
      state: ON
    type: core.GroupStateChangeTrigger
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >
        
        val mySwitch = Group_Bewegungsmelder_ExpirationTimer.members.filter[i|i.name.startsWith(triggeringItem.name)].head 

        if(mySwitch.state == OFF && (Haus_Alarmanlage_Manuell.state == ON || Group_Anwesenheitsstatus.state == OFF)){ 

        var String ItemNameON = triggeringItem.label.toString 

        val String strMessage = "NACHRICHT"

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

        val success = mailActions.sendMail("test@test.de", "Nachricht von Zuhause",strMessage) 

        val actions = getActions("pushover", "pushover:pushover-account:test") 

        actions.sendPriorityMessage(strMessage,"Nachricht von zuhause",1) 

        mySwitch.postUpdate(ON) 
        } 
    type: script.ScriptAction
Hast Du auch nicht ;) Ich habe aus einem anderen Projekt die Alarmanlage erweitert, um einen Timer, der nicht bei jeder Bewegung eine Nachricht schickt... viewtopic.php?t=7233 Die Alarmanlage ist von mir zusammen gestückelt ;)
OpenHAB 4.1.1
in einem Docker-Container
auf einer Synology DS1515+

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

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von udo1toni »

Absinthe hat geschrieben: 2. Okt 2022 23:59 das bedeutet, dass ich keine Variablen innerhalb der Rule aufmachen sollte, wenn ich eine Mischung aus UI-Rule und DSL-Code betreibe?
Nein. Du kannst Variablen und Konstanten nach Belieben anlegen. Nur kannst Du keine globalen Variablen anlegen.

Streng genommen sind die globalen Variablen in *.rules Dateien auch nicht wirklich global. Sie sind auf die Rules beschränkt, welche sich in der gleichen Datei befinden.
Typischer Workaround: Du nutzt statt einer globalen Variablen ein Item. Das funktioniert für Werte, die übergeben werden sollen, aber leider nicht für den Timer, eine Timer Variable enthält einen Zeiger auf einen Eintrag im openHAB Scheduler.
Solange Du eine Variable nur innerhalb einer Rule verwenden willst, gibt es auch die Möglichkeit, den Wert vom letzten Durchlauf erneut zu laden (wobei ich mir nicht sicher bin, ob das in der DSL funktioniert, oder doch nur mit ECMA Code).
Das Item wäre z.B. ein Weg, die bereits generierte Alarmmeldung für den Versand zwischenzuspeichern.

Zwei Rules sollten reichen. Es gäbe dafür verschiedene Ansätze, z.B. auch mit einem weiteren Switch Item (im Beispiel AlarmTimer), welches per expiration Timer ein postUpdate(OFF) sendet.

Rules:

Code: Alles auswählen

configuration: {}
triggers:
  - id: "1"
    configuration:
      groupName: Group_Bewegungsmelder
      state: ON
    type: core.GroupStateChangeTrigger
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >
        val mySwitch = Group_Bewegungsmelder_ExpirationTimer.members.filter[i|i.name.startsWith(triggeringItem.name)].head 
        if(mySwitch.state == OFF && (Haus_Alarmanlage_Manuell.state == ON || Group_Anwesenheitsstatus.state == OFF)){ 
            var String ItemNameON = triggeringItem.label.toString 
            val String strMessage = "ACHTUNG: Bewegung erkannt durch " + ItemNameON
            myMessage.postUpdate(strMessage)
            AlarmTimer.postUpdate(ON)
            mySwitch.postUpdate(ON) 
        }
    type: script.ScriptAction


configuration: {}
triggers:
  - id: "1"
    configuration:
      ItemName: AlarmTimer
      state: OFF
    type: core.GroupStateChangeTrigger
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >
        if(Haus_Alarmanlage_Manuell.state == ON || Group_Anwesenheitsstatus.state == OFF){ 
            val strMessage = myMessage.state.toString
            val mailActions = getActions("mail","mail:smtp:Mail_SMTP") 
            val pushActions = getActions("pushover", "pushover:pushover-account:test") 
            mailActions.sendMail("test@test.de", "Nachricht von Zuhause",strMessage) 
            pushActions.sendPriorityMessage(strMessage,"Nachricht von zuhause",1) 
            myMessage.postUpdate("")
        }
    type: script.ScriptAction
Das sind natürlich zwei getrennte Rules, die auch als getrennte Rules über die UI angelegt werden müssen.
Das String Item myMessage speichert die Alarmmeldung, das Item AlarmTimer wird beim Auftreten des Alarms gesetzt, nach Ablauf der hinterlegten Zeit löst es durch das postUpdate(OFF) die zweite Rule aus, welche dann nochmals die Bedingungen abprüft.

In einer DSL Text Rule ginge das alle wesentlich eleganter :) wobei das natürlich auch Geschmackssache ist:

Code: Alles auswählen

var Timer tAlarm = null                                                                // Zeiger auf Scheduler Eintrag
var String strAlarmItem = ""                                                           // Speicher für gemeldete Items

rule "Alarm melden"
when
    Member of Group_Bewegungsmelder changed to ON or
    Item Haus_Alarmanlage_Manuell changed to OFF or
    Item Group_Anwesenheitsstatus changed to ON
then
    if(Haus_Alarmanlage_Manuell.state == OFF && Group_Anwesenheitsstatus.state == ON) { // Falls deaktiviert
        tAlarm?.cancel                                                                  // lösche Timer, falls vorhanden
        tAlarm = null                                                                   // lösche den Zeiger
        strAlarmItem = ""                                                               // entferne den Itemnamen
        return;                                                                         // und brich die Rule ab.
    }
    if(triggeringItem === null) {                                                       // Rule wurde nicht durch Member getriggert
        return;
    }
    val mySwitch = Group_Bewegungsmelder_ExpirationTimer.members.filter[i|
                       i.name.startsWith(triggeringItem.name)
                   ].head
    if(mySwitch.state != OFF){                                                          // wurde bereits alarmiert?
        return;                                                                         // dann Abbruch
    }
    mySwitch.postUpdate(ON)                                                             // Alarmfrequenz begrenzen
    if(strAlarmItem != "")                                                              // Falls schon ein Alarm besteht
       strAlarmItem  = strAlarmItem + ", "                                              // ergänze die Aufzählung
    strAlarmItem  = strAlarmItem + triggeringItem.label                                 // Itemnamen zwischenspeichern
    if(tAlarm !== null)                                                                 // Falls Timer bereits läuft
        return;                                                                         // nicht erneut erzeugen
    tAlarm = createTimer(now.plusSeconds(60),[|                                         // Lege Timer an
        val String strMessage = "ACHTUNG: Bewegung erkannt durch " + strAlarmItem       // Meldetext festlegen
        val mailActions = getActions("mail","mail:smtp:Mail_SMTP")                      // Handle für Mail holen
        val pushActions = getActions("pushover", "pushover:pushover-account:test")      // Handle für Push holen
        mailActions.sendMail("test@test.de", "Nachricht von Zuhause",strMessage)        // Mail versenden
        pushActions.sendPriorityMessage(strMessage,"Nachricht von zuhause",1)           // Push versenden
        strAlarmItem = ""                                                               // Itemnamen entfernen
        tAlarm = null                                                                   // und Zeiger auf Scheduler entfernen
    ])
end
Sieht schlimm aus...
Diese Rule kann allerdings schon etwas mehr :)
Zunächst löst die Rule nicht nur aus, wenn einer der Bewegungsmelder ausgelöst hat, sondern auch, wenn die Schalter für die Scharf Schaltung deaktiviert wurden.

Wird die Rule ausgelöst, so prüft der Code zunächst, ob der Alarm deaktiviert ist. Ist das der Fall, so wir ein eventuell laufender Timer abgebrochen und die Variablen geleert. Anschließend wird die Rule sofort abgebrochen. Das heißt, wenn Du nach Hause kommst, wird der Alarmzustand in dem Moment beendet, wo Dein Smartphone erkannt wurde, nicht erst, wenn der Timer abläuft.

Im nächsten Schritt prüft die Rule, ob triggeringItem null ist. Ist das der Fall, so wurde die Rule durch einen der Schalter ausgelöst und es gibt nichts zu tun (es gab ja keinen Alarm, sondern nur eine Deaktivierung eines Schalters, der andere ist aber noch aktiv, sonst wäre die Rule schon abgebrochen).
Jetzt steht also fest, dass ein Bewegungsmelder ausgelöst hat und auch alarmiert werden soll. Aber darf der Alarm überhaupt weitergereicht werden? das wird nun geprüft, über die zugehörigen Expiration Items, wie gehabt. Ist also der zugehörige Switch ON, kann die Rule wieder abgebrochen werden.
Nun steht endgültig fest, dass es sich um einen zu meldenden Vorfall handelt.

Es könnte nun aber sein, dass bereits ein anderer Alarm auf die Meldung wartet! Dem trägt die Rule Rechnung, indem sie prüft, ob in der Variablen, in der das Itemlabel des Alarms gehalten wird schon etwas steht. Ist das der Fall, so ergänzt sie den String einfach. Auf diese Weise geht kein Name verloren-
Sollte nun der Timer schon existieren, kann die Rule beendet werden.

Nur, wenn noch kein Timer existiert (tAlarm === null) wird der Timer angelegt und die Rule ist fertig.

Wenn der Timer abläuft, werden ohne Wenn und Aber die Meldung raus gegeben und die Variablen geleert.

Einrückungen im Code dienen nur der Lesbarkeit :)

EDIT: Semikolon hinter return ergänzt...
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
Answers: 0

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von Absinthe »

Wooooowwww! :shock: :shock: :shock:

MEGA VIELEN DANK!!! Ich weiß gar nicht was ich sagen soll... DANKE udo1toni!!!!!

Funktioniert und erfüllt alles was ich möchte 8-)

Noch viel zu lernen ich habe im openHAB... um es mit den Worten eines grünen Kerlchens es auszudrücken ;)

Eine kleine Anpassung habe ich vorgenommen:

Code: Alles auswählen

if(Haus_Alarmanlage.state == OFF || Group_Anwesenheitsstatus.state == ON) {         // Falls deaktiviert
Ich möchte ja, nicht das beides als UND zutreffen muss, damit die Rule abgebrochen wird, sondern es reicht, wenn eine Bedingung erfüllt ist. Deshalb sollte hier doch ein ODER stehen?

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

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

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von udo1toni »

Nein, das UND ist an dieser Stelle schon richtig. Die Logik an dieser Stelle funktioniert umgekehrt zu Deiner Logik. Du prüfst, ob einer der beiden Schalter den Alarm aktiviert hat, ist das der Fall, wird der Alarm ausgewertet.
Im vorliegenden Fall müssen beide Aktivierungen aus sein, Die manuelle Scharfschaltung darf nicht ON sein und es darf keine Abwesenheit gemeldet werden, falls diese Bedingungen erfüllt sind, darf die Rule vorzeitig abgebrochen werden.
Wenn da ein ODER stünde, müssten immer beide Bedingungen erfüllt sein, damit überhaupt alarmiert wird.
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
Answers: 0

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von Absinthe »

hmmm... dann ist hier irgendwo noch der Wurm drin...

Sobald ich längere Zeit zuhause bin löst die Alarmanlage aus, wenn ich mich im Haus bewege...

Ich würde dies später im Code so lösen...

Code: Alles auswählen

     if(Group_Anwesenheitsstatus.state == ON){                                                          	   // Ist jemand zuhause?
        return;                                                                         							  // dann Abbruch
    }
Ich möchte die Alarmanlage nicht ständig ein und ausschalten müssen... Die soll eigentlich automatisch aktiv sein, wenn keiner mehr zuhause ist.
OpenHAB 4.1.1
in einem Docker-Container
auf einer Synology DS1515+

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

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von udo1toni »

Wie gesagt, die Verknüpfung ist da nur drin, damit die Alarmanlage überhaupt manuell scharf geschaltet werden kann. Dann allerdings ist sie in der Form auch wichtig und richtig.
iPhones melden sich gerne mal im WLAN ab, um Strom zu sparen. Da ich selbst kein iPhone nutze, weiß ich nur, dass es irgendeine Möglichkeit gibt, das zu umgehen, aber nicht konkret, wie diese Lösung aussieht.
Sprich, Du müsstest mal gezielt in diese Richtung forschen (Suche hier im Forum dürfte schon zu Treffern führen, späatestens im englischen Forum wirst Du garantiert fündig).
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
Answers: 0

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von Absinthe »

Irgendwas stimmt in der Rule noch nicht... Die iPhones melden ordentlich den Status zuhause. Dieser hält sich auch...

Der manuelle Schalter war eigentlich dazu gedacht, um die Alarmanlage ausschalten zu können, wenn ich sie nicht brauchen kann.

Nur leider funktioniert irgendwas gar nicht. Und zwar melden die ersten beiden Bewegungsmelder einen Alarm, obwohl der Status der Anwesenheit auf "ON" gesprungen ist. Auch wird das Ausschalten der Alarmanlage von der Rule ignoriert und hat keinen Einfluss auf deren Verhalten...

Code: Alles auswählen

var Timer tAlarm = null                                                                // Zeiger auf Scheduler Eintrag
var String strAlarmItem = ""                                                           // Speicher für gemeldete Items

rule "Alarmanlage_Home_Automatik"
when
    Member of Group_Bewegungsmelder changed to ON or
    Member of Group_Fensterkontakt_Binaereingang changed to OPEN or
    Item Haus_Alarmanlage changed to OFF or
    Item Group_Anwesenheitsstatus changed to ON
then
    if(Haus_Alarmanlage.state == OFF && Group_Anwesenheitsstatus.state == ON) {         // Falls deaktiviert
        tAlarm?.cancel                                                                  // lösche Timer, falls vorhanden
        tAlarm = null                                                                   // lösche den Zeiger
        strAlarmItem = ""                                                               // entferne den Itemnamen
        return;                                                                         // und brich die Rule ab.
    }
    if(triggeringItem === null) {                                                       // Rule wurde nicht durch Member getriggert
        return
    }
    if(Group_Anwesenheitsstatus.state == ON){                                           // Ist jemand zuhause?
       return;                                                                         	// dann Abbruch
   }
    val mySwitch = Group_Bewegungsmelder_ExpirationTimer.members.filter[i|i.name.startsWith(triggeringItem.name)].head
    if(mySwitch.state != OFF){                                                          // wurde bereits alarmiert?
        return;                                                                         // dann Abbruch
    }
    mySwitch.postUpdate(ON)                                                             // Alarmfrequenz begrenzen
    if(strAlarmItem != "")                                                              // Falls schon ein Alarm besteht
       strAlarmItem  = strAlarmItem + ", "                                              // ergänze die Aufzählung
    strAlarmItem  = strAlarmItem + triggeringItem.label                                 // Itemnamen zwischenspeichern
    if(tAlarm !== null)                                                                 // Falls Timer bereits läuft
        return;                                                                         // nicht erneut erzeugen
    tAlarm = createTimer(now.plusSeconds(60),[|                                         // Lege Timer an
        val String strMessage = "ACHTUNG: Folgender Bewegungsmelder hat ausgelöst: "+strAlarmItem+". Bewegung erkannt am: "+new DateTimeType().format("%1$td.%1$tm.%1$ty %1$tH:%1$tM") // Meldetext festlegen
        val mailActions = getActions("mail","mail:smtp:Mail_SMTP")                      // Handle für Mail holen
        val pushActions = getActions("pushover", "pushover:pushover-account:Test")      // Handle für Push holen
        mailActions.sendMail("mail@mail.de", "Alarmanlage",strMessage)        // Mail versenden
        pushActions.sendPriorityMessage(strMessage,"Alarmanlage",1)                     // Push versenden
        strAlarmItem = ""                                                               // Itemnamen entfernen
        tAlarm = null                                                                   // und Zeiger auf Scheduler entfernen
    ])
end
Ich habe den Code noch um die Ziele erweitert, wenn jemand zuhause, dass abgebrochen wird... Wenn dieser Teil nicht enthalten ist, läuft die Alarmanlage rund, wenn jemand zuhause und meldet jede Bewegung...

Code: Alles auswählen

if(Group_Anwesenheitsstatus.state == ON){                                           // Ist jemand zuhause?
       return;                                                                         	// dann Abbruch
   }
Jemand eine Idee, woran das liegen könnte?

Zur Vollständigkeit: Ich habe noch die Fensterkontakte als Trigger mit aufgenommen.

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

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

Re: Alarmanlage - Meldung nach Wartezeit

Beitrag von udo1toni »

Du kannst nicht einfach die Ruge ändern, ohne verstanden zu haben, was da passiert.

In Deiner ursprünglichen Rule hast Du geprüft, ob die Anwesenheit auf OFF steht ODER Haus_Alarmanlage auf ON steht. Das heißt, Du kannst mit dem Schalter Haus_Alarmanlage die Anlage manuell EINSCHALTEN, obwohl jemand zuhause ist.
Genauso ist die Anlage auf jeden Fall aktiv, wenn niemand zuhause ist, unabhängig von Haus_Alarmanlage.

Deshalb prüfe ich, ob Haus_Alarmanlage OFF ist UND gleichzeitig auch jemand da ist. Ist das der Fall, bricht die Rule einen eventuell laufenden Timer ab und initialisiert alles so, wie es gebraucht wird, um einen neuen Alarm melden zu können.

Wenn Du nun die Anlage manuell AUSSCHALTEN können willst, obwohl niemand zuhause ist, stimmt die Logik natürlich nicht mehr.
Es reicht aber nicht, einfach eine Bedingung einzubauen, die nichts macht, außer die Rule abzubrechen. Du musst die Schalter stattdessen so verwenden, wie ursprünglich gedacht, d.h. Haus_Alarmanlage muss auf OFF stehen und es muss jemand da sein, dann wird die Regel laufende Timer abbrechen und auch keinen neuen Timer anlegen, denn die Rule bricht ja sofort ab, auch wenn eine Bewegung erkannt wird.

Alternativ hast Du im Hintergrund noch eine alte Version der Rule, die parallel läuft.

Leider ist da auch noch ein return, bei dem hinten kein Semikolon dran steht. (hinter der Abfrage triggeringItem === null). Das Semikolon ist nicht optional, ergänze das bitte noch.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Antworten