Hauptmenü

DOIF/do always

Begonnen von PatrickR, 30 Januar 2016, 15:33:04

Vorheriges Thema - Nächstes Thema

PatrickR

Mahlzeit!

Habe aktuell ca. 10 DOIFs erfolgreich im Einsatz und ging bislang davon aus, das Prinzip zu durchschauen. Nun habe ich ein Problem mit folgender Definition:

D_OG.WO.VR100_clean:

([Presence_all] eq "present")
()
DOELSEIF ([10:00|15])
(set OG.WO.VR100 cleanHouse)
DOELSEIF ([10:00|2346])
(set OG.WO.VR100 cleanSpot 250 250)



attr D_OG.WO.VR100_clean do always


Das Modul soll verschiedene Programme meines Staubsaugerroboters wochentagsabhängig starten, sofern niemand zu Hause ist. Statt den Präsenzstatus in beiden Zweigen abzufragen ging ich davon aus, mit einem leeren Zweig (wie oben) das Problem eleganter gelöst zu haben. Nun wurde ich heute morgen unsanft geweckt als man mir mitteilte, der Roboter fahre gerade durch die Wohnung.

Nun meine Fragen:

  • Ich ging bislang davon aus, dass bei jedem Event einer der Bedingungen in eckigen Klammern die DOIF-Bedingungen sequenziell geprüft werden. Wieso wurde dann heute morgen cleanSpot 250 250 ausgelöst?
  • Ist do always in meinem Fall (also konkret bei festen Zeiten wie [10:00|2346]) überhaupt nötig?

Danke im voraus!

Patrick
lepresenced - Tracking von Bluetooth-LE-Tags (Gigaset G-Tag) mittels PRESENCE

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning." - Rich Cook

Ellert

Zitatging ich davon aus, mit einem leeren Zweig (wie oben) das Problem eleganter gelöst zu haben
Falscher Ausgangspunkt ;) , wie DOIF sich wirklich verhält, steht schon in der Einleitung, s. http://fhem.de/commandref_DE.html#DOIF . Noch Fragen?

turo

#2
Moin, moin,

beim DOIF werden nur die Bedingungen geprüft, in denen ein Gerät oder eine Triggerzeit vorkommt, die gerade "gezündet" hat. Heute um 10:00 gab es keine Änderung bei Presence_all, daher wurden nur die 2. und 3. Bedingung geprüft und die 3. schlug dann zu...

Lösung: DOELSEIF ([10:00|15] and [Presence_all] ne "present") usw.

Mit dem "do always": Ich würde sagen, dass ist hier nicht nötig.

EDIT: Auf den leeren Zweig kann man natürlich dann ganz verzichten - das wäre eleganter.

Also

([10:00|15] and [Presence_all] ne "present" )
(set OG.WO.VR100 cleanHouse)
DOELSEIF ([10:00|2346] and [Presence_all] ne "present" )
(set OG.WO.VR100 cleanSpot 250 250)

3xRaspberry PI, Homematic, SELVE Rollos, 1-wire, Logitech Harmony, Alexa, Fussbodenheizung (ESP8266), Netatmo

PatrickR

@turo
Danke für die hilfreiche Antwort. Ich muss mir irgendwie abgewöhnen, DOIF mit dem IF eigentlich jeder anderen Programmiersprache zu vergleichen :)
Wie in Deinem Vorschlag hatte ich es tatsächlich vorher, wollte aber auf die Doppelung der Presence-Abfrage verzichten. Jetzt sollte es laufen.

Patrick
lepresenced - Tracking von Bluetooth-LE-Tags (Gigaset G-Tag) mittels PRESENCE

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning." - Rich Cook

turo

