[gelöst] ELSE in DOIF greift nicht

Begonnen von kroman, 08 Oktober 2017, 14:33:29

Vorheriges Thema - Nächstes Thema

kroman

Schönen Nachmittag!

Ich kämpfe schon seit einigen Stunden mit folgendem DOIF und hoffe, dass mir jemand unter die Arme greifen kann.


define d_testa dummy
attr d_testa userReadings oldState { OldValue($NAME)}

define doif_test DOIF ([d_test1] eq "on" and [d_test2] eq "on") (set d_testa sleep) DOELSEIF ([d_test1] eq "on" and [d_test2] eq "off") ( IF ( {ReadingsVal("d_testa","oldState","") eq "away"} ) (set d_testa home,set d_testb home_zuvor_away) ELSE (set d_testa home,set d_testb home_zuvor_sleep) ) DOELSE (set d_testa away)



Der Ablauf ist folgender:

1. d_test1 und d_test2 sind off
-> d_testa:STATE=away -> OK
-> d_testb:STATE=initial -> OK (manuell gesetzt zur Veranschaulichung)


Internals:
   NAME       d_testa
   NR         215
   STATE      away
   TYPE       dummy
   READINGS:
     2017-10-08 13:54:36   oldState        home
     2017-10-08 13:54:36   state           away

Internals:
   NAME       d_testb
   NR         211
   STATE      initial
   TYPE       dummy
   READINGS:
     2017-10-08 13:54:45   state           initial


2. set d_test1 on
-> d_testa:STATE geht auf home -> OK
(man sieht hier auch, dass oldState funktioniert)
-> d_testb:STATE=home_zuvor_away -> OK


Internals:
   NAME       d_testa
   NR         215
   STATE      home
   TYPE       dummy
   READINGS:
     2017-10-08 13:57:44   oldState        away
     2017-10-08 13:57:44   state           home

Internals:
   NAME       d_testb
   NR         211
   STATE      home_zuvor_away
   TYPE       dummy
   READINGS:
     2017-10-08 13:57:44   state           home_zuvor_away


3. set d_test2 on
-> d_testa:STATE geht auf sleep -> OK
(oldState home passt auch)


Internals:
   NAME       d_testa
   NR         215
   STATE      sleep
   TYPE       dummy
   READINGS:
     2017-10-08 14:00:30   oldState        home
     2017-10-08 14:00:30   state           sleep

Internals:
   NAME       d_testb
   NR         211
   STATE      home_zuvor_away
   TYPE       dummy
   READINGS:
     2017-10-08 13:57:44   state           home_zuvor_away


4. set d_test2 off
-> d_testa:STATE geht auf home -> OK
-> aber d_testb:STATE geht nicht auf home_zuvor_sleep -> NOK


Internals:
   NAME       d_testa
   NR         215
   STATE      home
   TYPE       dummy
   READINGS:
     2017-10-08 14:03:20   oldState        sleep
     2017-10-08 14:03:20   state           home

Internals:
   NAME       d_testb
   NR         211
   STATE      home_zuvor_away
   TYPE       dummy
   READINGS:
     2017-10-08 14:03:20   state           home_zuvor_away


Die ELSE Anweisung innerhalb des DOIF greift also nicht und ich weiß nicht warum.
Ich hab's auch mit perl if nicht hinbekommen.

Das zeigt der Event monitor an dieser Stelle:

2017-10-08 14:22:12 dummy d_testa home
2017-10-08 14:22:12 dummy d_testa oldState: sleep
2017-10-08 14:22:12 dummy d_testb home_zuvor_away
2017-10-08 14:22:12 DOIF doif_test cmd_nr: 2
2017-10-08 14:22:12 DOIF doif_test cmd: 2
2017-10-08 14:22:12 DOIF doif_test cmd_event: d_test2
2017-10-08 14:22:12 DOIF doif_test cmd_2
2017-10-08 14:22:12 dummy d_test2 off


Und das steht im log:

2017.10.08 14:24:20 5: Cmd: >set d_test2 off<
2017.10.08 14:24:20 4: dummy set d_test2 off
2017.10.08 14:24:20 5: Starting notify loop for d_test2, 1 event(s), first is off
2017.10.08 14:24:20 5: Cmd: >IF ( {ReadingsVal("d_testa","oldState","") eq "away"} ) (set d_testa home,set d_testb home_zuvor_away) ELSE (set d_testa home,set d_testb home_zuvor_sleep)<
2017.10.08 14:24:20 5: Cmd: >{if( {ReadingsVal("d_testa","oldState","") eq "away"} ){fhem('set d_testa home');fhem('set d_testb home_zuvor_away')}else{fhem('set d_testa home');fhem('set d_testb home_zuvor_sleep')}}<
2017.10.08 14:24:20 1: PERL WARNING: Odd number of elements in anonymous hash at (eval 86072) line 1.
2017.10.08 14:24:20 3: eval: {if( {ReadingsVal("d_testa","oldState","") eq "away"} ){fhem('set d_testa home');fhem('set d_testb home_zuvor_away')}else{fhem('set d_testa home');fhem('set d_testb home_zuvor_sleep')}}
2017.10.08 14:24:20 5: Cmd: >set d_testa home<
2017.10.08 14:24:20 4: dummy set d_testa home
2017.10.08 14:24:20 5: Starting notify loop for d_testa, 2 event(s), first is home
2017.10.08 14:24:20 5: End notify loop for d_testa
2017.10.08 14:24:20 5: Cmd: >set d_testb home_zuvor_away<
2017.10.08 14:24:20 4: dummy set d_testb home_zuvor_away
2017.10.08 14:24:20 5: Starting notify loop for d_testb, 1 event(s), first is home_zuvor_away
2017.10.08 14:24:20 5: End notify loop for d_testb
2017.10.08 14:24:20 5: Starting notify loop for doif_test, 4 event(s), first is cmd_nr: 2
2017.10.08 14:24:20 5: End notify loop for doif_test
2017.10.08 14:24:20 5: End notify loop for d_test2


Hat jemand Rat?

Auch bessere Lösungen sind gerne willkommen.
Mir gefällt diese (abgesehen davon, dass sie nicht funktioniert) eh nicht 100%ig, aber mir fällt nichts besseres ein  :-\)

Danke im Voraus!

Gruß,
kroman

viegener

Ich habs jetzt nicht genauer analysiert, aber ich denke die geschweiften Klammern in deinem IF sind ein Problem. Du verwendest diese um auf die perl-Ebene zu kommen, das ist aber für IF laut commandref gar nicht nötig:

ZitatThe <condition> is the same as in perl-if

Ich vermute mal, dass daher auch die perl-Warnung kommt
Odd number of elements in anonymous hash at (eval 86072) line 1.

Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

amenomade

Ja, IF ( {ReadingsVal("d_testa","oldState","") eq "away"} )
=> IF ( [d_testa:oldState] eq "away" )
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

kroman

Danke euch beiden mal!

Da war ich jedoch auch schon denke ich.
Hier funktioniert schon Schritt 2 nicht.


([d_test1] eq "on" and [d_test2] eq "on") (set d_testa sleep) DOELSEIF ([d_test1] eq "on" and [d_test2] eq "off") ( IF ( [d_testa:oldState] eq "away" ) (set d_testa home,set d_testb home_zuvor_away) ELSE (set d_testa home,set d_testb home_zuvor_sleep) ) DOELSE (set d_testa away)


1. d_test1 und d_test2 sind off
-> d_testa:STATE=away -> OK
-> d_testb:STATE=initial -> OK (manuell gesetzt zur Veranschaulichung)


Internals:
   NAME       d_testa
   NR         215
   STATE      away
   TYPE       dummy
   READINGS:
     2017-10-08 19:45:22   oldState        home
     2017-10-08 19:45:22   state           away

