Zwei DOIFs zu einem DOIF kombinieren -> Ist das sinnvoll oder Quatsch?

Begonnen von hoppel118, 03 Dezember 2019, 11:20:16

Vorheriges Thema - Nächstes Thema

hoppel118

Hallo Leute,

ich beschäftige mich gerade intensiv mit DOIF und versuche das alles zu verstehen. Nun habe ich eine konkrete Frage. Ich habe eine Kühlgefrierkombi mit HomeConnect-Anbindung. Das funktioniert so weit auch alles. Das Device stellt mir zwei Readings zur Erkennung eines Türalarms (Off/Present) bereit und wenn eine der beiden Türen zu lange offen ist, fängt das Gerät an zu piepen. Hier das list des Devices:

Internals:
   CHANGED   
   DEF        hcconn BOSCH-KGN36HI33-68A40E026CA7
   FUUID      5db19a18-f33f-5dcf-550b-cab968ae2b23a95a
   NAME       KGN36HI33
   NR         482
   STATE      Idle
   TYPE       HomeConnect
   aliasname  Kühlschrank
   brand      Bosch
   commandPrefix
   eventChannelTimeout 1575366592.97928
   haId       BOSCH-KGN36HI33-68A40E026CA7
   hcconn     hcconn
   programs   
   retrycounter 0
   type       FridgeFreezer
   vib        KGN36HI33
   READINGS:
     2019-10-24 16:09:34   BSH.Common.Setting.PowerState BSH.Common.EnumType.PowerState.On
     2019-12-03 10:26:57   BSH.Common.Status.DoorState BSH.Common.EnumType.DoorState.Closed
     2019-12-03 10:26:57   Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer BSH.Common.EnumType.EventPresentState.Off
     2019-12-02 20:57:51   Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator BSH.Common.EnumType.EventPresentState.Off
     2019-10-24 16:12:46   Refrigeration.FridgeFreezer.Setting.SetpointTemperatureFreezer -18 °C
     2019-11-26 13:05:53   Refrigeration.FridgeFreezer.Setting.SetpointTemperatureRefrigerator 6 °C
     2019-11-26 13:05:28   Refrigeration.FridgeFreezer.Setting.SuperModeFreezer 0
     2019-11-26 13:05:28   Refrigeration.FridgeFreezer.Setting.SuperModeRefrigerator 0
     2019-11-26 15:39:07   state           Idle
Attributes:
   alias      Kühlschrank
   group      Hausgeräte
   icon       scene_wine_cellar
   room       System->Hausgeräte,Hersteller->HomeConnect,Obergeschoss->Küche


Mit den folgenden beiden DOIFs schicke ich mir nun eine Nachricht per yowsup/WhatsApp, wenn eine der beiden Türen zu lange offen ist. Nach dem Alarmton gibt es noch ein wait für 10 Sekunden. Damit man nicht jedesmal gleich eine WhatsApp erhält, sondern noch ein Bisschen Zeit hat, die Speisen/Getränke einzuräumen und die Tür wieder zu schließen.

Ich habe mir nun also zwei DOIFs gebaut, eins für die Kühlschranktür und eins für die Gefrierschranktür. Hier die beiden lists:

DOIF Kühlschranktür

Internals:
   CFGFN     
   DEF        ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator] eq "BSH.Common.EnumType.EventPresentState.Present")
  (({Log 3, "Kühlschrank: Tür zu lange offen"}),(set Unser_WhatsApp send Kühlschrank: Achtung, Tür zu lange offen!!!))
