Globale, flexible Fenster-/Tür-Offen-Meldungen

Begonnen von Benni, 20 April 2015, 20:19:31

Vorheriges Thema - Nächstes Thema

Benni

Globale und flexible Fenster- und Türüberwachung

Aus der Idee und Anregung aus folgendem Thread "Dynamischer Watchdog" habe ich für mich eine flexible Fenster und Türüberwachung aufgebaut, die mir entsprechende Meldungen auf mein Handy schickt (via Pushover), wenn ein Fenster, bzw. eine Tür bestimmte Mindest-Zeit lang offen ist.

Es kann (!) dabei variabel für jeden Fenster- (FK) und Türkontakt (TK) per Attribute festgelegt werden, nach welcher Zeit die Meldung erscheinen soll, bzw. nach welcher weiteren Zeit ggf. nochmals gewarnt werden soll und wie oft gewarnt werden soll.

Zusätzlich habe ich für die Verwendungen in den Meldungen zwei weitere Attribute in Verwendung, mit denen zum Einen eine sprechende Bezeichnung für das Fenster oder die Tür (Bspw. "Das Toilettenfenster im OG") und ein "Gerätetyp" (Bspw. "Fenster") angegeben werden können.

Bisher hatte ich dazu für jedes Fenster, bzw. für jede Tür entsprechend einen oder mehrere Watchdog-devices, die das übernommen haben.Jetzt gibt es dazu insgesamt  für alles nur noch 2 Notifies, sowie 2 Funktionen in der 99_MyUtils.pm, die von den Notifies aufgerufen werden.
Soll nun für einen FK oder TK eine Überwachung eingerichtet werden, müssen nur noch die entsprechenden Attribute als userattr definiert und belegt werden. Im einfachsten muss lediglich das Attribut winOpenMaxTrigger angegeben werden und das sollte größer 0 sein. Ist dieses Attribut größer als 1 angegeben, so werden entsprechend Wiederholungs-Meldungen ausgegeben (n-1 Wiederholungen).

Weitere mögliche Attribute, die (optional) beim auslösenden Device angegeben werden können sind folgende:

  • winOpenName   - Ein schöner Klartext-Name für das Device für die Meldung (Default ist alias, bzw. NAME)
  • winOpenType   - Eine Typbezeichnung für die Meldung (Bei mir quasi als Betreff)
  • winOpenTimer  - Die Zeit, die gewartet werden soll, bis die erste Offen-Meldung ausgegeben werden soll (Default 10 Minuten)
  • winOpenTimer2 - Optinaler 2. Zeitraum für die Folgemeldung(en) (Default = winOpenTimer, bzw. 10 Minuten)

Die Attribute müssen beim Device (TK/FK) zuvor per userrattr definiert werden:


attr <device> userattr winOpenMaxTrigger winOpenTimer winOpenTimer2 winOpenType:Fenster,Türe winOpenName


Hier die Details:

Als erstes mal die sub, die von einem notify aufgerufen wird, sobald ein FK oder TK diese durch einen 'open' oder 'tilted'-Event auslöst. Dazu wird von dieser Funktion ein entsprechender Timer (at) angelegt, das den selben Namen hat, wie das auslösende Device, mit angehängtem _OpenTimer.


Kleiner Hinweis: Ich habe den verwendeten Code sehr ausführlich kommentiert, so dass möglichst jeder folgen kann, was in welcher Code-Zeile genau passiert.



