Befehl mit wait > Wegfall der Bedingung wärend wait aktiv: noch gültig?

Begonnen von M_I_B, 24 November 2016, 00:15:14

Vorheriges Thema - Nächstes Thema

M_I_B

Moin Kinnaz,

mal angenommen, ich verzögere den Befehlsteil mit "wait" auf Grund einer Kombination aus Bedingungen. Wait ist also bereits am laufen.
Was passiert, wenn währenddessen eine oder mehrere Bedingungen nicht mehr wahr sind? Wird dann der Befehl trotzdem ausgeführt, weil er auf Grund der vormals wahren Bedingungen auszuführen war oder wird nach Ablauf der wait- Phase erneut geprüft? Das ist mir nicht so wirklich klar geworden ^^


Brockmann

Zitat von: M_I_B am 24 November 2016, 00:15:14
mal angenommen, ich verzögere den Befehlsteil mit "wait" auf Grund einer Kombination aus Bedingungen. Wait ist also bereits am laufen.
Was passiert, wenn währenddessen eine oder mehrere Bedingungen nicht mehr wahr sind? Wird dann der Befehl trotzdem ausgeführt, weil er auf Grund der vormals wahren Bedingungen auszuführen war oder wird nach Ablauf der wait- Phase erneut geprüft? Das ist mir nicht so wirklich klar geworden ^^

Wait läuft solange, bis das DOIF seinen Status wechselt. Erfolgt bis zum Ablauf der wait-Frist kein Statuswechsel, wird die Aktion ausgeführt. Es wird nicht nochmal explizit geprüft, ob die Bedingungen noch erfüllt sind. Das schließt DOIF implizit aus der Tatsache, dass kein Statuswechsel stattgefunden hat. Selbst wenn eine oder mehrere Bedingungen nicht mehr wahr sind, kann die Aktion also trotzdem ausgeführt werden, wenn zwischenzeitlich keine andere Kondition getriggert wurde und wahr war. Im Zweifelsfall sollte man dem DOIF also mit einem leeren DOELSE am Ende einen "Notausgang" lassen.

M_I_B

... jo super, Dank für die Ausführlichkeit!

Ich fasse noch mal mit meinen Worten zusammen:

1.:
Der "geWaitete" Befehl wird auf jeden Fall ausgeführt, auch wenn eine zum Befehl auslösende Eingangsbedingung zwischenzeitlich nicht mehr wahr ist.

2.:
Der "geWaitete" Befehl wird dann verworfen, wenn in dem DOIF / DOELSEIF / DOELSE innert der WAIT- Phase eine andere Bedingung wahr wird und somit der dazu gehörende Befehlsteil ausgeführt wird.

Korrekt so?

Wenn ja, dann muss man also irgendwie dafür sorgen, das während der WAIT- Phase keine andere Bedingung wahr werden kann, wenn man den "geWaiteten" Befehl auf jeden Fall zu Ende bringen möchte?!

Brockmann

Zitat von: M_I_B am 24 November 2016, 09:22:41
Der "geWaitete" Befehl wird auf jeden Fall ausgeführt, auch wenn eine zum Befehl auslösende Eingangsbedingung zwischenzeitlich nicht mehr wahr ist.
"auf jeden Fall" ist mir etwas zu undifferenziert aber im Prinzip Ja

Zitat von: M_I_B am 24 November 2016, 09:22:41
Der "geWaitete" Befehl wird dann verworfen, wenn in dem DOIF / DOELSEIF / DOELSE innert der WAIT- Phase eine andere Bedingung wahr wird und somit der dazu gehörende Befehlsteil ausgeführt wird.
Ja

Zitat von: M_I_B am 24 November 2016, 09:22:41
Wenn ja, dann muss man also irgendwie dafür sorgen, das während der WAIT- Phase keine andere Bedingung wahr werden kann, wenn man den "geWaiteten" Befehl auf jeden Fall zu Ende bringen möchte?!
Korrekt.
Alternative, wenn etwas unter allen Umständen ausgeführt werden soll: Lass das DOIF ein AT definieren, das die Aktion zum gewünschten Zeitpunkt ausführt. Dann ist es egal, was mit dem DOIF anschließend noch passiert.

M_I_B