DOELSEIF ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator] eq "BSH.Common.EnumType.EventPresentState.Off")
  (({Log 3, "Kühlschrank: Tür wieder geschlossen"}),(set Unser_WhatsApp send Kühlschrank: Tür wieder geschlossen))
   FUUID      5de53b1c-f33f-5dcf-7871-63ecda7b41e43a83
   MODEL      FHEM
   NAME       di_Kuehlschrank
   NOTIFYDEV  KGN36HI33,global
   NR         4370
   NTFY_ORDER 50-di_Kuehlschrank
   STATE      initialized
   TYPE       DOIF
   VERSION    20268 2019-09-28 21:00:39
   READINGS:
     2019-12-03 10:29:02   cmd             0
     2019-12-03 10:29:02   mode            enabled
     2019-12-03 10:29:02   state           initialized
   Regex:
     accu:
     cond:
       KGN36HI33:
         0:
           Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator ^KGN36HI33$:^Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator:
         1:
           Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator ^KGN36HI33$:^Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator:
   attr:
     cmdState:
     wait:
       0:
         10
       1:
         0
     waitdel:
   condition:
     0          ::ReadingValDoIf($hash,'KGN36HI33','Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator') eq "BSH.Common.EnumType.EventPresentState.Present"
     1          ::ReadingValDoIf($hash,'KGN36HI33','Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator') eq "BSH.Common.EnumType.EventPresentState.Off"
   do:
     0:
       0          ({Log 3, "Kühlschrank: Tür zu lange offen"}),(set Unser_WhatsApp send Kühlschrank: Achtung, Tür zu lange offen!!!)
     1:
       0          ({Log 3, "Kühlschrank: Tür wieder geschlossen"}),(set Unser_WhatsApp send Kühlschrank: Tür wieder geschlossen)
     2:
   helper:
     DEVFILTER  ^global$|^KGN36HI33$
     NOTIFYDEV  global|KGN36HI33
     globalinit 1
     last_timer 0
     sleeptimer -1
   readings:
     all         KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator
   uiState:
   uiTable:
Attributes:
   devStateIcon cmd_1:general_an@green .*:general_aus@grey
   group      DOIF exkl Homebridge Switch
   room       Hersteller->HomeConnect,Obergeschoss->Küche,System->DOIF,System->Hausgeräte
   wait       10:0


DOIF Gefrierschranktür

Internals:
   CFGFN     
   DEF        ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer] eq "BSH.Common.EnumType.EventPresentState.Present")
  (({Log 3, "Gefrierschrank: Tür zu lange offen"}),(set Unser_WhatsApp send Gefrierschrank: Achtung, Tür zu lange offen!!!))
DOELSEIF ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer] eq "BSH.Common.EnumType.EventPresentState.Off")
  (({Log 3, "Gefrierschrank: Tür wieder geschlossen"}),(set Unser_WhatsApp send Gefrierschrank: Tür wieder geschlossen))
   FUUID      5de53a87-f33f-5dcf-0f2e-24d0fd85b8070d98
   MODEL      FHEM
   NAME       di_Gefrierschrank
   NOTIFYDEV  global,KGN36HI33
   NR         4353
   NTFY_ORDER 50-di_Gefrierschrank
   STATE      initialized
   TYPE       DOIF
   VERSION    20268 2019-09-28 21:00:39
   READINGS:
     2019-12-03 10:28:27   cmd             0
     2019-12-03 10:28:27   mode            enabled
     2019-12-03 10:28:27   state           initialized
   Regex:
     accu:
     cond:
       KGN36HI33:
         0:
           Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer ^KGN36HI33$:^Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer:
         1:
           Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer ^KGN36HI33$:^Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer:
   attr:
     cmdState:
     wait:
       0:
         10
       1:
         0
     waitdel:
   condition:
     0          ::ReadingValDoIf($hash,'KGN36HI33','Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer') eq "BSH.Common.EnumType.EventPresentState.Present"
     1          ::ReadingValDoIf($hash,'KGN36HI33','Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer') eq "BSH.Common.EnumType.EventPresentState.Off"
   do:
     0:
       0          ({Log 3, "Gefrierschrank: Tür zu lange offen"}),(set Unser_WhatsApp send Gefrierschrank: Achtung, Tür zu lange offen!!!)
     1:
       0          ({Log 3, "Gefrierschrank: Tür wieder geschlossen"}),(set Unser_WhatsApp send Gefrierschrank: Tür wieder geschlossen)
     2:
   helper:
     DEVFILTER  ^global$|^KGN36HI33$
     NOTIFYDEV  global|KGN36HI33
     globalinit 1
     last_timer 0
     sleeptimer -1
   readings:
     all         KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer
   uiState:
   uiTable:
Attributes:
   devStateIcon cmd_1:general_an@green .*:general_aus@grey
   group      DOIF exkl Homebridge Switch
   room       Hersteller->HomeConnect,Obergeschoss->Küche,System->DOIF,System->Hausgeräte
   wait       10:0


Hier nochmal die beiden DOIFs im RAW Format:

([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator] eq "BSH.Common.EnumType.EventPresentState.Present")
  (({Log 3, "Kühlschrank: Tür zu lange offen"}),(set Unser_WhatsApp send Kühlschrank: Achtung, Tür zu lange offen!!!))
DOELSEIF ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator] eq "BSH.Common.EnumType.EventPresentState.Off")
  (({Log 3, "Kühlschrank: Tür wieder geschlossen"}),(set Unser_WhatsApp send Kühlschrank: Tür wieder geschlossen))


([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer] eq "BSH.Common.EnumType.EventPresentState.Present")
  (({Log 3, "Gefrierschrank: Tür zu lange offen"}),(set Unser_WhatsApp send Gefrierschrank: Achtung, Tür zu lange offen!!!))
DOELSEIF ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer] eq "BSH.Common.EnumType.EventPresentState.Off")
  (({Log 3, "Gefrierschrank: Tür wieder geschlossen"}),(set Unser_WhatsApp send Gefrierschrank: Tür wieder geschlossen))


Anhand dieser beiden DOIFs passiert genau das, was ich erwarte. Aber:

Gibt es eine sinnvolle Möglichkeit die beiden DOIFs in einem DOIF zu kombinieren oder macht das keinen Sinn?

Danke euch und viele Grüße Hoppel
Server: Openmediavault, XEON E3-1240L-v5, Supermicro X11SSH-CTF, 64GB ECC RAM, SSD, RAID-Z2
Homebridge | Alexa | Yowsup
Homematic | HomeConnect | MQTT | Philips Hue | Sonos | Unifi Network & Protect | vbus | Xiaomi

Damian

Klar, das ist die hohe Kunst, so etwas über eine Definition abzuwickeln, also etwas zu generalisieren.

Dazu musst du die Trigger-Bedingung so verallgemeinern, dass sie alle Geräte abdeckt. Mit $DEVICE kannst du auf das triggernde Device zugreifen, welches du dann im Ausführungsteil nutzen kannst.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Pfriemler

Never change a running system...
Klar: Wenn das Regex in der Bedingung von "...Event.DoorAlarmRefrigerator" auf "Event.DoorAlarm.*" geändert würde, würden beide Türen das gleiche DOIF triggern, du müsstest die Meldungen nur anpassen. Allerdings würden Dir Ereignisse entgehen - wenn die Tiefkühlertür offen ist und jemand macht den Kühlschrank auf und wieder zu, wäre der Alarm gelöscht. Und Du würdest Dich der Möglichkeit berauben, auf beide Türöffnungen ggf. mit Zusatzbedingungen oder unterschiedlichen Zeiten zu reagieren.

Du kannst die beiden DOIFs auch zu einem zusammenfassen, indem Du beide Zweige eines DOIFs mit in das andere kopierst (die erste Bedingung dann natürlich mit einem DOELSEIF voran). Das hat summa nicht weniger Text, nur ein Device weniger.

Ich finde die Lösung mit zwei getrennten DOIFs für zwei getrennte Türen am besten.