sub winOpenStart($;$) {
    #Als Parameter muss der device-Name übergeben werden
    my $dev=shift(@_);
   
    #Optional kann noch ein Zähler für das erneute Triggern übergeben werden,
    #dieser ist per default 0
    my $retrigger=shift(@_);
    $retrigger=0 if (!$retrigger);
   

    #Erst mal prüfen, ob das übergebene device überhaupt existiert
    if ($defs{$dev}) {
   
        #Aus dem device, sofern vorhanden das Attribut winOpenMaxTrigger auslesen, das
        #angibt, wie oft eine Meldung ausgegeben werden soll.
        #Fehlt dieses Attribut oder ist 0, dann wird für das device gar keine Offen-Meldung ausgegeben
        my $maxtrigger=AttrVal($dev,'winOpenMaxTrigger',0);
   
        if($maxtrigger) {
   
      #Festlegen des Namens für den Timer, der angelegt wird um die Meldung nach gewünschter
          #Zeit auszugeben.
          my $devtimer=$dev.'_OpenTimer';

          #Sollte dieser Timer bereits existieren, so wird er zunächst gelöscht.
          fhem("delete $devtimer") if ($defs{$devtimer});

 
          #Holen von weiteren Attributen, sofern vorhanden:
         
          #Zeit, nach der die Meldung ausgegeben werden soll
          #Default sind 10 Minuten, falls nicht angegeben
          my $waittime=AttrVal($dev,'winOpenTimer','00:10:00');

          #Zeit für die Folge-Meldungen, sofern abweichend angegeben
          #Default ist die normale Zeit, die oben schon ermittelt wurde
          my $devtimer2=AttrVal($dev,'winOpenTimer2',$waittime);

          #Ein eventuell definierter "schöner" Name für das Device, der in der Meldung ausgegeben werden soll.
          #Ist der nicht angegeben, wird das Device-Alias genommen, fehlt auch das, wir einfach der
          #device-Name genommen.
          my $devname=AttrVal($dev,'winOpenName',AttrVal($dev,'alias',$dev));
         
          #Eine Art Typ (Tür oder Fenster), der bei mir quasi im Betreff der Offen-Meldung angegeben wird
          my $devtype=AttrVal($dev,'winOpenType','Fenster/Tür');

          #Hier wandeln wir noch den state des devices in deutschen Klartext um
          my $devstate='offen';
          $devstate='gekippt' if (ReadingsVal($dev,'state','') eq 'tilted');
         
          #Hier wird, sofern bereits eine Wiederholung der Offen-Meldung ausgegeben werden soll,
          #dies textlich auch so berücksichtigt.
          my $immer='noch ';
          $immer='immer noch ' if ($retrigger>0);

          #Jetzt wird der Ausgabebefehl für die Offenmeldung zusammengebaut
          #(Ich habe eine sub PushInfo, die Betreff und Text als Parameter erhält und aktuell
          # meine Meldungen über Pushover ausgibt)
          my $pushcmd="PushInfo('$devtype','$devname ist $immer $devstate');;";
         
          #Sind wir schon beim Einrichten einer Folgemeldung, muss die Wartezeit für die Folgemeldungen
          #genommen werden.
          $waittime=$devtimer2 if ($retrigger);

          #Wir erhöhen hier den Trigger-Zähler um 1...
          $retrigger+=1;
          #... und fügen das Re-Triggern als weitere Code-Zeile für das at-DEF an.
          #das sorgt dann dafür, dass diese Funktion hier nach Ablauf des Timers einfach wieder
          #getriggert wird, um einen neuen Timer anzulegen für die Folgemeldung
          $pushcmd.="winOpenStart('$dev','$retrigger');;" if($retrigger < $maxtrigger);

         
          #Nachdem wir hier alles zusammen haben,
          #legen wir den Timer (das at) an und legen ihn freundlicherweise in den, bzw. die
          #selben Räumen ab, wie auch das auslösende device.
          fhem("define $devtimer at +$waittime {$pushcmd}");
          fhem("attr $devtimer room ".AttrVal($dev,'room','Unsorted'));
        }
    }
}


