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
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.
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.
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...
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
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.
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 :)
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
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.
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
Na dann schauen wir mal, wie es weiter geht. Aber bei Gelegenheit nehme ich mich dem Thema dann mal an. ;)
Gruß Hoppel
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.