Jm2c.
"Änd're nie in fhem.cfg, denn das tut hier allen weh!" *** Wheezy@Raspi(3), HMWLAN+HMUART, CUL868(SlowRF) für FHT+KS+FS20, miniCUL433, Rademacher DuoFern *** "... kaum macht man es richtig, funktioniert es ..."

Per

Zitat von: Pfriemler am 03 Dezember 2019, 13:14:19Du kannst die beiden DOIFs auch zu einem zusammenfassen, indem
Dann hast du aber nur einen wait-Timer, damit gilt das mit der zweiten geöffneten Tür wieder.
Aber du kannst generalisieren und Zustand ([] eq "open") und Alter der Bedingungen ([:sec]>10) abfragen. Erst wenn alles zu ist, wieder zurücksetzen.
Wenn du alle Fenster im Haus abfragen würdest, wäre der Aufwand gerechtfertigt, aber für zwei Devices sehe ich es aber als Kanone und Spatzen und so...

hoppel118

Zitat von: Damian am 03 Dezember 2019, 13:08:27
Klar, das ist die hohe Kunst, so etwas über eine Definition abzuwickeln, also etwas zu generalisieren.

OK, so etwas habe ich mir schon gedacht. ;)

Zitat von: Damian am 03 Dezember 2019, 13:08:27
Dazu musst du die Trigger-Bedingung so verallgemeinern, dass sie alle Geräte abdeckt. Mit $DEVICE kannst du auf das triggernde Device zugreifen, welches du dann im Ausführungsteil nutzen kannst.

$DEVICE verstehe ich nicht. Wie muss ich das einbauen? (Sorry, bin kein Programmierer. ;) )

Zitat von: Pfriemler am 03 Dezember 2019, 13:14:19
Du kannst die beiden DOIFs auch zu einem zusammenfassen, indem Du beide Zweige eines DOIFs mit in das andere kopierst (die erste Bedingung dann natürlich mit einem DOELSEIF voran). Das hat summa nicht weniger Text, nur ein Device weniger.

Funktioniert das wirklich? Ob das einen Mehrwert bringt, hm... Du meinst wie folgt:

define di_Kuehlgefrierkombi DOIF ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator] eq "BSH.Common.EnumType.EventPresentState.Present")
  (({Log 3, "Kühlschrank: Tür zu lange offen"}),(set Unser_WhatsApp send Kühlschrank: Achtung, Tür zu lange offen!!!))
DOELSEIF ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator] eq "BSH.Common.EnumType.EventPresentState.Off")
  (({Log 3, "Kühlschrank: Tür wieder geschlossen"}),(set Unser_WhatsApp send Kühlschrank: Tür wieder geschlossen))
DOELSEIF ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer] eq "BSH.Common.EnumType.EventPresentState.Present")
  (({Log 3, "Gefrierschrank: Tür zu lange offen"}),(set Unser_WhatsApp send Gefrierschrank: Achtung, Tür zu lange offen!!!))
DOELSEIF ([KGN36HI33:Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer] eq "BSH.Common.EnumType.EventPresentState.Off")
  (({Log 3, "Gefrierschrank: Tür wieder geschlossen"}),(set Unser_WhatsApp send Gefrierschrank: Tür wieder geschlossen))

attr di_Kuehlgefrierkombi wait 10:0:10:0


Zitat von: Pfriemler am 03 Dezember 2019, 13:14:19
Never change a running system...
Klar: Wenn das Regex in der Bedingung von "...Event.DoorAlarmRefrigerator" auf "Event.DoorAlarm.*" geändert würde, würden beide Türen das gleiche DOIF triggern, du müsstest die Meldungen nur anpassen. Allerdings würden Dir Ereignisse entgehen - wenn die Tiefkühlertür offen ist und jemand macht den Kühlschrank auf und wieder zu, wäre der Alarm gelöscht. Und Du würdest Dich der Möglichkeit berauben, auf beide Türöffnungen ggf. mit Zusatzbedingungen oder unterschiedlichen Zeiten zu reagieren.