Hinweis: Die in der winOpenStart enthaltene Funktion "PushInfo()" muss natürlich durch eine eigene Push oder E-Mail-Funktion ersetzt werden. Im einfachsten Fall und zum Testen kann man hier auch einfach mal einen Log-Eintrag mittels Log3() erzeugen.
(Ein Beispiel dazu gibt's inzwischen ein paar Posts weiter unten in diesem Thread.)


Das Notify, das diese Funktion hier aufruft, ist bei mir relativ global gefasst, da alles andere direkt in der Funktion abgefragt, bzw. abgefangen wird:


define winOpen.OpenNotify notify .*:(open|tilted) {winOpenStart($NAME)}


Weiterhin gibt es noch ein 2. Notify, das auf den entsprechenden closed-Event triggert und den Timer auch wieder löscht, sofetn dieser noch aktiv ist. Dieses ist ebenso relativ global gefasst:


define winOpen.CloseNotify notify .*:closed {winOpenStop($NAME)}



sub winOpenStop($) {
    #Dazu muss das entsprechende device (TK/FK) per Name hierher übergeben werden

    #Den übergebenen device-Namen holen
    my ($dev)=@_;

    #Den Namen des Timers zusammenbauen
    my $devtimer=$dev.'_OpenTimer';
       
    #Existiert ein Timer diesen Namens, so wird er jetzt gelöscht und das war's auch schon.
    if ($defs{$devtimer}) {
        fhem("delete $devtimer");
    }
}


Als Fensterkontakte habe ich bei mir übrigens von Homematic den HM-SEC-SC-2 bzw. den HM-SEC-RHS in Verwendung.

Beispiel:

Als kleines Beispiel kann zum Testen ja mal ein einfacher Dummy definiert werden:

Zitat
Internals:
   CFGFN
   NAME       FensterTestDummy
   NR         7060
   STATE      closed
   TYPE       dummy
   CHANGETIME:
   Readings:
     2015-04-19 22:24:51   state           closed
Attributes:
   room       DEVELOP
   setList    open closed tilted
   userattr   winOpenMaxTrigger winOpenTimer winOpenTimer2 winOpenType:Fenster,Türe winOpenName
   webCmd     closed:open:tilted
   winOpenMaxTrigger 3
   winOpenName Fenster Test-Dummy
   winOpenTimer 00:00:15
   winOpenTimer2 00:00:30
   winOpenType Fenster

Update 08.05.2019: @flummy1978 hat in folgendem Beitrag seine Umsetzung mit sleep, statt at zur Verfügung gestellt. Ich selbst habe es nicht getestet, da bisher aber keine negativen Rückmeldungen gekommen sind, gehe ich davon aus, dass es funktioniert:

Zitat von: flummy1978 am 10 April 2019, 22:25:33
Ich habe das jetzt mit sleep & cancel sleep übernommen und umgesetzt.

slor

Sehr Cool! Sowas habe ich schon lange gesucht!
Könnte man das Intervall noch an die Außentemperatur koppeln?
Je kälter, fest schneller kommt die Warnung.
Fhem auf Raspberry Pi 4
CCU3 mit RaspberryMatic mit HMCCU an FHEM
HMCCU, Telegram, Conbee2 und Hue/Tradfri/Osram Lampen AQARA Sensoren, HomeConnect

Benni

Klar könnte man!
Man kann das ganze im Prinzip beliebig komplex stricken.

Man kann aber auch einfach das Intervall für die Meldung und ggf. die Wiederholungen relativ kurz setzen und dann einfach die erste Meldung ignorieren und erst nach der 2., 3. oder .... x-ten aufstehen und das Fenster wieder zu machen. ;)

Ob es kalt (oder zu warm) ist oder nicht, weiß man ja i.d.R. sowieso und wenn nicht, könnte man sich relativ einfach auch die aktuelle Außentemperatur in der Meldung mit anzeigen lassen.

Hollo

Das macht einen sehr guten Eindruck.
Das global gehaltene gefällt mir und läßt sich sicher flexibel anpassen.

Kleine Anmerkung; müssen die beiden Notify (Notifies?) nicht anders definiert werden!?


define winOpen.OpenNotify notify .*:(open|tilted) {winOpenStart($NAME)}



define winOpen.CloseNotify notify .*:closed {winOpenStop($NAME)}

FHEM 6.x auf RPi 3B Buster
Protokolle: Homematic, Z-Wave, MQTT, Modbus
Temp/Feuchte: JeeLink-Clone und LGW mit LaCrosse/IT
sonstiges: Linux-Server, Dreambox, "RSS-Tablet"

selfarian

Hollo hat Recht ^^ danke! Hatte das garnicht gesehen, und mich über die Fehlermeldung gewundert ;)
Aber mit der Korrektur geht es ;)
RasPi mit HMLAN, 5x HM-SEC-SC, HM LED16 als Alarmanlagendisplay, HM-TC-IT-WM-W-EU, 4x HM-CC-RT-DN, 1x HM PBU, 1x HM PBI-4

Benni

#5
Ups! Das passiert, wenn man mal  was nicht per Copy&Paste übernimmt  ;D

