[Gelöst] Zufallszeit in DOIF-Bedingung innerhalb der Sunset-Funktion?

Begonnen von Superposchi, 17 April 2024, 10:50:47

Vorheriges Thema - Nächstes Thema

Superposchi

Hallo, ich möchte gerne meine Rolladenschaltung etwas wechselhafter gestalten.
Bisher reagierte wurden die Rolladen bei Sonnenuntergang, aber frühestens um 21:30 Uhr und spätestens um 23:00 Uhr, geschlossen. Zum Zweck der Flexibilität sind die beiden Zeiten in Readings des jeweiligen Aktors gespeichert, so kann ich sie schnell und einfach über das Frontend verändern. Das funktioniert auch perfekt.

Da aber den ganzen Winter die Rolladen damit immer um 21:30 Uhr (oder der eingestellten Zeit) geschlossen wurden, wirkt es mir zu gleichmäßig und nicht natürlich. Darum wollte ich die beiden Zeiten für frühestens und spätestens mit einer Kombination eines Zufallswertes (+/- 10 Min.) jeden Tag wechseln gestalten. Ich habe dazu das Beispiel aus der CommandRef des DOIF für zufällige Zeitberechnung statt auf den Sonnenuntergang selbst auf die beiden Zeitpunkte angepasst. Offenbar scheint aber irgendwo ein Fehler zu sein, da das DOIF nicht auslöst. Wahrscheilich ist einfach eine Klammer zu viel/zu wenig gesetzt. Ich blicke durch die Klammerlogik nicht wirklich durch. Braucht das int eventuell noch eine zusätzliche geschweifte Klammer?

Der aktuell veränderte Code lautet:
(([?HM_70B5AE:state_to_close] eq "2") and ([{sunset(0,"[([HM_70B5AE:time_to_close_after]-[00:10]+int(rand(1200)))]","[([HM_70B5AE:time_to_close_before]-[00:10]+int(rand(1200)))]")}]))
    (set HM_70B5AE [HM_70B5AE:level_down]) ({Ansage("Das Schlafzimmerrollo wird geschlossen", "Echo_Wohnzimmer,Echo_Schlafzimmer")})

Wenn ich den DOIF-Zweig manuell auslösen funktioniert er, nach der Anpassung wird er allerdings nicht mehr automatisch ausgelöst, sondern bleibt auf initilized stehen.

Erklärung der verwendeten Readings:
state_to_close        -  ist numerisch und dient zur Auswahl verschiedener Schließmethoden wie Astronomisch, Anwesenheit, feste Zeit, etc.
time_to_close_after  -  ist der Zeitpunkt für die früheste Schließung und kann aus dem Frontend angepasst werden
time_to_close_before  -  ist der Zeitpunkt für die späteste Schließung und kann aus dem Frontend angepasst werden
level_down            -  ist der Prozentwert auf den das Rollo geschlossen werden soll, zb zum Lüften 30 statt 0

Bei Wunsch kann ich das List gerne nachliefern, da der Zweig aber nur ein Auszug aus einem wesentlich größeren DOIF ist und der Rest funktioniert, würde dies meiner Meinung nach erst mal mehr Verwirrung stiften als Nutzen. Außerdem hat das DOIF vor der Codeanpassung auch in diesem Zweig komplett funktioniert, somit ist ein allgemeiner Fehler im DOIF eher auszuschließen. Wie gesagt vermute ich einfach eine falsch gesetzte Klammer in dem Teil für die Zeitpunktberechnung.

Vielleicht kann sich das mal jemand mit mehr DOIF-Erfahrung ansehen.

Damian

Du kannst schauen, ob die sunset-Zeit als Timer-Reading definiert wurde. Wenn ja, dann weißt du schon mal, dass die Timerdefinition geklappt hat.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Superposchi

#2
Nein offenbar nicht.