Ja genau! In einigen Beiträgen hier im Forum habe ich gemerkt, dass viele genau mit diesem "ich werte nicht alle Bedingungen aus" Feature von DOIF so ihre Probleme haben. Und das trifft wohl genau diejenigen, die schon einige Programmiererfahrungen haben: Eilert hat zwar Recht, dass das fett und prominent im Handbuch steht, aber solche  if ... elseif ... else Kaskaden hat man schon in -zig Programmiersprachen gesehen und gelernt. Da guckt man bei der n+1. Version dann nur noch auf "ist es hier jetzt 'else if', 'elsif', 'elif' oder noch was" und geht etwas nachlässig davon aus, dass das schon so funktioniert wie immer.

Ich gestehe, dass ich da auch voll reingetappt bin und ziemlich gegrübelt habe, bis ich das Verhalten eingesehen hatte (turo an turo: "Das musst Du doch hinkriegen - das ist doch einfachste Logik!")  :)

turo

3xRaspberry PI, Homematic, SELVE Rollos, 1-wire, Logitech Harmony, Alexa, Fussbodenheizung (ESP8266), Netatmo

Damian

Zitat von: turo am 31 Januar 2016, 11:49:02
Ja genau! In einigen Beiträgen hier im Forum habe ich gemerkt, dass viele genau mit diesem "ich werte nicht alle Bedingungen aus" Feature von DOIF so ihre Probleme haben. Und das trifft wohl genau diejenigen, die schon einige Programmiererfahrungen haben: Eilert hat zwar Recht, dass das fett und prominent im Handbuch steht, aber solche  if ... elseif ... else Kaskaden hat man schon in -zig Programmiersprachen gesehen und gelernt. Da guckt man bei der n+1. Version dann nur noch auf "ist es hier jetzt 'else if', 'elsif', 'elif' oder noch was" und geht etwas nachlässig davon aus, dass das schon so funktioniert wie immer.

Ich gestehe, dass ich da auch voll reingetappt bin und ziemlich gegrübelt habe, bis ich das Verhalten eingesehen hatte (turo an turo: "Das musst Du doch hinkriegen - das ist doch einfachste Logik!")  :)

turo

Es wäre kein Problem per Attribut den Check auf alle Fälle auszuweiten. Meine Prophezeiung ist allerdings jetzt schon, dass es nicht gut funktionieren wird. Diese Funktionalität hatte ich am Anfang im Modul so programmiert und wunderte mich immer, was die Module so alles machten, was ich eigentlich nicht wollte. Oft kommt man gar nicht mehr zur Auswertung des Zweiges, wo das jeweilige Event abgefragt wird, weil zuvor irgendein anderer Zweig wahr ist. Die Sache ist also schon etwas komplexer, als eine sequenzielle Abarbeitung in höheren Programmiersprachen.

Gruß

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

turo

@Damian: Ich finde auch, dass das Verhalten genau so sinnvoll ist, wie Du es derzeit implementiert hast: Im Prinzip ist das ja ein implizites "und außerdem ist gerade ein passender Event generiert worden", was an jede Bedingung angehängt wird. Und viele geläufige Konstrukte, wie etwa die Reaktion auf (Handy-)Messages, funktionieren nur mit dieser Ergänzung. Da müssen wir "Programmiererfahrenen" uns eben daran erinnern, die Beschreibung genau zu lesen ;-)

Ein "check always" Argument wäre natürlich möglich, fände ich aber etwas zu grob und ich würde befürchten, dass sich das dann viele als Standardmaßnahme bei Problemen einschalten - diese dann vielleicht sogar lösen, aber sich im Endeffekt schwierigere Probleme an anderen Stellen einfangen. Ich weiss nicht, wie Du zu weiteren syntaktischen Erweiterungen stehst, aber wie wäre es denn mit einem "check this always" pro Bedingung? Vielleicht ein "?" nach der öffnenden Klammer? Dann wäre so Probleme wie von PatrickR eleganter lösbar. Ich denke da vor allem so an (negative) Zusicherungen wie "auf keinen Fall, wenn jemand im Haus ist" oder "wenn es über 20 Grad sind, brauchen wir uns gar nicht erst um Heizzeitpunkte und so kümmern".