Zitat von: Brockmann am 24 November 2016, 09:31:58Alternative, wenn etwas unter allen Umständen ausgeführt werden soll: Lass das DOIF ein AT definieren, das die Aktion zum gewünschten Zeitpunkt ausführt. Dann ist es egal, was mit dem DOIF anschließend noch passiert.

Schicke Idee und Lösung; da wäre ich jetzt erst mal nimmernich drauf gekommen  ;D Genau so werde ich das machen...

Vielen Dank; das hilf ungemein weiter und erspart mir weitere, wilde Verrenkungen  8)

Otto123

Hallo Micha,

ich habe eure Diskussion aufmerksam gelesen, ich kann es theoretisch nicht so zerpflücken. Ich bin mir immer unsicher was DOIF dort wirklich tut. Ich habe aber zwei Beispiele im Einsatz, die genauso funktionieren wie ich es mir vorstelle:

Einschalten und Nachtriggern vom Licht bei Bewegung. Die DEF([PIR1:motion] and ([?Tageslicht] eq "0" or [?PIRWg:brightness] < 150)) (set SW01_Sw01 on)(set SW01_Sw01 off)
Dazu ein wait 0,250 und ein do resetwait.
Der Bewegungsmelder steht auf "Standard" und liefert frühestens nach 240 sec einen neuen trigger.

Watchdog für Abwesenheitserkennung nach 5 min.
die DEF:([st_Dev_Otto] eq "absent")(set PersonOtto absent) DOELSEIF ([st_Dev_Otto] eq "present")(set PersonOtto present)
dazu ein wait 300

Gruß Otto
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

Brockmann

Zitat von: Otto123 am 24 November 2016, 10:43:15
Watchdog für Abwesenheitserkennung nach 5 min.
die DEF:([st_Dev_Otto] eq "absent")(set PersonOtto absent) DOELSEIF ([st_Dev_Otto] eq "present")(set PersonOtto present)
dazu ein wait 300

Vielleicht nur zur Verdeutlichung:
Wenn Dein "st_Dev_Otto" auf "absent" wechselt, beginnt die Wartezeit des wait.
Wenn nun innerhalb dieser Wartezeit "st_Dev_Otto" - warum auch immer - auf "xyz" wechseln würde, dann würde die Wartezeit weiterlaufen und nach Ablauf "PersonOtto" auf "absent" gesetzt werden, selbst wenn "st_Dev_Otto" zu diesem Zeitpunkt gar nicht mehr "absent" ist.

Ja, ist etwas an den Haaren herbeigezogen, aber macht vielleicht deutlich, worum es hier geht.
DOIF prüft nicht explizit während oder nach Ablauf der wait-Zeit, ob die Bedingung noch wahr ist, sondern schließt dies implizit aus dem Zustand des DOIF. Hat der sich nicht geändert, wird die Bedingung wohl noch erfüllt sein. Das ist eine spezielle Eigenheit von DOIF bzw. wait, die man bei komplexen DOIFs im Auge behalten sollte. Nachdem ich das selbst irgendwann kapiert hatte, geht bei mir nun jedes Mal ein Warnlämpchen an, wenn wait ohne DOELSE verwendet wird. Dass muss nicht zwangsläufig problematisch sein, kann aber...

Otto123

Also ich erkenne folgendes Verhalten:
geht st_Dev_Otto auf absent startet nur der waittimer.
geht danach innerhalb der 300 sec st_Dev_Otto wieder auf present wird der waittimer gelöscht. Das Modul registriert den wechselnden State vom st_Dev_Otto, ansonsten passiert nichts. Also das DOELSEIF wird in dem Moment nicht durchlaufen.

Ich finde das widerspricht dem was Du sagst!