Dieser Weg kommt für mich nicht in Frage, da ich nicht mehr den vollen Funktionsumfang hätte.

Zitat von: Pfriemler am 03 Dezember 2019, 13:14:19
Ich finde die Lösung mit zwei getrennten DOIFs für zwei getrennte Türen am besten.

OK, gut zu wissen, dass mein erster Ansatz grundsätzlich eine gute Lösung ist.

Zitat von: Per am 03 Dezember 2019, 13:42:02
Dann hast du aber nur einen wait-Timer, damit gilt das mit der zweiten geöffneten Tür wieder.
Aber du kannst generalisieren und Zustand ([] eq "open") und Alter der Bedingungen ([:sec]>10) abfragen. Erst wenn alles zu ist, wieder zurücksetzen.
Wenn du alle Fenster im Haus abfragen würdest, wäre der Aufwand gerechtfertigt, aber für zwei Devices sehe ich es aber als Kanone und Spatzen und so...

Müsste das mit dem "wait" dann nicht wie folgt funktionieren (wie ich auch oben schon im kombinierten DOIF aufgeführt hatte)?

attr di_Kuehlgefrierkombi wait 10:0:10:0

Momentan passe ich DOIF-Beispiele an meine Bedürnisse an und baue Kleinigkeiten aus dem Wiki ein. Alles darüber hinaus ist gefühlt unmöglich, da mir die entsprechenden Verknüpfungen im Gehirn fehlen... :D Welche Programmiersprache müsste ich eigentlich lernen, um das insgesamt zu verstehen?

Danke euch und Gruß Hoppel
Server: Openmediavault, XEON E3-1240L-v5, Supermicro X11SSH-CTF, 64GB ECC RAM, SSD, RAID-Z2
Homebridge | Alexa | Yowsup
Homematic | HomeConnect | MQTT | Philips Hue | Sonos | Unifi Network & Protect | vbus | Xiaomi

Per

Zitat von: hoppel118 am 03 Dezember 2019, 16:21:21Müsste das mit dem "wait" dann nicht wie folgt funktionieren (wie ich auch oben schon im kombinierten DOIF aufgeführt hatte)?

attr di_Kuehlgefrierkombi wait 10:0:10:0
Nein, sobald DOIF einen anderen Zweig anspringt, wird der vorher aktive Timer abgebrochen.

Damian

ZitatWelche Programmiersprache müsste ich eigentlich lernen, um das insgesamt zu verstehen?

Die Sprache, über die alles in FHEM abgewickelt ist, also Perl ;)

Da du einen Wait-Timer definiert hast, ist die Generalisierung schwierig, da in einem DOIF (FHEM-Modus) nur ein wait-Timer existiert. Hier muss man auf DOIF-Perl ausweichen (der kann beliebig viele wait-Timer verwalten), aber da solltest du erst mal Perl lernen :)

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

hoppel118

Dann hat sich das eigentliche Thema hier erstmal erledigt. Ich bleibe bei meinen beiden DOIFs.

Zitat von: Damian am 03 Dezember 2019, 17:03:09
Die Sprache, über die alles in FHEM abgewickelt ist, also Perl ;)

Das FHEM und Perl zusammengehören, ist quasi klar. :) Ist Perl denn eine Sprache mit der man starten kann, wenn man bei Null anfängt? Gibt's da empfehlenswerte Lektüre? :)

Danke euch und Gruß Hoppel
Server: Openmediavault, XEON E3-1240L-v5, Supermicro X11SSH-CTF, 64GB ECC RAM, SSD, RAID-Z2
Homebridge | Alexa | Yowsup
Homematic | HomeConnect | MQTT | Philips Hue | Sonos | Unifi Network & Protect | vbus | Xiaomi

Damian

Zitat von: hoppel118 am 03 Dezember 2019, 23:12:07
Dann hat sich das eigentliche Thema hier erstmal erledigt. Ich bleibe bei meinen beiden DOIFs.