Ich habe das im ersten Post inzwischen korrigiert.

<klugscheissermodus>
Ach, übrigens gibt es zu notify eigentlich gar keinen Plural, da notify ein Verb ist. Das Substantiv dazu wäre notification und der Plural dann notifications
</klugscheissermodus>

harway2007

 :o
1.
also - obwohl alles richtig kopiert und subs abgelegt .. produziert keine at befehle im raum der Sensoren
(Raum heisst bei mir "Tuerschloss1")
2.
und die Ausgabe über
sub PushInfo($$$$$) {
my ($uebergabe) = @_;
fhem("set MyTTS tts hier die meldungen $uebergabe ");
}
klappt auch nicht ..
3.
und wie bitte kann man die die 10 Minuten in der sub für einzelne Sensoren übersteuern ?

bitte mal prüfen ob da nicht im Ablauf was fehlt oder falsch ist ...

MFG Harway

Benni

1. Wie sieht denn dein device für Tuerschloss1 aus? Gib mal bitte ein list des device an.

2. Wie sehen denn deine beiden notify aus? (jeweils noch ein list bitte) Meine PushInfo erwartet übrigens 2 Parameter und nicht 5, so wie deine. Steht irgendwas im Log?

3. Zum "übersteuern" der Zeiten gibt es die beiden Attribute winOpenTimer und winOpenTimer2.

Der Ablauf ist übrigens geprüft, getestet und bei mir Produktiv im Einsatz.

stromer-12

Bei mir funktioniert die Routine.
Ist doch alles im 1.Post erklärt.

Ich habe sie nachträglich auf einen Aufruf geschrumpft.
FHEM (SVN) auf RPi1B mit HMser | ESPLink
FHEM (SVN) virtuell mit HMLAN | HMUSB | CUL

stromer-12

Ach ja im Start notify ist im 1.Post noch ein Fehler.
Zwischen open und tilted muss ein "|" und kein ":"
FHEM (SVN) auf RPi1B mit HMser | ESPLink
FHEM (SVN) virtuell mit HMLAN | HMUSB | CUL

Benni

Da kann ich mich ja direkt nochmal selbst zitieren  8)

Zitat von: Benni am 21 April 2015, 10:25:49
Ups! Das passiert, wenn man mal  was nicht per Copy&Paste übernimmt  ;D

Den ersten Post habe ich dementsprechend nochmals korrigiert.

Hollo

Zitat von: stromer-12 am 23 April 2015, 10:53:19
Ach ja im Start notify ist im 1.Post noch ein Fehler.
Zwischen open und tilted muss ein "|" und kein ":"
Darauf hatte ich als "Klugscheisser" ja schon direkt hingewiesen.  ;D
Egal, solche Codeschnipsel sind Gold wert und kleine Tippfehler erkennt man meist duch aufmerksames Lesen der Fehlermeldung.
FHEM 6.x auf RPi 3B Buster
Protokolle: Homematic, Z-Wave, MQTT, Modbus
Temp/Feuchte: JeeLink-Clone und LGW mit LaCrosse/IT
sonstiges: Linux-Server, Dreambox, "RSS-Tablet"

HoTi

He das muss ich doch Test.
Mit Log3, ich habe noch nicht verstanden wie ich anstelle des Log ein Fhem befehl absetze?! Kann mir das einer sagen? (Set msg "test")

Das Log sieht so aus:

FensterTestDummy_OpenTimer: Not enough arguments for main::Log3 at (eval 6278) line 1, near "'Fenster Test-Dummy ist noch  offen')"

Da stimmt doch irgendwas noch nicht?
Viele Grüße aus  Oberbayern
Tim (RettungsTim)

Benni

Log3(undef,3,'blahblahblah');

http://forum.fhem.de/index.php?topic=14341.0


Im Kontext von winOpenStart dann irgendwie so:

Log3($dev,1,"Fenster ist noch offen");

Alternativ geht hier natürlich auch immer noch problemlos das da

Log(1,'Fenster ist noch offen');


QuesT

Hallo Benni,

danke sowas hab ich schon gesucht.
Da ich auch ein Meldung via Pushover senden will könntest du deine Sub dazu auch noch posten?
Denn das ganze ist noch eine nummer zu hoch für mich.

Danke