Hier mal die list's von einem gleichartigen DOIF mit dem ich testen kann
Ausgangszustand present
Internals:
   DEF        ([st_Dev_Brina] eq "absent")(set PersonBrina absent) DOELSEIF ([st_Dev_Brina] eq "present")(set PersonBrina present)
   NAME       di_Dev_Brina
   NR         466
   NTFY_ORDER 50-di_Dev_Brina
   STATE      cmd_2
   TYPE       DOIF
   Readings:
     2016-11-24 11:32:25   Device          st_Dev_Brina
     2016-11-24 11:30:45   cmd             2
     2016-11-24 11:30:45   cmd_event       st_Dev_Brina
     2016-11-24 11:30:45   cmd_nr          2
     2016-11-24 11:32:25   e_st_Dev_Brina_STATE present
     2016-11-24 11:30:45   state           cmd_2
     2016-11-24 11:32:25   wait_timer      no timer
   Condition:
     0          InternalDoIf($hash,'st_Dev_Brina','STATE','','',AttrVal($hash->{NAME},'notexist',undef)) eq "absent"
     1          InternalDoIf($hash,'st_Dev_Brina','STATE','','',AttrVal($hash->{NAME},'notexist',undef)) eq "present"
   Devices:
     0           st_Dev_Brina
     1           st_Dev_Brina
     all         st_Dev_Brina
   Do:
     0:
       0          set PersonBrina absent
     1:
       0          set PersonBrina present
   Helper:
     event      present
     globalinit 1
     last_timer 0
     sleepdevice st_Dev_Brina
     sleepsubtimer 0
     sleeptimer -1
     timerdev   st_Dev_Brina
     timerevent present
     triggerDev st_Dev_Brina
     timerevents:
       present
     timereventsState:
       state: present
     triggerEvents:
       present
     triggerEventsState:
       state: present
   Internals:
     0           st_Dev_Brina:STATE
     1           st_Dev_Brina:STATE
     all         st_Dev_Brina:STATE
   Itimer:
   Readings:
   Regexp:
     0:
     1:
     All:
   State:
   Trigger:
Attributes:
   room       Status
   wait       300

Zustand absent
Internals:
   DEF        ([st_Dev_Brina] eq "absent")(set PersonBrina absent) DOELSEIF ([st_Dev_Brina] eq "present")(set PersonBrina present)
   NAME       di_Dev_Brina
   NR         466
   NTFY_ORDER 50-di_Dev_Brina
   STATE      cmd_2
   TYPE       DOIF
   Readings:
     2016-11-24 11:41:20   Device          st_Dev_Brina
     2016-11-24 11:30:45   cmd             2
     2016-11-24 11:30:45   cmd_event       st_Dev_Brina
     2016-11-24 11:30:45   cmd_nr          2
     2016-11-24 11:41:20   e_st_Dev_Brina_STATE absent
     2016-11-24 11:30:45   state           cmd_2
     2016-11-24 11:41:20   wait_timer      24.11.2016 11:46:20 cmd_1 st_Dev_Brina
   Condition:
     0          InternalDoIf($hash,'st_Dev_Brina','STATE','','',AttrVal($hash->{NAME},'notexist',undef)) eq "absent"
     1          InternalDoIf($hash,'st_Dev_Brina','STATE','','',AttrVal($hash->{NAME},'notexist',undef)) eq "present"
   Devices:
     0           st_Dev_Brina
     1           st_Dev_Brina
     all         st_Dev_Brina
   Do:
     0:
       0          set PersonBrina absent
     1:
       0          set PersonBrina present
   Helper:
     event      absent
     globalinit 1
     last_timer 0
     sleepdevice st_Dev_Brina
     sleepsubtimer 0
     sleeptimer 0
     timerdev   st_Dev_Brina
     timerevent absent
     triggerDev st_Dev_Brina
     timerevents:
       absent
     timereventsState:
       state: absent
     triggerEvents:
       absent
     triggerEventsState:
       state: absent
   Internals:
     0           st_Dev_Brina:STATE
     1           st_Dev_Brina:STATE
     all         st_Dev_Brina:STATE
   Itimer:
   Readings:
   Regexp:
     0:
     1:
     All:
   State:
   Trigger:
Attributes:
   room       Status
   wait       300

