[gelöst] offene Fenster zählen und auflisten

Begonnen von Christian80, 13 November 2020, 16:12:07

Vorheriges Thema - Nächstes Thema

Christian80

Hallo zusammen,

ich habe hier im Forum ein DOIF gefunden, welches offene Fenster zählt und habe es für mein Setup angepasst.


defmod d_FK_Anzahl DOIF ([#"Fensterkontakt_.*":state:"open"] > 0)\
(\
  set $SELF openWindowsCount [#"Fensterkontakt_.*":state:"open"],\
  set $SELF openWindowsState open\
)\
DOELSE\
(\
  set $SELF openWindowsCount 0,\
  set $SELF openWindowsState closed\
)
attr d_FK_Anzahl alias d_FK_Anzahl
attr d_FK_Anzahl do always
attr d_FK_Anzahl group Fensterkontakte
attr d_FK_Anzahl readingList openWindowsCount  openWindowsState
attr d_FK_Anzahl room Logik
attr d_FK_Anzahl stateFormat openWindowsState (openWindowsCount)

setstate d_FK_Anzahl open (1)
setstate d_FK_Anzahl 2020-11-13 16:02:02 Device Fensterkontakt_Wohnen1
setstate d_FK_Anzahl 2020-11-13 16:02:02 cmd 1
setstate d_FK_Anzahl 2020-11-13 16:02:02 cmd_event Fensterkontakt_Wohnen1
setstate d_FK_Anzahl 2020-11-13 16:02:02 cmd_nr 1
setstate d_FK_Anzahl 2020-09-05 11:12:44 mode enabled
setstate d_FK_Anzahl 2020-11-13 16:02:02 openWindowsCount 1
setstate d_FK_Anzahl 2020-11-13 16:02:02 openWindowsState open
setstate d_FK_Anzahl 2020-11-13 16:02:02 state cmd_1


Das funktioniert auch soweit.

Gibt es eine Möglichkeit die Namen aller offenen Fenster aufzulisten und in einem Reading zu schreiben?

Danke und schöne Grüße
Christian

Damian

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

xenos1984

Macht das nicht genau das Beispiel aus der CommandRef?

http://fhem.de/commandref_DE.html#DOIF_aggregation

define di_Fenster DOIF (["^Window:open"])
(push "Fenster $DEVICE wurde geöffnet. Es sind folgende Fenster offen: [@"^Window":state:"open"]")
DOELSEIF ([#"^Window:closed":state:"open"] == 0)
(push "alle Fenster geschlossen")

attr di_Fenster do always
attr di_Fenster cmdState [$SELF:Device] zuletzt geöffnet|alle geschlossen



Christian80

Ich habe mir nun folgendes DOIF gebaut:


Internals:
   DEF        ([#"Fensterkontakt_.*":state:"open"] > 0)
(
  set $SELF openWindowsCount [#"Fensterkontakt_.*":state:"open"],
  set $SELF openWindowsState open
)
DOELSE
(
  set $SELF openWindowsCount 0,
  set $SELF openWindowsState closed
)
   DOIFDEV    ^global$|Fensterkontakt_.*
   FUUID      5f53445e-f23f-dffb-48d3-87603c
   MODEL      FHEM
   NAME       d_FK_Anzahl
   NR         273
   NTFY_ORDER 50-d_FK_Anzahl
   STATE      open (2)
   TYPE       DOIF
   VERSION    23235 2020-11-25 22:42:28
   CHANGED:
     windows: Fensterkontakt_Essen2 Fensterkontakt_Wohnen3
   CHANGEDWITHSTATE:
     windows: Fensterkontakt_Essen2 Fensterkontakt_Wohnen3
   DOIF_Readings:
     windows    ::AggregateDoIf($hash,'@as( )','Fensterkontakt_.*','state','"open"','"keine"')
   READINGS:
     2020-12-20 13:04:52   Device          Fensterkontakt_Essen2
     2020-12-20 13:04:52   cmd             1
     2020-12-20 13:04:52   cmd_event       Fensterkontakt_Essen2
     2020-12-20 13:04:52   cmd_nr          1
     2020-09-05 11:12:44   mode            enabled
     2020-12-20 13:04:52   openWindowsCount 2
     2020-12-20 13:04:52   openWindowsState open
     2020-12-20 13:04:52   room_FK         Fensterkontakt_Essen2 Fensterkontakt_Wohnen3
     2020-12-20 13:04:52   state           cmd_1
     2020-12-20 13:04:52   windows         Fensterkontakt_Essen2 Fensterkontakt_Wohnen3
   Regex:
     DOIF_Readings:
       :
         windows:
           "Fensterkontakt_.*" Fensterkontakt_.*
       d_FK_Anzahl:
     accu:
     cond:
       :
         0:
           "Fensterkontakt_.*" Fensterkontakt_.*
   attr:
     cmdState:
     wait:
     waitdel:
   condition:
     0          ::AggregateDoIf($hash,'#','Fensterkontakt_.*','state','"open"') > 0
   do:
     0:
       0             set d_FK_Anzahl openWindowsCount [#"Fensterkontakt_.*":state:"open"],   set d_FK_Anzahl openWindowsState open
     1:
       0             set d_FK_Anzahl openWindowsCount 0,   set d_FK_Anzahl openWindowsState closed
   helper:
     DEVFILTER  ^global$|Fensterkontakt_.*
     NOTIFYDEV  global|.*Fensterkontakt_.*.*
     event      open
     globalinit 1
     last_timer 0
     sleeptimer -1
     timerdev   Fensterkontakt_Essen2
     timerevent open
     triggerDev Fensterkontakt_Essen2
     DOIF_eventa:
       cmd_nr: 1
       cmd: 1
       cmd_event: Fensterkontakt_Essen2
       cmd_1
     DOIF_eventas:
       cmd_nr: 1
       cmd: 1
       cmd_event: Fensterkontakt_Essen2
       state: cmd_1
     timerevents:
       open
     timereventsState:
       state: open
     triggerEvents:
       open
     triggerEventsState:
       state: open
   internals:
   perlblock:
   readings:
   trigger:
   uiState:
   uiTable:
Attributes:
   DOIF_Readings windows:[@as( )"Fensterkontakt_.*":state:"open","keine"]
   alias      d_FK_Anzahl
   do         always
   group      Fensterkontakte
   readingList openWindowsCount  openWindowsState
   room       Logik
   stateFormat openWindowsState (openWindowsCount)
   userReadings room_FK {(ReadingsVal($name,"windows",""));;}


Zählen und Auflisten funktioniert nun.

Ich habe im Reading windows z.B folgenden Wert stehen: Fensterkontakt_Essen2 Fensterkontakt_Wohnen3

Kann ich das Reading mittels userReadings so bearbeiten, dass ich "Fensterkontakt_" entfernen kann?

Danke und schönen 4. Advent

Grüße
Christian

Damian

Teilausdrücke kann man nicht auslagern, aber du kannst ein DOIF_Reading anlegen, auf welches zu zugreifen kannst:

attr DOIF_Readings Fensteranzahl: [#"Fensterkontakt_.*":state:"open"]

Auf Fensteranzahl kannst du dann in DOIF überall zugreifen über:

[$SELF:Fensteranzahl]
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Christian80

Die Fensteranzahl habe ich bereits.

ich bräuchte ein Reading, welches anstelle von "Fensterkontakt_Essen2 Fensterkontakt_Wohnen3"  den Inhalt "Essen2 Wohnen3" besitzt.

Grüße
Christian

Sany

das kannst Du folgendermaßen lösen:

[@as(<br>)"Fensterkontakt_.*":state:"open"]

statt # nimmst Du @as(<br>)
@: Liste der Namen
a: verwende den alias (wenn gesetzt, hier kannst Du deine Essen2, Wohnen3 nutzen, wenn der alias im Device entsprechend gesetzt ist
s(<br>): schreibt eine Liste, also alle Einträge werden untereinander geschrieben. Kannst Du weglassen, dann stehts alles in einer Zeile.

und wie Damian es schon geschrieben hat würde ich hier auch DOIF_Readings verwenden (so habe ich das bei mir auch gelöst).


Viel Erfolg!
fhem als LXC auf Proxmox auf einem minix Z100 , weitere LXC mit ZigBee2MQTT, MariaDB und Grafana. Homematic, FS20, mySensors, MQTT2, Tasmota, Shelly, Z-Wave  ....

Christian80

Ich danke euch für eure Tipps.

Der Ansatz mit dem "Alias" funktioniert für mich perfekt.

Danke und schöne Weihnachten.
Christian

teichtaucher

#8
Ich muss den Threat mal kapern, weil ich ein ähnliches Problem habe. Ich habe ein kleines E-Ink Display and einem ESP8266 mit ESPEasy am laufen. Über den http Command
http://192.168.178.46/control?cmd=epd,txl,1,Zeile1,2,Zeile2kann ich das Display ansteuern. Ich kann dabei bis zu 24 Zeilen ansteuern. Ich hätte es gern so, dass ab einem Fenster offen folgender Text auf dem Display angezeigt wird:

Fenster offen:
Bad

Also jedes Fenster in eine Zeile, in Zeile 1 statisch "Fenster offen:"
Ich habe mir überlegt dass es mit einer Schleife gut gehen würde. Also sowas wie

my $string = "http://192.168.178.46/control?cmd=epd,txl,"
for each $win in @"^Window":state:"open" $string + "," + $index +"," + $win
Hat einer von euch eine Idee wie man das schön in Code gießen kann?

So sieht mein Doif zurzeit aus:

(["^*.fk.*:open"]) {GetHttpFile("192.168.178.46","/control?cmd=epd,txl,1,Test,2,offen")}
DOELSE
{GetHttpFile("192.168.178.46","/control?cmd=epd,clear")}

Bin mir auch nicht sicher ob ich GetHttpFile verwenden soll, dass es ja blocking ist. Ach ja, der DoElse Zweig hat gar nicht funktioniert.

teichtaucher

#9
Ich muss mir mal selbst antworten. Ich hatte bei dem Thema den Perl-Modus in der Commandref nicht gesehen/gefunden. Steht aber alles hier weiter unten in bei den Beispielen im Perl-Modus

Perl-Modus:
define di_Fenster DOIF {if (["^Window:open"]) {foreach (AggrDoIf('@','^windows','state','"open"')) {Log3 "di_Fenster",3,"Das Fenster $_ ist noch offen"}}}

So sieht jetzt mein Doif aus:

define di_FensterDisplay DOIF (["^*.fk.*:open"])
{my $str = "http://192.168.178.46/control?cmd=epd,txl,1,Fenster,2,offen:";; my $idx=2;; foreach (AggrDoIf('@','^*.fk.*','state','"open"')) {$idx++;;$str=$str.",".$idx.',%22'.uri_escape(AttrVal($_,"alias",$_)).'%22'}system("wget -q $str &");;Log(3, $str)}
DOELSEIF (["^*.fk.*:closed"] and [#"^*.fk.*":state:"open"]>0)
{my $str = "http://192.168.178.46/control?cmd=epd,txl,1,Fenster,2,offen:";; my $idx=2;; foreach (AggrDoIf('@','^*.fk.*','state','"open"')) {$idx++;;$str=$str.",".$idx.',%22'.uri_escape(AttrVal($_,"alias",$_)).'%22'}system("wget -q $str &");;Log(3, $str)}
DOELSEIF (["^*.fk.*:closed"] and [#"^*.fk.*":state:"open"]==0)
{system("wget -q http://192.168.178.46/control?cmd=epd,clear &")}
DOELSE
{system("wget -q http://192.168.178.46/control?cmd=epd,clear &")}

Wenn ein Fenster geöffnet wurde, zeige Info auf dem Display an. Dabei wird der Alias jedes Fensters in einer separaten Zeile angezeigt.
Wenn ein Fenster geschlossen wurde aber noch wenigstens eins offen, update Display komplett
Wenn kein Fenster mehr offen ist, lösche Displayinhalt

Bei Displayupdate wird eine URL beim ESPEasy aufgerufen (war die einfachste Variante). Besser hätte ich eigentlich gefunden wenn ESPEasy zyklisch jede Minute aufwacht und sich die Infos von FHEM holt. Pull von ESPEasy von FHEM geht aber nicht.

Ach ja, habe ein Waveshare 2.9" Display an einem Wemos D1 laufen. Leider unterstützt ESPEasy das 2.9 Waveshare nativ ist. Ich habe aber den Treiber angepasst, so dass es jetzt läuft. Für wen es interessiert kann ich gern das Binary für den Wemos D1 hochladen.

Damian

#10
Nur ein kleiner Tipp am Rande:

Beim DOIF wird nicht $ am Ende der Regex-Angabe gemacht, daher ist .* am Ende der Device-Regex nicht erforderlich.

statt

["^*.fk.*:open"]
kann man auch angeben:

["^*.fk:open"]

und ^* macht irgendwie keinen Sinn, bedeutet , beliebige Wiederholung des Anfangs ???
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

teichtaucher

Danke für den Tipp. Du hast natürlich recht, ich war irgendwie beim "*" für any character, habe es getestet und es hat funktioniert. Bei mir haben alle Fensterkontakte ein ".fk." im Namen. Richtig wäre daher

[".+\.fk\..+:open"]

oder?

Damian

#12
Zitat von: teichtaucher am 16 Mai 2024, 19:26:47Danke für den Tipp. Du hast natürlich recht, ich war irgendwie beim "*" für any character, habe es getestet und es hat funktioniert. Bei mir haben alle Fensterkontakte ein ".fk." im Namen. Richtig wäre daher

[".+\.fk\..+:open"]

oder?

Beim DOIF würde auch schon reichen:

["\.fk\.:open"]
da kein ^ vorangestellt wird und auch kein $ angehängt wird, wie beim notify.

Der Doppelpunkt unterteilt die Regex vom Device und Regex vom restlichen Event
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

teichtaucher

Danke, hat funktioniert. Kann ich aus

[#"^*.fk.*":state:"open"]>0

auch das hier machen?

[#"\.fk\.:open"]>0

Zudem habe ich noch was komisches beobachtet: Teilweise wird mein Display auch aktualisiert obwohl gar kein Fenster mehr geöffnet wurde. In den Readings unter cmd_event sehe ich dann Fenster die schon offen sind. Warum reagiert das DOIF dann immer noch darauf? Ich hätte erwaret dass es nur auslöst wenn ein Fenster geöffnet wurde und nicht wenn es schon offen ist. Ich habe kein attr do always gesetzt.

Damian

Zitat von: teichtaucher am 17 Mai 2024, 08:51:04Danke, hat funktioniert. Kann ich aus

[#"^*.fk.*":state:"open"]>0

auch das hier machen?

ja, die Regex-Angaben werden im DOIF immer gleich behandelt.

[#"\.fk\.:open"]>0

ZitatZudem habe ich noch was komisches beobachtet: Teilweise wird mein Display auch aktualisiert obwohl gar kein Fenster mehr geöffnet wurde. In den Readings unter cmd_event sehe ich dann Fenster die schon offen sind. Warum reagiert das DOIF dann immer noch darauf? Ich hätte erwaret dass es nur auslöst wenn ein Fenster geöffnet wurde und nicht wenn es schon offen ist. Ich habe kein attr do always gesetzt.

Bei den Readings mit "e_" im Namen sieht man welches Event zur Ausführung geführt hat. Eigentlich sollte nur ein öffnendes Fenster zur Ausführung führen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

teichtaucher

Ich sehe keine Reading mit "e_". So sieht mein Doif aktuell aus:

Internals:
   CFGFN     
   DEF        (["\.fk\.:open"])
{my $str = "http://192.168.178.46/control?cmd=epd,txl,1,Fenster,2,offen:";; my $idx=2;; foreach (AggrDoIf('@','^*.fk.*','state','"open"')) {$idx++;;$str=$str.",".$idx.',%22'.uri_escape(AttrVal($_,"alias",$_)).'%22'}system("wget -q $str &");;Log(3, $str)}
DOELSEIF (["\.fk\.:closed"] and [#"\.fk\.:open"]>0)
{my $str = "http://192.168.178.46/control?cmd=epd,txl,1,Fenster,2,offen:";; my $idx=2;; foreach (AggrDoIf('@','^*.fk.*','state','"open"')) {$idx++;;$str=$str.",".$idx.',%22'.uri_escape(AttrVal($_,"alias",$_)).'%22'}system("wget -q $str &");;Log(3, $str)}
DOELSEIF (["\.fk\.:closed"] and [#"\.fk\.:open"]==0)
{system("wget -q http://192.168.178.46/control?cmd=epd,clear &")}
DOELSE
{system("wget -q http://192.168.178.46/control?cmd=epd,clear &")}
   FUUID      6643580f-f33f-2bd4-9ee6-e91d434b283f2a60
   MODEL      FHEM
   NAME       gl.fd.FensterDisplay
   NOTIFYDEV  .*(\.fk\.).*,global
   NR         6836
   NTFY_ORDER 50-di_Fenster
   STATE      cmd_1
   TYPE       DOIF
   VERSION    28546 2024-02-23 20:11:05
   eventCount 282
   READINGS:
     2024-05-17 13:36:46   Device          ki.fk.FensterRechts
     2024-05-17 13:37:14   cmd             1
     2024-05-17 13:37:14   cmd_event       ki.fk.FensterRechts
     2024-05-17 13:37:14   cmd_nr          1
     2024-05-17 13:36:36   mode            enabled
     2024-05-17 13:37:14   state           cmd_1
     2024-05-17 13:37:14   wait_timer      no timer
   Regex:
     accu:
     bar:
     barAvg:
     collect:
     cond:
       :
         0:
           "\.fk\.:open" \.fk\.:open
         1:
           "\.fk\.:closed" \.fk\.:closed
           "\.fk\.:open" \.fk\.:open
         2:
           "\.fk\.:closed" \.fk\.:closed
           "\.fk\.:open" \.fk\.:open
   attr:
     cmdState:
     wait:
       0:
         30
       1:
         30
       2:
         30
       3:
         0
     waitdel:
   condition:
     0          ::EventDoIf('\.fk\.',$hash,'open',0)
     1          ::EventDoIf('\.fk\.',$hash,'closed',0) and ::AggregateDoIf($hash,'#','\.fk\.')>0
     2          ::EventDoIf('\.fk\.',$hash,'closed',0) and ::AggregateDoIf($hash,'#','\.fk\.')==0
   do:
     0:
       0          {my $str = "http://192.168.178.46/control?cmd=epd,txl,1,Fenster,2,offen:";; my $idx=2;; foreach (AggrDoIf('@','^*.fk.*','state','"open"')) {$idx++;;$str=$str.",".$idx.',%22'.uri_escape(AttrVal($_,"alias",$_)).'%22'}system("wget -q $str &");;Log(3, $str)}
     1:
       0          {my $str = "http://192.168.178.46/control?cmd=epd,txl,1,Fenster,2,offen:";; my $idx=2;; foreach (AggrDoIf('@','^*.fk.*','state','"open"')) {$idx++;;$str=$str.",".$idx.',%22'.uri_escape(AttrVal($_,"alias",$_)).'%22'}system("wget -q $str &");;Log(3, $str)}
     2:
       0          {system("wget -q http://192.168.178.46/control?cmd=epd,clear &")}
     3:
       0          {system("wget -q http://192.168.178.46/control?cmd=epd,clear &")}
   helper:
     NOTIFYDEV  .*(\.fk\.).*,global
     event      contact: open (to VCCU)
     globalinit 1
     last_timer 0
     sleepdevice ki.fk.FensterRechts
     sleepsubtimer -1
     sleeptimer -1
     timerdev   ki.fk.FensterRechts
     timerevent contact: open (to VCCU)
     triggerDev ki.fk.FensterRechts
     DOIF_eventa:
       cmd_nr: 1
       cmd: 1
       cmd_event: ki.fk.FensterRechts
       cmd_1
     DOIF_eventas:
       cmd_nr: 1
       cmd: 1
       cmd_event: ki.fk.FensterRechts
       state: cmd_1
     timerevents:
       alive: yes
       battery: ok
       contact: open (to VCCU)
       sabotageError: off
       open
     timereventsState:
       alive: yes
       battery: ok
       contact: open (to VCCU)
       sabotageError: off
       state: open
     triggerEvents:
       alive: yes
       battery: ok
       contact: open (to VCCU)
       sabotageError: off
       open
     triggerEventsState:
       alive: yes
       battery: ok
       contact: open (to VCCU)
       sabotageError: off
       state: open
   internals:
   readings:
   trigger:
   uiState:
   uiTable:
Attributes:
   room       Global
   wait       30:30:30:0

Was ich aber sehe ist dass von Zeit zu Zeit die Readings aktualisiert werden. Bei cmd_event steht dann immer mal ein anderes Fenster drin und ein Update wird ausgelöst. Ich habe an allen Festern die hm-sec-sco. Ich dachte bisher immer, dass die ihren Status nur on Event senden, also wenn Fenster geöffnet oder geschlossen wird. Aber kann es sein, dass die dauerhaft zyklisch mal "feuern"?

Damian

Wenn du es ganz genau wissen willst, dann musst du dir alle Events der Fenster loggen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

teichtaucher

...habe ich mir gerade angeschaut. Es scheint, dass meine Fensterkontakte zyklisch (den aktuellen Status) senden. Und mein Doif reagiert darauf. Ich stelle die Frage mal in der Rubrik Homematic - das Doif verhält sich richtig. (Es interpretiert jede Nachricht von den Fensterkontakten als Event. Wenn die Fenster schon offen waren wird deshalb trotzdem nochmal "offen" erkannt).

juemuc

Du kennst das Attribut "event-on-change-reading"?

Das könnte Deine Problem lösen.

Viele Grüße
Jürgen
3x Sonos Play 1, 1x Sonos Arc + Sub, 1 Sonos-One, 1x Sonos Playbar
FB6690 + FB7490 mit 4x Dect 200 und 3 Dect-ULE-Thermostate,  raspberry3B+, HM Funkmodul HM-MOD-RPI-PCB, HM Klingelsensor HM-Sen-DB-PCB, HM (IP) Fensterkontakte und  Amazon Echo Dot,  piVCCU, pi OS (bookworm).