Internals:
   NAME       d_testb
   NR         211
   STATE      initial
   TYPE       dummy
   READINGS:
     2017-10-08 19:49:42   state           initial


2. set d_test1 on
-> d_testa:STATE geht auf home -> OK
-> d_testb:STATE=home_zuvor_sleep, sollte aber home_zuvor_away sein -> NOK


Internals:
   NAME       d_testa
   NR         215
   STATE      home
   TYPE       dummy
   READINGS:
     2017-10-08 19:50:54   oldState        away
     2017-10-08 19:50:54   state           home

Internals:
   NAME       d_testb
   NR         211
   STATE      home_zuvor_sleep
   TYPE       dummy
   READINGS:
     2017-10-08 19:50:54   state           home_zuvor_sleep



2017.10.08 19:50:54 5: Cmd: >set d_test1 on<
2017.10.08 19:50:54 4: dummy set d_test1 on
2017.10.08 19:50:54 5: Starting notify loop for d_test1, 1 event(s), first is on
2017.10.08 19:50:54 5: Cmd: >IF ( [d_testa:oldState] eq "away" ) (set d_testa home,set d_testb home_zuvor_away) ELSE (set d_testa home,set d_testb home_zuvor_sleep)<
2017.10.08 19:50:54 5: Cmd: >{if( ReadingValIf('d_testa','oldState','') eq "away" ){fhem('set d_testa home');fhem('set d_testb home_zuvor_away')}else{fhem('set d_testa home');fhem('set d_testb home_zuvor_sleep')}}<
2017.10.08 19:50:54 5: Cmd: >set d_testa home<
2017.10.08 19:50:54 4: dummy set d_testa home
2017.10.08 19:50:54 5: Starting notify loop for d_testa, 2 event(s), first is home
2017.10.08 19:50:54 5: End notify loop for d_testa
2017.10.08 19:50:54 5: Cmd: >set d_testb home_zuvor_sleep<
2017.10.08 19:50:54 4: dummy set d_testb home_zuvor_sleep
2017.10.08 19:50:54 5: Starting notify loop for d_testb, 1 event(s), first is home_zuvor_sleep
2017.10.08 19:50:54 5: End notify loop for d_testb
2017.10.08 19:50:54 5: Starting notify loop for doif_test, 4 event(s), first is cmd_nr: 2
2017.10.08 19:50:54 5: End notify loop for doif_test
2017.10.08 19:50:54 5: End notify loop for d_test1


Kann es sein, dass DOIF schneller ist als oldState?

amenomade

#4
Aber bei dem Moment, wo Du "set d_test1 on" machst, ist d_testa:oldState  noch gleich "home".

Dann kommt das Event "d_test1 on", der triggert dein DOIF, der prüft die Bedingung (dann immer noch "home"), und führt den Befehl aus "ELSE (set d_testa home,set d_testb home_zuvor_sleep)"

Erst dann kommt das Event "d_testa home", der triggert den userReading, und dies (oldState) wechselt zu away.

Es scheint mir alles ganz normal zu sein. Das DOIF ist nicht schneller als oldState. Das DOIF löst das Event aus, das oldState dann ändert.
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

viegener

@anemode: absolut richtig

@kroman: das problem ist ja, dass auch userReadings ja auf die events reagieren und damit im selben notify loop wie der DOIF laufen, damit kannst Du nicht damit rechnen, dass das user reading bereits gewechselt hat.
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

kroman

Danke Leute!

Ich hatte einen Knopf im Hirn.
Ich brauche ja nur d_testa:state statt d_testa:oldState zu verwenden, dann funktioniert alles wie ich will.

Wie bin ich nur auf diesen oldState gekommen? (Frage an mich selbst)
Darüber werde ich morgen früh nochmal mit frischem Kopf nachdenken.

viegener

Überhaupt kein Thema - ich habe auch mindestens eine halbe Stunde draufgestarrt, bis mir endlich klar wurde, dass eigentlich kein Fehler besteht
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

amenomade