Zustand wieder present
Internals:
   DEF        ([st_Dev_Brina] eq "absent")(set PersonBrina absent) DOELSEIF ([st_Dev_Brina] eq "present")(set PersonBrina present)
   NAME       di_Dev_Brina
   NR         466
   NTFY_ORDER 50-di_Dev_Brina
   STATE      cmd_2
   TYPE       DOIF
   Readings:
     2016-11-24 11:42:04   Device          st_Dev_Brina
     2016-11-24 11:30:45   cmd             2
     2016-11-24 11:30:45   cmd_event       st_Dev_Brina
     2016-11-24 11:30:45   cmd_nr          2
     2016-11-24 11:42:04   e_st_Dev_Brina_STATE present
     2016-11-24 11:30:45   state           cmd_2
     2016-11-24 11:42:04   wait_timer      no timer
   Condition:
     0          InternalDoIf($hash,'st_Dev_Brina','STATE','','',AttrVal($hash->{NAME},'notexist',undef)) eq "absent"
     1          InternalDoIf($hash,'st_Dev_Brina','STATE','','',AttrVal($hash->{NAME},'notexist',undef)) eq "present"
   Devices:
     0           st_Dev_Brina
     1           st_Dev_Brina
     all         st_Dev_Brina
   Do:
     0:
       0          set PersonBrina absent
     1:
       0          set PersonBrina present
   Helper:
     event      present
     globalinit 1
     last_timer 0
     sleepdevice st_Dev_Brina
     sleepsubtimer 0
     sleeptimer -1
     timerdev   st_Dev_Brina
     timerevent present
     triggerDev st_Dev_Brina
     timerevents:
       present
     timereventsState:
       state: present
     triggerEvents:
       present
     triggerEventsState:
       state: present
   Internals:
     0           st_Dev_Brina:STATE
     1           st_Dev_Brina:STATE
     all         st_Dev_Brina:STATE
   Itimer:
   Readings:
   Regexp:
     0:
     1:
     All:
   State:
   Trigger:
Attributes:
   room       Status
   wait       300


Gruß Otto
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

Brockmann

Zitat von: Otto123 am 24 November 2016, 11:38:52
geht st_Dev_Otto auf absent startet nur der waittimer.
geht danach innerhalb der 300 sec st_Dev_Otto wieder auf present wird der waittimer gelöscht. Das Modul registriert den wechselnden State vom st_Dev_Otto, ansonsten passiert nichts. Also das DOELSEIF wird in dem Moment nicht durchlaufen.

Ich finde das widerspricht dem was Du sagst!
Da haben wir wohl unterschiedliche Ansichten darüber, was ich gesagt habe.  ;)

Setz st_Dev_Otto auf "absent". Der waittimer startet.
Setz st_Dev_Otto nun nicht auf "present" sondern auf "unknown". Der waittimer wird weiter laufen.

Otto123

Zitat von: Brockmann am 24 November 2016, 12:04:25
Da haben wir wohl unterschiedliche Ansichten darüber, was ich gesagt habe.  ;)

Setz st_Dev_Otto auf "absent". Der waittimer startet.
Setz st_Dev_Otto nun nicht auf "present" sondern auf "unknown". Der waittimer wird weiter laufen.
Stimmt  :-[ geht auch mit willi
Ich habe ja gesagt ich kann nicht mitreden.  ;)

Und warum ist das so? Weil ich den Test auf present im DOELSEIF habe?
ich meine: Da hätte ich es ja richtig gemacht und sogar verstanden ...
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

M_I_B

Moin Otto ...
Zitat von: Otto123 am 24 November 2016, 10:43:15Einschalten und Nachtriggern vom Licht bei Bewegung. Die DEF([PIR1:motion] and ([?Tageslicht] eq "0" or [?PIRWg:brightness] < 150)) (set SW01_Sw01 on)(set SW01_Sw01 off)
Dazu ein wait 0,250 und ein do resetwait.
Der Bewegungsmelder steht auf "Standard" und liefert frühestens nach 240 sec einen neuen trigger.

Habe ich einfacher gelöst (glaube ich in meiner Naivität) ;)
Ich bin davon ausgegangen (gehe noch davon aus), das ein mit "on-for-timer" gesetzter Aktor, wenn er sich noch in dem gesetzten Zeitfenster befindet, bei einem weiteren "on-for-timer" wieder von vorne beginnt. Also habe ich stumpf (komplett) einen auf den hier gemacht, was bis dato schmerzfrei funzt:
## Aussenlicht bei Bewegung und Dunkelheit ##
define LichtPIRga DOIF ([LUM] < 35 and [HM2BB1] eq "motion") (set HM4SW2_1 on-for-timer 180, sleep 0.2, setreading HM2BB1 state noMotion)
attr LichtPIRga do always
define LichtPIRtr DOIF ([LUM] < 35 and [HM2BB2] eq "motion") (set HM4SW1_1 on-for-timer 180, sleep 0.2, setreading HM2BB2 state noMotion)
attr LichtPIRtr do always