Das DOIF umfasst insgesamt 4 Zweige.
1. Reaktion auf Anwesenheit (Ein Timer ist erstellt, wobei mir nicht klar ist warum der auf Mitternach steht - eigentlich sollte kein Timer erstellt werden, da auf eine Rückmeldung unserer beiden Handys - die die Anwesenheit steuert - reagiert wird.)
2. Reaktion auf Astronomie (Das ist der Part der nicht funktionier -  es wurde kein Timer erstellt)
3. Manuelles Schließen von Hand (Kein Timer vorhanden da keine Automation)
4. Reaktion auf feste Uhrzeit ( 3 Timer erstellt, jeweils einer für Werktags, einer für Sammstags und einer für Sonn-/Feiertags)

Hier doch mal das List zum selber nachschauen:
Internals:
   DEF        (([?HM_70B5AE:state_to_close] eq "1") and ([Rheinertstrasse:residentsAsleep] ne "0"))
(set HM_70B5AE [HM_70B5AE:level_down]) ({Ansage("Das Schlafzimmerrollo wird geschlossen", "Echo_Wohnzimmer,Echo_Schlafzimmer")})
DOELSEIF (([?HM_70B5AE:state_to_close] eq "2") and ([{sunset(0,"[([HM_70B5AE:time_to_close_after]-[00:10]+int(rand(1200)))]","[([HM_70B5AE:time_to_close_before]-[00:10]+int(rand(1200)))]")}]))
(set HM_70B5AE [HM_70B5AE:level_down]) ({Ansage("Das Schlafzimmerrollo wird geschlossen", "Echo_Wohnzimmer,Echo_Schlafzimmer")})
DOELSEIF ([?HM_70B5AE:state_to_close] eq "3")
(set test Manuell)
DOELSEIF (([?HM_70B5AE:state_to_close] eq "4") and ([([HM_70B5AE:time_to_close_at_wd]-[00:10]+int(rand(1200)))|WD]) or ([([HM_70B5AE:time_to_close_at_sa]-[00:10]+int(rand(1200)))|Sa]) or ([([HM_70B5AE:time_to_close_at_su]-[00:10]+int(rand(1200)))|WE]) and ([HM_70B5AE] ne "off"))
(set HM_70B5AE [HM_70B5AE:level_down]) ({Ansage("Das Schlafzimmerrollo wird geschlossen", "Echo_Wohnzimmer,Echo_Schlafzimmer")})
   FUUID      640207d6-f33f-7706-d83e-dc8245ecd3a18949
   FVERSION   98_DOIF.pm:0.285460/2024-02-23
   MODEL      FHEM
   NAME       schlafzimmerrollo_schliessen
   NOTIFYDEV  global,HM_70B5AE,Rheinertstrasse
   NR         188
   NTFY_ORDER 50-schlafzimmerrollo_schliessen
   STATE      initialized
   TYPE       DOIF
   VERSION    28546 2024-02-23 20:11:05
   eventCount 33
   READINGS:
     2024-04-17 11:13:03   cmd             0
     2024-04-17 11:13:03   mode            enabled
     2024-04-17 11:13:03   state           initialized
     2024-04-17 11:13:03   timer_01_c02    18.04.2024 00:00:00
     2024-04-17 11:13:03   timer_02_c04    17.04.2024 19:51:08|WD
     2024-04-17 11:13:03   timer_03_c04    17.04.2024 21:08:10|Sa
     2024-04-17 11:13:03   timer_04_c04    17.04.2024 21:21:15|WE
   Regex:
     accu:
     bar:
     barAvg:
     collect:
     cond:
       HM_70B5AE:
         3:
           &STATE     ^HM_70B5AE$
       Rheinertstrasse:
         0:
           residentsAsleep ^Rheinertstrasse$:^residentsAsleep:
     itimer:
       HM_70B5AE:
         itimer:
           time_to_close_after ^HM_70B5AE$:^time_to_close_after:
           time_to_close_at_sa ^HM_70B5AE$:^time_to_close_at_sa:
           time_to_close_at_su ^HM_70B5AE$:^time_to_close_at_su:
           time_to_close_at_wd ^HM_70B5AE$:^time_to_close_at_wd:
           time_to_close_before ^HM_70B5AE$:^time_to_close_before:
   attr:
     cmdState:
     wait:
     waitdel:
   condition:
     0          (::ReadingValDoIf($hash,'HM_70B5AE','state_to_close') eq "1") and (::ReadingValDoIf($hash,'Rheinertstrasse','residentsAsleep') ne "0")
     1          (::ReadingValDoIf($hash,'HM_70B5AE','state_to_close') eq "2") and (::DOIF_time_once($hash,0,$wday))
     2          ::ReadingValDoIf($hash,'HM_70B5AE','state_to_close') eq "3"
     3          (::ReadingValDoIf($hash,'HM_70B5AE','state_to_close') eq "4") and (::DOIF_time_once($hash,1,$wday,"WD")) or (::DOIF_time_once($hash,2,$wday,"Sa")) or (::DOIF_time_once($hash,3,$wday,"WE")) and (::InternalDoIf($hash,'HM_70B5AE','STATE') ne "off")
   days:
     1          WD
     2          Sa
     3          WE
   do:
     0:
       0          set HM_70B5AE [HM_70B5AE:level_down]
       1          {Ansage("Das Schlafzimmerrollo wird geschlossen", "Echo_Wohnzimmer,Echo_Schlafzimmer")}
     1:
       0          set HM_70B5AE [HM_70B5AE:level_down]
       1          {Ansage("Das Schlafzimmerrollo wird geschlossen", "Echo_Wohnzimmer,Echo_Schlafzimmer")}
     2:
       0          set test Manuell
     3:
       0          set HM_70B5AE [HM_70B5AE:level_down]
       1          {Ansage("Das Schlafzimmerrollo wird geschlossen", "Echo_Wohnzimmer,Echo_Schlafzimmer")}
     4:
   helper:
     NOTIFYDEV  global,HM_70B5AE,Rheinertstrasse
     globalinit 1
     last_timer 4
     sleeptimer -1
   internals:
     all         HM_70B5AE:STATE
   intervalfunc:
   localtime:
     0          1713391200
     1          1713376268
     2          1713380890
     3          1713381675
   readings:
     all         Rheinertstrasse:residentsAsleep
   realtime:
     0          00:00:00
     1          19:51:08
     2          21:08:10
     3          21:21:15
   time:
     0          {sunset(0,"[([HM_70B5AE:time_to_close_after]-[00:10]+int(rand(1200)))]","[([HM_70B5AE:time_to_close_before]-[00:10]+int(rand(1200)))]")}
     1          ([HM_70B5AE:time_to_close_at_wd]-[00:10]+int(rand(1200)))
     2          ([HM_70B5AE:time_to_close_at_sa]-[00:10]+int(rand(1200)))
     3          ([HM_70B5AE:time_to_close_at_su]-[00:10]+int(rand(1200)))
   timeCond:
     0          1
     1          3
     2          3
     3          3
   timer:
     0          0
     1          0
     2          0
     3          0
   timers:
     1           0
     3           1  2  3
   triggertime:
     1713376268:
       localtime  1713376268
       hash:
     1713380890:
       localtime  1713380890
       hash:
     1713381675:
       localtime  1713381675
       hash:
     1713391200:
       localtime  1713391200
       hash:
   uiState:
   uiTable:
Attributes:
   alias      Schließung
   do         always
   group      Schlafzimmerfenster
   room       Steuerung->Rolladen
   verbose    4

Wobei ich mir bei näherer Betrachtung nicht sicher bin ob der erste Timer nicht doch bei der Astronomischen Schaltung zum tragen kommt. Dann wäre der Zeitpunkt Mitternacht aber definitiv verkehrt.

Superposchi

Also soweit ich es jetzt eingrenzen konnte liegt der Fehler in
{sunset(0,"[([HM_70B5AE:time_to_close_after]-[00:10]+int(rand(1200)))]","[([HM_70B5AE:time_to_close_before]-[00:10]+int(rand(1200)))]")}Egal in welcher Klammerkonstellation ist es probiere, es wird entweder ein Fehler ausgegeben oder der Wert wird ignoriert.

Sind zwischen den Anführungszeichen gar keine Berechnungen mehr möglich?
Gibt es eventuell eine Möglichkeit das Reading vor dem Einfügen zu berechnen, zb durch ein UserReading?

Ralf W.

Nimm doch Attribut wait und pack rand dort hinein.
http://twitter.com/RWausD
Schon gewusst, dass Haarausfall zu einer Glatze führen kann?

FHEM: NUC7PJYH2, Ubuntu Server 22.04.2 LTS, HMCCU - RaspberryMatic, DE ConBee II, diverse Sensoren und Aktoren.