Das FHEM und Perl zusammengehören, ist quasi klar. :) Ist Perl denn eine Sprache mit der man starten kann, wenn man bei Null anfängt? Gibt's da empfehlenswerte Lektüre? :)

Danke euch und Gruß Hoppel

Jede Programmiersprache hat ihre Vor- und Nachteile. Ich persönlich (allerdings mit Vorkenntnissen) konnte mich schnell in Perl zurechtfinden. Ich würde mit der Programmiersprache anfangen, mit der du arbeiten willst. Es macht wenig Sinn Programmiersprachen aus dem Buch zu lernen ohne dafür einen praktischen Einsatz zu haben.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Beta-User

Falls du ein Buch suchst: https://forum.fhem.de/index.php/topic,100206.msg993864.html#msg993864

Ich selbst (ohne behaupten zu wollen, jetzt Perl wirklich zu können) nutze in der Regel vorhandenen Code, der in etwa das tut, was ich haben will und schaue mir bei Bedarf (über Suche im Netz bei perldoc oder perlmonks) nach, was bestimmte Perl-Funktionen eigentlich tun.

Mein persönliches Aha-Erlebnis (was, so "einfach" ist das) war Benni's generalisierter Fenster-Offen-Code (sollte über die Suche bei den Codeschnipseln zu finden sein) und müßte (ohne DOIF...) auch diesen Fall hier "nebenbei" ohne größere Klimmzüge mit abdecken können.

Gruß, Beta-User
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

hoppel118

Na dann schauen wir mal, wie es weiter geht. Aber bei Gelegenheit nehme ich mich dem Thema dann mal an. ;)

Gruß Hoppel
Server: Openmediavault, XEON E3-1240L-v5, Supermicro X11SSH-CTF, 64GB ECC RAM, SSD, RAID-Z2
Homebridge | Alexa | Yowsup
Homematic | HomeConnect | MQTT | Philips Hue | Sonos | Unifi Network & Protect | vbus | Xiaomi

Damian

Zitat von: hoppel118 am 04 Dezember 2019, 21:16:50
Na dann schauen wir mal, wie es weiter geht. Aber bei Gelegenheit nehme ich mich dem Thema dann mal an. ;)

Gruß Hoppel

Offenbar konntest du drei Jahre lang ohne Perl mit FHEM gut auskommen, also kann es nicht den ganz so hohen Stellenwert für dich gehabt haben, denn sonst hättest du da schon etwas mehr in diese Richtung gemacht. Die meisten hier dürften keine Programmierer sein und kommen gut zurecht mit dem was FHEM an Möglichkeiten bietet.

Eine Programmiersprache beherrschen, heißt ja nicht nur die Syntax zu kennen, ebenso wichtig ist es grundsätzliches Verständnis von allgemeiner Programmierung zu haben und auch da gibt es inzwischen verschiedene Welten: prozedural, aber auch objektorientiert. Oft braucht man jahrelange Programmiererfahrung um "mitreden zu können".

Zusätzlich kommt hinzu in FHEM ereignisorientiert zu denken, da Events immer im Mittelpunkt stehen, das macht die Sache nicht unbedingt einfacher.

Wenn du aber keine FHEM-Module programmieren willst, dann solltest du mit geringen Perl-Kenntnissen schon klar kommen (Kenntnis über Variablen und Funktionen).

Im Bezug auf deine ursprüngliche Fragestellung findest du hier ein Beispiel für Generalisierung für beliebig viele Fenster mit Verzögerung https://fhem.de/commandref_DE.html#DOIF_Anwendungsbeispiele_im_Perlmodus  (Verzögerte Fenster-offen-Meldung mit Wiederholung für mehrere Fenster). Das ist hauptsächlich Perl, nur die beiden Stellen in eckigen Klammern als Ereignistrigger (kennst du ja schon aus der DOIF-FHEM-Welt) sind spezifisch, sie stellen intern eine Perl-Funktion dar.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF