Hauptmenü

DOIF mit Selbstbezug

Begonnen von olwaldi, 10 Oktober 2026, 18:22:43

Vorheriges Thema - Nächstes Thema

olwaldi

Ich versuche zu verstehen, wie/ob man selbstbezügliche DOIFs erstellen darf. Hier ein einfaches Beispiel, daß zwar funktioniert, aber in cmd_1 steckenbleibt:
define AudioMode DOIF ([AudioModeKeys] eq "on")\
  (set AudioModeKeys off)\
DOELSE\

attr AudioMode cmdState on|off
attr AudioMode do resetwait
attr AudioMode wait 10:0
#   DEF        ([AudioModeKeys] eq "on")
#  (set AudioModeKeys off)
#DOELSE
#
#   FUUID      656d878e-f33f-fc3a-38f2-09c42f025fc93f22
#   MODEL      FHEM
#   NAME       AudioMode
#   NOTIFYDEV  global,AudioModeKeys
#   NR         73
#   NTFY_ORDER 50-AudioMode
#   STATE      on
#   TYPE       DOIF
#   VERSION    30659 2025-12-25 12:37:16
#   eventCount 87
#   READINGS:
#     2026-10-10 18:12:54   Device          AudioModeKeys
#     2026-10-10 18:13:04   cmd             1
#     2026-10-10 18:13:04   cmd_event       AudioModeKeys
#     2026-10-10 18:13:04   cmd_nr          1
#     2026-10-10 18:12:54   e_AudioModeKeys_STATE on
#     2026-10-10 18:11:26   mode            enabled
#     2026-10-10 18:13:04   state           on
#     2026-10-10 18:13:04   wait_timer      no timer
#   Regex:
#     accu:
#     bar:
#     barAvg:
#     collect:
#     cond:
#       AudioModeKeys:
#         0:
#           &STATE     ^AudioModeKeys$
#   attr:
#     cmdState:
#       0:
#         on
#       1:
#         off
#     wait:
#       0:
#         10
#       1:
#         0
#     waitdel:
#   condition:
#     0          ::InternalDoIf($hash,'AudioModeKeys','STATE') eq "on"
#   do:
#     0:
#       0          set AudioModeKeys off
#     1:
#       0         
#   helper:
#     NOTIFYDEV  global,AudioModeKeys
#     event      on
#     globalinit 1
#     last_timer 0
#     sleepdevice AudioModeKeys
#     sleepsubtimer -1
#     sleeptimer -1
#     timerdev   AudioModeKeys
#     timerevent on
#     triggerDev AudioModeKeys
#     DOIF_eventa:
#       cmd_nr: 1
#       cmd: 1
#       cmd_event: AudioModeKeys
#       on
#     DOIF_eventas:
#       cmd_nr: 1
#       cmd: 1
#       cmd_event: AudioModeKeys
#       state: on
#     timerevents:
#       on
#     timereventsState:
#       state: on
#     triggerEvents:
#       on
#     triggerEventsState:
#       state: on
#   internals:
#     all         AudioModeKeys:STATE
#   readings:
#   trigger:
#   uiState:
#   uiTable:
#
setstate AudioMode on
setstate AudioMode 2026-10-10 18:12:54 Device AudioModeKeys
setstate AudioMode 2026-10-10 18:13:04 cmd 1
setstate AudioMode 2026-10-10 18:13:04 cmd_event AudioModeKeys
setstate AudioMode 2026-10-10 18:13:04 cmd_nr 1
setstate AudioMode 2026-10-10 18:12:54 e_AudioModeKeys_STATE on
setstate AudioMode 2026-10-10 18:11:26 mode enabled
setstate AudioMode 2026-10-10 18:13:04 state on
setstate AudioMode 2026-10-10 18:13:04 wait_timer no timer

Vermutlich wird der Status von DOIF auf on/cmd_1 gesetzt, wenn nach 10s der Wert auf off gesetzt wird.

Aber wie erreiche ich mein Ziel, daß der state vom DOIF synchron zu AudioModeKeys geändert wird?

Grüßle, Michael
Nachtrag: Dasselbe Problem habe ich auch mit einem anderen DOIF, wo nicht so offensichtlich dieselbe Art von "Rekursivität" genutzt wird.

Per

DOIF kennt ein Attribut (selftrigger), mit welchem du Selftriggering explizit erlauben kannst.

olwaldi

Danke für den Hinweis.

Ich vermute mittlerweile, daß ich gar kein DOIF-Problem habe. Obiges DOIF funktioniert ja, mit und ohne DOELSE. Der Wert des state gibt eben nur an, ob cmd_1 wirklich nach Ablauf des wait_timer abgearbeitet wurde. Ich hatte geglaubt, daß ein DOIF "irgendwie" in den Zustand cmd_2 kommen muß, ehe es wieder in cmd_1 wechseln kann. Aber sobald das "richtige" Ereignis triggert, startet cmd_1 von neuem.

Wie schon oben im Nachtrag geschrieben, ich habe an anderer Stelle mit einem ähnlich strukturierten DOIF ein Problem. Das liegt aber wohl daran, daß die Events nicht so kommen wie geglaubt. Aber da kann das DOIF nix machen:-)

Grüßle, Michael

Per

Wenn du nur 10 Sekunden dem Einschalten von AudioModeKeys wieder ausschalten möchtest, lass einfach DOELSE weg.
Oder nutz' den Perl Mode ;).

olwaldi

#4
So habe ich es auch gemacht.

Aber: Bei meinem "echt" problematischen DOIF funktionierts nur, wenn es ein leeres DOELSE gibt. Das verstehe ich dann nicht, mal ein Muß, mal optional?!? Hier mein echtes Problem, gelöst durch leeres DOELSE:
define DenonOn DOIF (\
  ([AVsource] eq "none") and (\
    ([Denon:zoneMain] eq "on") or ([zone2:power] eq "on")\
  )\
)\
(set Denon rawCommand SI?, set Denon rawCommand Z2?)\
({SetAVtarget("$DEVICE")}, set Kueche off)\
DOELSE\
\

attr DenonOn cmdState setting|waiting
attr DenonOn do resetwait
attr DenonOn wait 1,1
#   DEF        (
#  ([AVsource] eq "none") and (
#    ([Denon:zoneMain] eq "on") or ([zone2:power] eq "on")
#  )
#)
#(set Denon rawCommand SI?, set Denon rawCommand Z2?)
#({SetAVtarget("$DEVICE")}, set Kueche off)
#DOELSE
#
#
#   FUUID      6ac73e10-f33f-fc3a-70b7-ef6813f9acecbb2e
#   MODEL      FHEM
#   NAME       DenonOn
#   NOTIFYDEV  Denon,global,AVsource,zone2
#   NR         108
#   NTFY_ORDER 50-DenonOn
#   STATE      setting
#   TYPE       DOIF
#   VERSION    30659 2025-12-25 12:37:16
#   eventCount 82
#   READINGS:
#     2026-10-11 09:01:36   Device          Denon
#     2026-10-11 09:01:38   cmd             1.2
#     2026-10-11 09:01:38   cmd_event       Denon
#     2026-10-11 09:01:38   cmd_nr          1
#     2026-10-11 09:01:38   cmd_seqnr       2
#     2026-10-11 08:59:42   e_AVsource_STATE none
#     2026-10-11 09:01:36   e_Denon_zoneMain on
#     2026-10-11 08:56:58   mode            enabled
#     2026-10-11 09:01:38   state           setting
#     2026-10-11 09:01:38   wait_timer      no timer
#   Regex:
#     accu:
#     bar:
#     barAvg:
#     collect:
#     cond:
#       AVsource:
#         0:
#           &STATE     ^AVsource$
#       Denon:
#         0:
#           zoneMain   ^Denon$:^zoneMain:
#       zone2:
#         0:
#           power      ^zone2$:^power:
#   attr:
#     cmdState:
#       0:
#         setting
#       1:
#         waiting
#     wait:
#       0:
#         1
#         1
#     waitdel:
#   condition:
#     0             (::InternalDoIf($hash,'AVsource','STATE') eq "none") and (     (::ReadingValDoIf($hash,'Denon','zoneMain') eq "on") or (::ReadingValDoIf($hash,'zone2','power') eq "on")   )
#   do:
#     0:
#       0          set Denon rawCommand SI?, set Denon rawCommand Z2?
#       1          {SetAVtarget("$DEVICE")}, set Kueche off
#     1:
#       0         
#   helper:
#     NOTIFYDEV  Denon,global,AVsource,zone2
#     event      zoneMain: on,stateAV: on
#     globalinit 1
#     last_timer 0
#     sleepdevice Denon
#     sleepsubtimer -1
#     sleeptimer -1
#     timerdev   Denon
#     timerevent zoneMain: on,stateAV: on
#     triggerDev Denon
#     timerevents:
#       zoneMain: on
#       stateAV: on
#     timereventsState:
#       zoneMain: on
#       stateAV: on
#     triggerEvents:
#       zoneMain: on
#       stateAV: on
#     triggerEventsState:
#       zoneMain: on
#       stateAV: on
#   internals:
#     all         AVsource:STATE
#   readings:
#     all         Denon:zoneMain zone2:power
#   trigger:
#   uiState:
#   uiTable:
#
setstate DenonOn setting
setstate DenonOn 2026-10-11 09:01:36 Device Denon
setstate DenonOn 2026-10-11 09:01:38 cmd 1.2
setstate DenonOn 2026-10-11 09:01:38 cmd_event Denon
setstate DenonOn 2026-10-11 09:01:38 cmd_nr 1
setstate DenonOn 2026-10-11 09:01:38 cmd_seqnr 2
setstate DenonOn 2026-10-11 08:59:42 e_AVsource_STATE none
setstate DenonOn 2026-10-11 09:01:36 e_Denon_zoneMain on
setstate DenonOn 2026-10-11 08:56:58 mode enabled
setstate DenonOn 2026-10-11 09:01:38 state setting
setstate DenonOn 2026-10-11 09:01:38 wait_timer no timer
Ohne das DOELSE wird ungewollt die erste Kommandosequenz ausgeführt: AVsource wechselt auf none -> triggert richtigerweise. Aber quasi gleichzeitig (identischer fhem-Zeitstempel) wird Denon:zoneMain off. Ohne DOELSE werden BEIDE Kommandosequenzen ausgeführt.

Mit leerem DOELSE funktioniert's wie erwartet, beide Sequenzen werden nicht ausgeführt, da wait_timer gelöscht wird. Vermutlich muß ich noch das Attribut wait noch auf 1,1:0 ändern, da es ja jetzt einen zweiten Zustand gibt.

Grüßle, Michael
Nachtrag: Auch das "unproblematische" DOIF scheint besser zu funktionieren mit einem leeren DOELSE. Das paßt dann wieder zusammen. cmdState setzt ich dann auf setoff|waiting. Wenn der wait_timer abläuft, wechselt der state auf setoff.