Zitat@anemode: absolut richtig

Wer ist das? ;)
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

viegener

@amenomade: Oops - bitte vielstmals um Entschuldigung - kleine Rechtschreibstörung am Abend - wenn man einmal nicht Ctrl-C/Ctrl-V macht - schon ist es verkehrt
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

amenomade

Kein Thema. Wenn man 1/2 Stunde lang auf ein DOIF starrt, fängt man bestimmt an, zu schielen ;)
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

kroman

Dann könnt ihr euch vorstellen wie's mir geht, ich starr da schon fast durchgehend seit gestern drauf  ;D

Per

Warum löst du das IF nicht ohnehin einfach auf und machst zwei DOELSEIF-Zweige draus? So groß ist die Ersparnis auch nicht auf der Vergleichsseite.
Und bitte: verwende <Enter>, um den Code lesbarer zu machen.


([d_test1] eq "on" and [d_test2] eq "on") (set d_testa sleep)
DOELSEIF ([d_test1] eq "on" and [d_test2] eq "off" and [d_testa:oldState] eq "away" ) (set d_testa home,set d_testb home_zuvor_away)
DOELSEIF ([d_test1] eq "on" and [d_test2] eq "off") (set d_testa home,set d_testb home_zuvor_sleep)
DOELSE (set d_testa away)

(hier mal noch mit "oldState")

Noch besser wird es mit <Enter> und <Tab>, letzteren muss man aber rein kopieren, z.B. aus einem echten Editor oder einem alten Beitrag.
([d_test1] eq "on" and [d_test2] eq "on")
(set d_testa sleep)
DOELSEIF ([d_test1] eq "on" and [d_test2] eq "off" and [d_testa:oldState] eq "away" )
(set d_testa home,set d_testb home_zuvor_away)
DOELSEIF ([d_test1] eq "on" and [d_test2] eq "off")
(set d_testa home,set d_testb home_zuvor_sleep)
DOELSE
(set d_testa away)


amenomade

Zitat<Tab>, letzteren muss man aber rein kopieren, z.B. aus einem echten Editor oder einem alten Beitrag

Oder man aktiviert CodeMirror https://wiki.fhem.de/wiki/Konfiguration#Syntaxhervorhebung
Dann funktioniert TAB. Und dazu profitiert man von Syntaxhervorhebungs-, Befehlsauswahl- und Befehlsvervollständigungsfunktionen.
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

Per

Zitat von: amenomade am 09 Oktober 2017, 16:44:46Oder man aktiviert CodeMirror
Stimmt, auf Fhem habe ich das. Aber im Forum funktioniert das noch nicht ;).

kroman

Zitat
Warum löst du das IF nicht ohnehin einfach auf und machst zwei DOELSEIF-Zweige draus? So groß ist die Ersparnis auch nicht auf der Vergleichsseite.

Danke für den Vorschlag Per, das ist vielleicht die übersichtlichere Variante, wenn auch Geschmackssache würde ich sagen.

Zitat
Und bitte: verwende <Enter>, um den Code lesbarer zu machen.

Darüber hab ich sogar nachgedacht, doch es dann gelassen, weil ich nicht wußte ob (um alles richtig zu machen) ich nun den Backslash am Ende ranmachen muss oder nicht.

Also nicht, weil man ja von der DEF ausgeht und nicht von der fhem.cfg, richtig?
Ich werde das aber künftig beherzigen.

Codemirror hatte ich schon mal in Verwendung, aber dann wieder abgeschalten weil die DEF keinen Zeilenbruch macht und man bei langen defines immer links und rechts scrollen muss. Wenn man den Zeilenumbruch manuell macht, steht der auch in der fhem.cfg was mich hauptsächlich beim grepen stört.
Also auch hier:

https://forum.fhem.de/index.php?topic=40836.0

Leider, sonst hätte ich es angelassen.

kroman


attr WEB codemirrorParam { "lineWrapping":true }


Jetzt bin ich wieder dabei.