[Workaround gefunden, ist Perl "Problem"] - mysteriöses DOIF Problem in einem Zweig.

Begonnen von Frank_Huber, 20 November 2023, 12:48:14

Vorheriges Thema - Nächstes Thema

Frank_Huber

Hallo zusammen,

wie im Betreff geschrieben kämpfe ich gerade mit einem seltsamen Problem.
Bei einem Freund haben wir ein DOIF dass je nach Verhältnis Soll zu Ist Temperatur Lüfter hoch oder runter regelt. das ganze dafür um bei normalen Heizkörpern mit niedrigeren Vorlauf Temperaturen heizen zu können.
Es gibt vier Zweige.
1. IST ist größer oder gleich als SOLL + 0.2
2. IST ist gleich SOLL
3. IST ist 0.1 kleiner als SOLL
4. IST ist 0.2 oder mehr unter SOLL
Das ist ja im Grunde nichts kompliziertes, ich habe es in vereinfachter Form in meinem Test-System:
([OG_HK_TV:Raum] >= ([SollTemp_OG:state] + 0.2)) (set OG_HK_TV Status cmd_1)
DOELSEIF ([OG_HK_TV:Raum] == [SollTemp_OG:state]) (set OG_HK_TV Status cmd_2)
DOELSEIF ([OG_HK_TV:Raum] == ([SollTemp_OG:state] - 0.1)) (set OG_HK_TV Status cmd_3)
DOELSEIF ([OG_HK_TV:Raum] <= ([SollTemp_OG:state] - 0.2)) (set OG_HK_TV Status cmd_4)


Das seltsame ist, CMD3 geht nicht wenn die IST Temperatur auf 21.6 steht. die anderen CMD gehen problemlos.
setze ich IST auf 21.7 gehen alle CMDs.

das ist doch ein einfacher Vergleich, warum machen diese 0.1 so einen Funktionsunterschied?

List mit IST von 21.7 / SOLL 21.8 cmd3 OK:
Internals:
   CFGFN     
   DEF        ([OG_HK_TV:Raum] >= ([SollTemp_OG:state] + 0.2)) (set OG_HK_TV Status cmd_1)
DOELSEIF ([OG_HK_TV:Raum] == [SollTemp_OG:state]) (set OG_HK_TV Status cmd_2)
DOELSEIF ([OG_HK_TV:Raum] == ([SollTemp_OG:state] - 0.1)) (set OG_HK_TV Status cmd_3)
DOELSEIF ([OG_HK_TV:Raum] <= ([SollTemp_OG:state] - 0.2)) (set OG_HK_TV Status cmd_4)
   FUUID      655b251a-f33f-5ef8-19c1-682d3c6675824ca8
   MODEL      FHEM
   NAME       Booster_PWM_OG
   NOTIFYDEV  OG_HK_TV,SollTemp_OG,global
   NR         277
   NTFY_ORDER 50-Booster_PWM_OG
   STATE      cmd_3
   TYPE       DOIF
   VERSION    27740 2023-07-10 09:31:11
   eventCount 50
   Helper:
     DBLOG:
       cmd:
         logdb:
           TIME       1700475308.65061
           VALUE      2
       cmd_event:
         logdb:
           TIME       1700475308.65061
           VALUE      SollTemp_OG
       cmd_nr:
         logdb:
           TIME       1700475308.65061
           VALUE      2
       cmd_seqnr:
         logdb:
           TIME       1700472268.49407
           VALUE      2
       mode:
         logdb:
           TIME       1700473102.94635
           VALUE      enabled
       state:
         logdb:
           TIME       1700475308.65061
           VALUE      cmd_2
   READINGS:
     2023-11-20 12:44:28   Device          SollTemp_OG
     2023-11-20 12:44:28   cmd             3
     2023-11-20 12:44:28   cmd_event       SollTemp_OG
     2023-11-20 12:44:28   cmd_nr          3
     2023-11-20 12:44:23   e_OG_HK_TV_Raum 21.7
     2023-11-20 12:44:28   e_SollTemp_OG_state 21.8
     2023-11-20 10:38:22   mode            enabled
     2023-11-20 12:44:28   state           cmd_3
   Regex:
     accu:
     bar:
     barAvg:
     collect:
     cond:
       OG_HK_TV:
         0:
           Raum       ^OG_HK_TV$:^Raum:
         1:
           Raum       ^OG_HK_TV$:^Raum:
         2:
           Raum       ^OG_HK_TV$:^Raum:
         3:
           Raum       ^OG_HK_TV$:^Raum:
       SollTemp_OG:
         0:
           state      ^SollTemp_OG$:^state:
         1:
           state      ^SollTemp_OG$:^state:
         2:
           state      ^SollTemp_OG$:^state:
         3:
           state      ^SollTemp_OG$:^state:
   attr:
     cmdState:
     wait:
     waitdel:
   condition:
     0          ::ReadingValDoIf($hash,'OG_HK_TV','Raum') >= (::ReadingValDoIf($hash,'SollTemp_OG','state') + 0.2)
     1          ::ReadingValDoIf($hash,'OG_HK_TV','Raum') == ::ReadingValDoIf($hash,'SollTemp_OG','state')
     2          ::ReadingValDoIf($hash,'OG_HK_TV','Raum') == (::ReadingValDoIf($hash,'SollTemp_OG','state') - 0.1)
     3          ::ReadingValDoIf($hash,'OG_HK_TV','Raum') <= (::ReadingValDoIf($hash,'SollTemp_OG','state') - 0.2)
   do:
     0:
       0          set OG_HK_TV Status cmd_1
     1:
       0          set OG_HK_TV Status cmd_2
     2:
       0          set OG_HK_TV Status cmd_3
     3:
       0          set OG_HK_TV Status cmd_4
     4:
   helper:
     NOTIFYDEV  OG_HK_TV,SollTemp_OG,global
     event      21.8
     globalinit 1
     last_timer 0
     sleeptimer -1
     timerdev   SollTemp_OG
     timerevent 21.8
     triggerDev SollTemp_OG
     DOIF_eventa:
       cmd_nr: 3
       cmd: 3
       cmd_event: SollTemp_OG
       cmd_3
     DOIF_eventas:
       cmd_nr: 3
       cmd: 3
       cmd_event: SollTemp_OG
       state: cmd_3
     timerevents:
       21.8
     timereventsState:
       state: 21.8
     triggerEvents:
       21.8
     triggerEventsState:
       state: 21.8
   internals:
   readings:
     all         OG_HK_TV:Raum SollTemp_OG:state
   trigger:
   uiState:
   uiTable:
Attributes:
   DbLogExclude .*
   do         always
   room       000 Heiz.HK.Booster
   verbose    0


List mit IST von 21.6 / SOLL 21.7 cmd3 nicht OK:
Internals:
   CFGFN     
   DEF        ([OG_HK_TV:Raum] >= ([SollTemp_OG:state] + 0.2)) (set OG_HK_TV Status cmd_1)
DOELSEIF ([OG_HK_TV:Raum] == [SollTemp_OG:state]) (set OG_HK_TV Status cmd_2)
DOELSEIF ([OG_HK_TV:Raum] == ([SollTemp_OG:state] - 0.1)) (set OG_HK_TV Status cmd_3)
DOELSEIF ([OG_HK_TV:Raum] <= ([SollTemp_OG:state] - 0.2)) (set OG_HK_TV Status cmd_4)
   FUUID      655b251a-f33f-5ef8-19c1-682d3c6675824ca8
   MODEL      FHEM
   NAME       Booster_PWM_OG
   NOTIFYDEV  OG_HK_TV,SollTemp_OG,global
   NR         277
   NTFY_ORDER 50-Booster_PWM_OG
   STATE      cmd_4
   TYPE       DOIF
   VERSION    27740 2023-07-10 09:31:11
   eventCount 48
   Helper:
     DBLOG:
       cmd:
         logdb:
           TIME       1700475308.65061
           VALUE      2
       cmd_event:
         logdb:
           TIME       1700475308.65061
           VALUE      SollTemp_OG
       cmd_nr:
         logdb:
           TIME       1700475308.65061
           VALUE      2
       cmd_seqnr:
         logdb:
           TIME       1700472268.49407
           VALUE      2
       mode:
         logdb:
           TIME       1700473102.94635
           VALUE      enabled
       state:
         logdb:
           TIME       1700475308.65061
           VALUE      cmd_2
   READINGS:
     2023-11-20 11:28:24   Device          SollTemp_OG
     2023-11-20 11:28:05   cmd             4
     2023-11-20 11:28:05   cmd_event       OG_HK_TV
     2023-11-20 11:28:05   cmd_nr          4
     2023-11-20 11:28:05   e_OG_HK_TV_Raum 21.6
     2023-11-20 11:28:24   e_SollTemp_OG_state 21.7
     2023-11-20 10:38:22   mode            enabled
     2023-11-20 11:28:05   state           cmd_4
   Regex:
     accu:
     bar:
     barAvg:
     collect:
     cond:
       OG_HK_TV:
         0:
           Raum       ^OG_HK_TV$:^Raum:
         1:
           Raum       ^OG_HK_TV$:^Raum:
         2:
           Raum       ^OG_HK_TV$:^Raum:
         3:
           Raum       ^OG_HK_TV$:^Raum:
       SollTemp_OG:
         0:
           state      ^SollTemp_OG$:^state:
         1:
           state      ^SollTemp_OG$:^state:
         2:
           state      ^SollTemp_OG$:^state:
         3:
           state      ^SollTemp_OG$:^state:
   attr:
     cmdState:
     wait:
     waitdel:
   condition:
     0          ::ReadingValDoIf($hash,'OG_HK_TV','Raum') >= (::ReadingValDoIf($hash,'SollTemp_OG','state') + 0.2)
     1          ::ReadingValDoIf($hash,'OG_HK_TV','Raum') == ::ReadingValDoIf($hash,'SollTemp_OG','state')
     2          ::ReadingValDoIf($hash,'OG_HK_TV','Raum') == (::ReadingValDoIf($hash,'SollTemp_OG','state') - 0.1)
     3          ::ReadingValDoIf($hash,'OG_HK_TV','Raum') <= (::ReadingValDoIf($hash,'SollTemp_OG','state') - 0.2)
   do:
     0:
       0          set OG_HK_TV Status cmd_1
     1:
       0          set OG_HK_TV Status cmd_2
     2:
       0          set OG_HK_TV Status cmd_3
     3:
       0          set OG_HK_TV Status cmd_4
     4:
   helper:
     NOTIFYDEV  OG_HK_TV,SollTemp_OG,global
     event      21.7
     globalinit 1
     last_timer 0
     sleeptimer -1
     timerdev   OG_HK_TV
     timerevent Raum: 21.6
     triggerDev SollTemp_OG
     timerevents:
       Raum: 21.6
       Status cmd_4
     timereventsState:
       Raum: 21.6
       Status cmd_4
     triggerEvents:
       21.7
     triggerEventsState:
       state: 21.7
   internals:
   readings:
     all         OG_HK_TV:Raum SollTemp_OG:state
   trigger:
   uiState:
   uiTable:
Attributes:
   DbLogExclude .*
   do         always
   room       000 Heiz.HK.Booster
   verbose    0

zum testen habe ich wie erwähnt das DOIF vereinfacht und im meinem System nachgestellt. anstelle der ESPEasy Lüfter setze ich ein Reading im Dummy und anstelle des echten Temperaturfühlers setze ich die Temperatur ebenfalls im Dummy.
zum nachstellen kann der Dummy "OG_HK_TV", Reading "Raum" auf 21.7 gesetzt werden.
dannach einfach den Dummy "SollTemp_OG" nacheinander auf 21.7 (cmd2), 21.8 (cmd3) und 21.9 (cmd4) gesetzt werden. alles funktioniert.

Um den Fehler nachzustellen dann den  Dummy "OG_HK_TV", Reading "Raum" auf 21.6 setzten.
dannach einfach den Dummy "SollTemp_OG" nacheinander auf 21.6, 21.7 und 21.8 setzen.
Er geht nicht im CMD3, er bleibt bei 21.7 in CMD2 stehen. CMD4 bei 21.8 dagegen geht wieder.
Ich kann es mir nicht erklären...

Alles zum nachstellen hier.

Dummy1:
defmod SollTemp_OG dummy
[font=Verdana, Arial, Helvetica, sans-serif]attr SollTemp_OG stateFormat state °C[/font]

Dummy2:
defmod OG_HK_TV dummy
[font=Verdana, Arial, Helvetica, sans-serif]attr OG_HK_TV readingList Raum[/font]
[font=Verdana, Arial, Helvetica, sans-serif]attr OG_HK_TV setList Raum[/font]
attr OG_HK_TV stateFormat Raum °C

DOIF:
defmod Booster_PWM_OG DOIF ([OG_HK_TV:Raum] >= ([SollTemp_OG:state] + 0.2)) (set OG_HK_TV Status cmd_1)\
DOELSEIF ([OG_HK_TV:Raum] == [SollTemp_OG:state]) (set OG_HK_TV Status cmd_2)\
DOELSEIF ([OG_HK_TV:Raum] == ([SollTemp_OG:state] - 0.1)) (set OG_HK_TV Status cmd_3)\
DOELSEIF ([OG_HK_TV:Raum] <= ([SollTemp_OG:state] - 0.2)) (set OG_HK_TV Status cmd_4)
[font=Verdana, Arial, Helvetica, sans-serif]attr Booster_PWM_OG do always[/font]

wäre schön wenn sich das jemand anschauen könnte. Ich kann mir keinen Reim daraus machen...

Aurel_B

#1
Habe es gerade durchgespielt und kann es nachvollziehen. Bei mir geht er auch bei OG_HK_TV Raum == 21.8 nicht durch cmd_3 durch. Schuss in's blaue: Float/Rundungsproblem? (siehe z.B. https://stackoverflow.com/questions/21587663/perl-how-to-compare-floating-numbers)