Gruss,
turo
3xRaspberry PI, Homematic, SELVE Rollos, 1-wire, Logitech Harmony, Alexa, Fussbodenheizung (ESP8266), Netatmo

Damian

Zitat von: turo am 31 Januar 2016, 17:03:06
@Damian: Ich finde auch, dass das Verhalten genau so sinnvoll ist, wie Du es derzeit implementiert hast: Im Prinzip ist das ja ein implizites "und außerdem ist gerade ein passender Event generiert worden", was an jede Bedingung angehängt wird. Und viele geläufige Konstrukte, wie etwa die Reaktion auf (Handy-)Messages, funktionieren nur mit dieser Ergänzung. Da müssen wir "Programmiererfahrenen" uns eben daran erinnern, die Beschreibung genau zu lesen ;-)

Ein "check always" Argument wäre natürlich möglich, fände ich aber etwas zu grob und ich würde befürchten, dass sich das dann viele als Standardmaßnahme bei Problemen einschalten - diese dann vielleicht sogar lösen, aber sich im Endeffekt schwierigere Probleme an anderen Stellen einfangen. Ich weiss nicht, wie Du zu weiteren syntaktischen Erweiterungen stehst, aber wie wäre es denn mit einem "check this always" pro Bedingung? Vielleicht ein "?" nach der öffnenden Klammer? Dann wäre so Probleme wie von PatrickR eleganter lösbar. Ich denke da vor allem so an (negative) Zusicherungen wie "auf keinen Fall, wenn jemand im Haus ist" oder "wenn es über 20 Grad sind, brauchen wir uns gar nicht erst um Heizzeitpunkte und so kümmern".

Gruss,
turo

Ich denke, dass das Modul inzwischen komplex genug geworden ist. Jede zusätzliche Erweiterung in diese Richtung, würde die Komplexität weiter erhöhen. Ich persönlich konnte jedes meiner Probleme mit den jetzigen Möglichkeiten des Moduls lösen, manchmal muss man zwei mal überlegen, bis man zu einer befriedigenden Lösung kommt. Und wem das zu wenig ist, der hat immer noch die Möglichkeit komplexere Probleme in Perl zu lösen oder ein spezifisches FHEM-Modul zu programmieren. Für mich ist DOIF ein Ersatz für at, notify, watchdog in Verbindung mit if-Abfragen nicht mehr und auch nicht weniger.

Gruß

Damian

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

blommaep

Mochte bei diese Thread anschliessen, haben ein etwas ähnliche Frage.
Ich verstehe folgendes nicht:

Ich habe folgendes DOIF:
defmod n_reset_presence_change_anybody DOIF ([pres_change_anybody:"arrived|left"]) \
  ( set pres_change_anybody idle)
attr n_reset_presence_change_anybody do resetwait
attr n_reset_presence_change_anybody room program
attr n_reset_presence_change_anybody wait 5

(Ein andere DOIF setz die dummy pres_change_anybody und das idee ein trigger zu haben den nach 5 secunden wieder idle geht, also hab ich damit ein Event ähnlich wann jemand zuhause kommt oder wieder geht. Wieleicht gibt es besser Methoden, dies ist was ich dazu gefunden hab)

Ich hatte as so verstanden das die events arrived und left immer den DOIF triggern wurden, mindestens wenn as nich schon die gleiche wert hat (auch ohne do resetwait). Es hat aber nicht funktioniert. Nur wann ich den "do resetwait" zugefugt hab, hat es funktioniert, obwohl es sehr seltsam (sichter nicht beim testen) wirklich ein zweite event innerhalb 5 seconden passiert natürlich.

Habe ähnliche, mehr komplizierte DOIF den nur mit do always gut lauft.

Ich habe mit alles lezen (das DOIF kann ja richtig viel), noch immer nicht verstanden. Also vieleicht versteht ihr. Frage also: warum brauche ich in DOIF wie diese ein "do always/do resetwait"?