Ich habe allerdings meine Register bei beiden auf 30sec. gesetzt und noch ein paar andere Register" verbogen...

Otto123

Hallo Micha,

ZitatHabe ich einfacher gelöst (glaube ich in meiner Naivität) ;)
Na darüber können wir jetzt aber "streiten"  :D
Ich will ja möglichst Müll vermeiden, oder unnütze Dinge ...  8)
Du sendest bei jeder Bewegung noch mal einen an den Aktor - ich schalte ein und wenn sich keiner mehr bewegt schalte ich aus. Nur zwei Funkbefehle zum Aktor auch wenn da Stundenlang einer rum hampelt.
Und ich muss die Readings nicht verbiegen, es reicht wenn Martin mit dem nächsten Update was ändert  ;)

Gruß Otto
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

M_I_B

... in Sachen Funklast hast du natürlich recht; ist hier nicht so relevant, da selten was los und wenn, dann sowieso manuell eingeschaltet ...
Wie immer führen viele Wege nach Rom ;) Ich werde mir deine Lösung aber mal als Kommentar darunter schreiben... lohnt das Nachdenken...

Per

Zitat von: Otto123 am 24 November 2016, 10:43:15([st_Dev_Otto] eq "absent")(set PersonOtto absent) DOELSEIF ([st_Dev_Otto] eq "present")(set PersonOtto present)
dazu ein wait 300
Nur als Tipp: sauberer wäre
wait 300:0

Zitat von: M_I_B am 24 November 2016, 12:45:57
Habe ich einfacher gelöst (glaube ich in meiner Naivität) ;)
Nicht wirklich :-X

und außerdem blockierst du FHEM:
Zitat von: M_I_B am 24 November 2016, 12:45:57(set HM4SW2_1 on-for-timer 180, sleep 0.2, setreading HM2BB1 state noMotion)
Dort lieber mit wait arbeiten. Nebenbei: was soll dein setreading außer unbekannten Sideeffekten noch bewirken? Wenn du nicht gerade mit event-on-update-reading die Meldungen des Sensors eh abgeblockt hast, kommen die auch so bei DOIF an.

Übrig bliebe ein
(set HM4SW2_1 on-for-timer 180)
welches man durch geschickte Namenswahl sogar generalisieren könnte. Oder mittels Userreading (ist mir gerade eingefallen, spart viel nachträgliche Anpassung, hoffentlich vergesse ich das nicht wieder, bis ich wieder am System bin :D)
Geht aber nur mit on-for-timer, da wait für alle gleichzeitig gelten würde.

M_I_B

Zitat von: Per am 25 November 2016, 11:17:39und außerdem blockierst du FHEM:Dort lieber mit wait arbeiten. Nebenbei: was soll dein setreading außer unbekannten Sideeffekten noch bewirken? Wenn du nicht gerade mit event-on-update-reading die Meldungen des Sensors eh abgeblockt hast, kommen die auch so bei DOIF an.
Also die 200ms- Blockade stört nicht. Aber was mich gerade irritiert ist, das an vielen Stellen im Forum, im Wiki und durch eigenes Probieren doch fest steht, das ein setreading ohne sleep den Event des SET unterdrückt. Ich habe zwar die genauen Zusammenhänge noch nicht begriffen, aber zumindest bei meinen ganzen TriState "Sensoren" funktioniert das ohne sleep nicht (siehe auch https://forum.fhem.de/index.php?topic=60930).

Und die Nummer mit dem "verbogenen" Reading ist auch aus den Threads zu dem Sensor. Der ist nämlich so gemein und setzt den status "motion" nicht selber zurück. Eine Prüfung auf "motion" würde also nur ein einziges mal funktionieren.


Korrigiere mich, wenn ich falsch liege, aber bitte so, das ich das auch verstehe ;)

BTW:
Zitatwelches man durch geschickte Namenswahl sogar generalisieren könnte.
Kann man ja auch so; die Namenswahl ist schon so gewählt. aBär das will ich an der Stelle gar nicht, da es keinen Sinn macht, das bei Auslösen eines Melders alles an geht ... Wenn das so wäre, könnte ein Flieger das schon mal für einen Flughafen halten ;)