Frank_Huber

Ja, uns ist es "vor Ort" bei 21.6 / 21.7 aufgefallen.
hatte auch paar Tage gedauert da drauf zu kommen. da rechnest ja nicht damit.

es gibt bestimmt noch andere Kombinationen die gehen bzw nicht gehen.
Auch wenn ich es nicht erklären kann war ich gestern erstmal from die Ursache gefunden zu haben. nach langer Suche nach dem Phantom. :-)

Damian

{if (21.6 == ( 21.7 - 0.1)) {1} else {0}}
Das Problem kann man auch direkt in Perl (Kommandozeile) nachvollziehen

Ich würde statt == mit <= arbeiten.

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

Frank_Huber

Zitat von: Damian am 20 November 2023, 20:23:09{if (21.6 == ( 21.7 - 0.1)) {1} else {0}}
Das Problem kann man auch direkt in Perl (Kommandozeile) nachvollziehen

Ich würde statt == mit <= arbeiten.


D. H.  == sollte generell nicht zum Zahlenwerte vergleichen verwendet werden?
Und warum macht Perl das "falsch"? 

Damian

Zitat von: Frank_Huber am 20 November 2023, 20:33:24D. H.  == sollte generell nicht zum Zahlenwerte vergleichen verwendet werden?
Und warum macht Perl das "falsch"?

Da musst du die Perlautoren fragen. Das gehört leider zu den Unzulänglichkeiten dieser Programmiersprache und ist sehr ärgerlich.

Intern werden die Zahlen anders dargestellt und das führt zu Rundungsungenauigkeiten bei Berechnungen.

{if (21.6 == round(( 21.7 - 0.1),1)) {1} else {0}}
funktioniert dagegen korrekt.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Frank_Huber

Zitat von: Damian am 20 November 2023, 21:06:23
Zitat von: Frank_Huber am 20 November 2023, 20:33:24D. H.  == sollte generell nicht zum Zahlenwerte vergleichen verwendet werden?
Und warum macht Perl das "falsch"?

Da musst du die Perlautoren fragen. Das gehört leider zu den Unzulänglichkeiten dieser Programmiersprache und ist sehr ärgerlich.

Intern werden die Zahlen anders dargestellt und das führt zu Rundungsungenauigkeiten bei Berechnungen.

{if (21.6 == round(( 21.7 - 0.1),1)) {1} else {0}}
funktioniert dagegen korrekt.
Danke Damian. Dann schau ich mal wie wir das lösen. Denke aber es wird auf >= and <= herauslaufen. Ist zwar augenscheinlich Overkill für nen 0.1 Bereich, aber so ist es dann halt. 😉

Danke nochmal und nen schönen Abend! 

Damian

leider funktioniert auch

{if (21.6 <= ( 21.7- 0.1)) {1} else {0}}

nicht richtig, da die Differenz intern wahrscheinlich sowas 21,5999999999999999 ist
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Per

Sowas ist wichtig zu wissen. Ich weiß zwar nicht, ob ich Probleme aufgrund dieses Verhaltens habe, aber diese Info bei Bedarf im Hinterkopf zu haben schadet nicht.

RalfRog

#9
Könnte man die Probleme der Zahlendarstellung umgehen, wenn man die Werte vorab mit 10 multipliziert und dann Integer arbeitet?

Also 217 - 1  ::)

Gruß Ralf
FHEM auf Raspi 2B mit nanoCUL, HM-MOD-RPI-PCB und über LAN MAX!Cube mit a-culFW (Stack 868 + 433)
HM- Fensterkontakte, UP-Schalter, Bewegungsmelder und ein Rauchmelder

Frank_Huber

Zitat von: RalfRog am 21 November 2023, 08:53:07Könnte man die Probleme der Zahlendarstellung umgehen, wenn man die Werte vorab mit 10 multipliziert und dann Integer arbeitet?

Also 217 - 1 
Danke Ralf, Diese Idee war genau richtig. :-)
in den Dummys jeweils UserReadings erstellt die x10 rechnen. im DOIF dann auch auf ganze Zahlen umgestellt und so läuft es wie es soll. :-)


Aurel_B

Super, das wäre auch meine Idee gewesen und so arbeite ich oft mit Temperaturen: multiplizieren so dass Ganzzahlen entstehen (i.d.R. x10), gegebenfalls erzwungen zu integer konvertieren (z.B. auf Arduinos) und ich umgehe damit die ganze Float-Problematik. Also:

if ( (int)(Temp1*10) == (int)(Temp2*10) )
Edit: bei Temperaturregelungen kann das PID20 Modul manchmal auch sehr hilfreich sein als Alternative!