Superposchi

Die Möglichkeit ist mir bisher nicht bekannt.
Wie müsste der Eintrag dann aussehen? Einfach int(rand(1200)) statt der Sekundenzahl eingeben?

Damian

Das Rechnen mit Zeitangaben funktioniert nur bei indirekten Zeittriggern, du hast hier als Zeittrigger eine Perlfunktion nämlich sunset, die Zeitangaben werden als Übergabeparameter übergeben und an dieser Stelle greift die DOIF-Zeitberechnung nicht mehr.

Man kann also bei den Zeitparametern von sunset höchstens ein Zeit-Reading angeben, aber keine DOIF-Zeitberechnung vornehmen, dafür kann man aber das Ergebnis von sunset wiederum für eine Zeitberechnung des Timers nutzen:

[({sunset(0,"[HM_70B5AE:time_to_close_after]","[HM_70B5AE:time_to_close_before]")}+rand(2400))]
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Superposchi

Das Ergebnis von Sunset ist ja jeden Tag anders und somit wechselnd. Da macht die Berechnung in meinen Augen weniger Sinn.
Mir geht es ja in erster Linie darum, dass es auch abwechselnde Zeiten gibt wenn das Ergebnis von Sunset außerhalb des Bereichs der beiden Zeitparameter liegt. Damit im Winter der Rolladen eben nicht jeden Tag konstatnt zu Beginn des ersten Zeitparameters schließt.

Wäre es denkbar das Zeit-Reading per UserReadings auszulesen und inklusive der Zufallsberechnung in ein weiteres Reading zu schreiben, welches dann in der DOIF-Bedingung statt dem originalen Zeit-Reading geschrieben wird? Beispielsweise so:
time_to_close_after2 { ReadingsVal($name,"time_to_close_after","0")-600+int(rand(1200)) }Analog dazu für das Ende des Zeitbereichs das gleiche mit dem anderen Reading. Vorausgesetzt das geht mit der Berechnung der verschiedenen Einheiten überhaupt. Das Reading hat ja das Format hh:mm und die beiden Operatoren das Format sec.
Würde das Userreading jeden Tag neu berechnet oder nur wenn das Reading das die jeweiligen Zeitwerte beinhaltet sich ändert?

Superposchi

#8
GELÖST

Habe es jetzt tatsächlich mit einem UserReading gemacht und mit etwas tüftelei bin ich zum Ziel gekommen.
Mit dem Code:
time_to_close_after_random { my($a,$b) = split(':', ReadingsVal($NAME, 'time_to_close_after', '0:0'));; my $seconds = ($a*3600)+$b*60;; my($seconds) = $seconds-600+int(rand(1200));; my $result = POSIX::strftime("%H:%M",gmtime($seconds));; return $result }wird aus dem Reading das die Uhrzeit beinhaltet und im Frontend editiert werden kann ein neues Reading mit einem Zufallsfenster von +/-10 Minuten erstellt. Da das UserReading bei jeder Rolladenbewegung neu gerechnet wird, wird es also mindestens einmal am Tag erneuert und somit sollte jeden Tag eine leichte Änderung der Zeit existieren.