Danke

Ellert

In Deinem Fall benötigst Du do always, weil in DOIF Loops unterbunden sind und set pres_change_anybody idle das DOIF daher nicht zurücksetzt, bzw. nicht in den Zustand cmd_2 schaltet.

blommaep

Dank Ellert. Das erklart mir schon viel.

Das "do always" Umschreibung sagt "wiederholt den Ausführungsteil, wenn die selbe Bedingung wiederholt wahr wird."
Das es dabei auch (wegen die virtuelle cmd_2) die "falsche" loop detection auflost, is vieleicht für mehr Leute schwer zu verstehen. Wielleicht besser wann das auch im commandref vermelded wirden könnte?

Ich glaube es ist klar das meine DOIF nicht wirklich ein loop verursachen kann. Ist diese loop unterbinding irgendwo beschrieben (wie es annehmt ein loop zu haben...)? Mochte mir hilfen das algemeines zu verstehen. zB wird so etwas auch als loop identifiziert? DOIF A ([GeratA:event] ) (set geratB x) // DOIF B ([geratB:event]) (set geratC) // DOIF C ([geratC:event]) (set geratA) ?

Ich habe auch versucht verbose auf 5 zu stellen und im log etwas von die loop detection zuruck zu finden (besonders bei andere Falle den nicht so einfach sind) . Ich finde aber nichts. Gibt es irgendwie ein log davon? Das wäre mich hielfen Diese fällen zu detectieren und verstehen. (Meine Ahnung es war bestes wann diese auch in loglevel 0 geloggt werden damit es eigentlich ein "fehler" im programm betrifft, aber wieleicht ist diese Idee falsh)

Vielen Dank.

Damian

Ein von DOIF erkannter Loop sieht so aus:

DOIF ([A]) (set A ...)

Ein Loop über mehrere DOIFs wird nicht erkannt bzw. nicht unterbunden, z. B.:

DOIF ([B]) (set A ...)  und DOIF ([A]) (set B ... )

hier würden beide DOIFs ping-pong spielen.

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

Ellert

Zitat von: blommaep am 21 Januar 2018, 15:27:47
Dank Ellert. Das erklart mir schon viel.

Das "do always" Umschreibung sagt "wiederholt den Ausführungsteil, wenn die selbe Bedingung wiederholt wahr wird."
Das es dabei auch (wegen die virtuelle cmd_2) die "falsche" loop detection auflost, is vieleicht für mehr Leute schwer zu verstehen. Wielleicht besser wann das auch im commandref vermelded wirden könnte?

Ich glaube es ist klar das meine DOIF nicht wirklich ein loop verursachen kann. Ist diese loop unterbinding irgendwo beschrieben (wie es annehmt ein loop zu haben...)? Mochte mir hilfen das algemeines zu verstehen. zB wird so etwas auch als loop identifiziert? DOIF A ([GeratA:event] ) (set geratB x) // DOIF B ([geratB:event]) (set geratC) // DOIF C ([geratC:event]) (set geratA) ?

Ich habe auch versucht verbose auf 5 zu stellen und im log etwas von die loop detection zuruck zu finden (besonders bei andere Falle den nicht so einfach sind) . Ich finde aber nichts. Gibt es irgendwie ein log davon? Das wäre mich hielfen Diese fällen zu detectieren und verstehen. (Meine Ahnung es war bestes wann diese auch in loglevel 0 geloggt werden damit es eigentlich ein "fehler" im programm betrifft, aber wieleicht ist diese Idee falsh)

Vielen Dank.

Über https://wiki.fhem.de/wiki/DOIF findest Du die wichtigsten Entwicklungsthreads und auch etwas zu Loops http://forum.fhem.de/index.php/topic,41859.0.html

In der Commandref ist das Attribut selftrigger beschrieben, dort steht auch etwas über Schleifen.