Zeitverzögerung in myUtilies

Begonnen von tfriedrich85, 25 Oktober 2019, 13:33:16

Vorheriges Thema - Nächstes Thema

tfriedrich85

Hallo zusammen,

ich betreibe mehrere Dimmer, die ich über Fhem ansteuern kann.
Nun möchte ich erreichen, dass diese Dimmer langsam auf einen Zielwert hochdimmen.
Aber dazu benötige ich eine Art sleep und delay. Scheinbar ist die Implementierung in fhem nicht so einfach.
Denn Sleep darf nicht ohne einen nachfolgenden Befehl verwendet werden, da sonst das System auf sleep wartet.


sub Dimmer($)
{
my $wert = shift;
my $step = ($wert-25) / 100;
my $prozent = $wert*10;
my $cmd =0;

for (my $i = 1; $i <= 100; $i++){
   my $hhhex =0;
   $prozent = $i * $step;
   
         #Werte für den Dimmer in HEX umrechnen
$hhhex = sprintf("0x%X", $prozent);
    #Werte an Dimmer schicken
         {system("i2cset -y 1 0x5b 0x00 $hhhex w");"ok"};

        Log 1, "Durchgang: $i";
Log 1, "prozent: $faktor";
#Warten bevor weiter hochgedimmt wird.
              fhem("sleep 10.00; set device on"); # device ist nur eine dummy Variable
}

}


Damit dimmt die Lampe zwar hoch und Fhem läuft auch ganz normal weiter, aber die 10 Sekunden zwischen jeder Dimmstufe werden nicht abgewartet.

Habt ihr Ideen, wie man das besser machen kann?

Beta-User

Versuch's mal mit zwei ";;" nach sleep ;) .

Aber der hintere Teil der Logik erschließt sich mir da noch nicht so recht, das "on" hat ja nichts mit einem Dimmwert zu tun, und eine richtige Schleife sehe ich auf die Schnelle auch nicht.

Tendenziell würde ich das eher über einen InternalTimer lösen, der jeweils weiterdimmt (also sich selbst wieder am Ende aufruft), bis der Zielwert erreicht ist, Aufrufeargument für diesen wäre der Gerätename; daraus kann dann der aktuelle Wert abgelesen werden (was dann ggf. auch einen mathematisch anderen Dimmverlauf ermöglicht, wenn erforderlich).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

tfriedrich85

Hallo,

doppeltes ;; hab ich versucht.
Hat aber nicht geholfen, dafür hab ich zusätzlich folgende Fehlermeldung:


2019.10.25 14:10:45 1: Durchgang: 99
2019.10.25 14:10:45 3: sleep 10;; set device on; : Last parameter must be quiet

Otto123

#3
was macht FHEM mit einem sleep? Es erzeugt ein at mit den Befehlen die hinter dem sleep stehen.

Also sleep 10; set device on erzeugt ein at welches in 10 sec das device on setzt. FHEM und der Rest der Logik läuft parallel weiter. Das ist ja der Sinn von einem nicht blockierenden sleep ;)

Wenn man das in einer Schleife macht (hab ich so nie getestet - also Theorie), werden 100 at's erzeugt die etwa zur gleichen Zeit das device 100 mal auf on schalten.  Die Schleife läuft maximal schnell weiter.

Ungetestet Idee: die Schleife mit normalen perl sleep  machen. Aber die Sub so aufrufen das sie nicht im FHEM Prozess läuft. Geht das mit system() ? Das wartete ja normal nicht.  :-\

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

Wernieman

Alternativ:
Anstelle eines sleep; FHEM-Befehl ein at +10 und sich selber aufrufen ...
- Bitte um Input für Output
- When there is a Shell, there is a Way
- Wann war Dein letztes Backup?

Wie man Fragen stellt: https://tty1.net/smart-questions_de.html

Beta-User

#5
Dass die Befehle am Ende "komisch aussehen", hatte ich ja auch bereits angemerkt, das erklärt aber nicht das "quiet".

Weil mir das auch nicht so lag, habe ich die betreffenden Routinen zwischenzeitlich wohl alle auf "AnalyzeCommandChain()" umgestellt...

Versuch's mal (in einer sinnvollen Schleife bzw. mit entsprechenden Selbstaufrufen oder einer berechneten Zeit und passendem Dimm-Level...) mit was in der Art:
AnalyzeCommandChain(undef, "sleep 10.00; set device on");



@Otto (bzw. auch Wernieman):
Es gibt schon Unterschiede zwischen einem (temporäten) at, einem "einfachen" und einem "benannten" sleep, zumindest, wenn ich das richtig verstanden habe (nur at landen in der statefile, oder? Und auch nur die sind im Raum "unbenannt"). Letztlich wird im laufenden Betrieb aber alles in InternalTimer-Aufrufen verwaltet, oder nicht?
Die spannenden Fragen sind eher, wie man so einen Timer wieder abbricht, und ob er einen Neustart überlebt; das ist jeweils unterschiedlich, und für Dinge, die nur im Hintergrund ablaufen und nicht gespeichert werden sollen, nehme ich zwischenzeitlich am liebsten direkt InternalTimer (bin da aber immer noch am lernen)...

Das ist für mich der direkteste Weg (alles andere macht bestimmte Berechnungen dann eben im Hintergrund), und ich spare mir das "Umverpacken".

Kleines Beispiel (indirekt gepeerte virtuelle Fensterkontakte, die nach einer bestimmten "offen"-Zeit der realen Fensterkontakte dann den/die zugehörigen RT's runterregeln):
sub myWinContactNotify ($$;$) {my ($window, $event, $timeout) = @_;my @virtuals = devspec2array("TYPE=CUL_HM:FILTER=model=VIRTUAL:FILTER=myRealFK=.*$window.*");foreach my $virtual (@virtuals) {my $myreals = AttrVal($virtual,"myRealFK","");
if ($event =~ /open|tilted/) {
$timeouteff = $timeout//AttrVal($virtual,"myTimeout",90);
my $checktime = gettimeofday()+$timeouteff;
InternalTimer($checktime,"myTimeoutWinContact",$virtual);
} else {
my @wcs = split(',',$myreals);
my $openwc = 0;
foreach my $wc (@wcs) {
$openwc++ if (ReadingsVal($wc,"state","closed") ne "closed");
}
CommandSet (undef,"$virtual geschlossen") unless ( $openwc );
}
}
}
sub myTimeoutWinContact ($) {
my $name = shift(@_);
#my $name = $hash{NAME};
return unless (ReadingsVal("Heizperiode","state","off") eq "on");
my $myreals = AttrVal($name,"myRealFK","");
my @wcs = split(',',$myreals);
my $openwc = 0;
foreach my $wc (@wcs) {
$openwc++ if (ReadingsVal($wc,"state","closed") ne "closed");
}
CommandSet (undef,"$name offen") if ( $openwc );
}
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

tfriedrich85

Hallo,

ich hab jetzt so einiges Versucht um das dimmen auf mehrere Minuten zu strecken. Aber bisher hat nichts funktioniert.
@Otto: eine Sleep mit einem anderen User auf Systemebene außerhalb von Fhem bringt den Raspi auch zum erliegen.

@Beta-User: Die Idee mit AnalyzeCommandChain ist gut, aber die Chain bekomme ich mit einer Mischung aus Fhem und Perl Befehlen nicht zum laufen.

AnalyzeCommandChain(undef, "sleep 10.00"; system("i2cset -y 1 0x5b 0x01 $hhhex w"););


Fehlermeldung:


syntax error at ./FHEM/99_myUtils.pm line 50, near ""sleep 10.00";" syntax error at ./FHEM/99_myUtils.pm line 50, near ";)"


Was mache ich da falsch.


Damian

Wie Otto schon geschrieben hat, du kannst nicht in einer Schleife mehrere Sleeps hintereinander absetzen, die auf sich warten. So etwas kannst du sinnvoll in einem rekursiven Aufruf machen. Eine Funktion ruft sich selbst in x-Sekunden auf.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Wernieman

Ich kann mich nur wiederholen:
ZitatAlternativ:
Anstelle eines sleep; FHEM-Befehl ein at +10 und sich selber aufrufen ...
- Bitte um Input für Output
- When there is a Shell, there is a Way
- Wann war Dein letztes Backup?

Wie man Fragen stellt: https://tty1.net/smart-questions_de.html

Beta-User

Zitat von: tfriedrich85 am 31 Oktober 2019, 21:07:34
Was mache ich da falsch.
Du solltest dich mal damit beschäftigen, welche Art Quotes welche Auswirkung hat... (also mit ' vs. "). Hier könntest du den zusammengebauten "system"-Aufruf in eine Variable packen, das macht den späteren AnalyzeCommandChain-Aufruf einfacher ;) .

Ansonsten stand auch schon in der ersten Antwort, dass man sowas besser durch rekursives Aufrufen löst, aber das war ja hier zuletzt erst mal gar nicht gefragt, oder?
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Damian

Bisher hat TE keine Lösung präsentiert, die den rekursiven Vorschlägen entspricht. Daher ist es müßig über irgendwelche Funktionsaufrufe zu diskutieren, wenn man nicht weiß in welchem Kontext sie benutzt werden.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

#11
Hier mal eine konkrete Lösung zum rumspielen, die rein in Perl mit Internaltimer läuft und ohne FHEM-Befehle wie sleep oder at auskommt. Der gesamte Code inkl. Eventhandler zum Anstoßen des Dimmens befindet sich an einer Stelle.

defmod dimmen DOIF subs {\
sub hoch {                                # Routine zum Hochdimmen\
my $wert=ReadingsVal("lampe","state",0);; # merke den aktuellen Zustand der Lampe\
if ($wert < 10)                          # wenn Wert kleiner zehn\
{\
   $wert++;;                               # erhöhe den Wert um eins\
   fhem_set("lampe $wert");;               # setze Lampe auf den um eins erhöhten Wert\
   set_Exec("wait",1,"hoch()");;           # Routine ruft sich selbst in einer Sekunde auf\
}\
}\
}\
\
{if ([FS] eq "on") {       # wenn Fernbedienung FS auf on gedrückt wird\
  del_Exec("wait");;        # lösche einen ggf. noch laufenden Timer\
  fhem_set("lampe 0");;    # Lampe mit Null initialisieren\
  hoch();;                  # Routine hoch zum Hochdimmen aufrufen\
}\
}\


Gespielt wird mit einem Dummy namens lampe.

Ergebnis: lampe wird im Sekundentakt von 0 auf 10 hochgedimmt, wenn man den Vorgang über ein Ereignis (hier Fernbedienung) auslöst. Das Gerüst lässt sich beliebig erweitern: Schrittweite, Zeitintervall, set-Befehl anpassen; auch das Herunterdimmen innerhalb des gleichen Moduls mit einer weiteren Perl-Funktion ist kein Problem.

Weitere Infos zu verwendeten Perlfunktionen (fhem_set, set_Exec, del_Exec), siehe: https://fhem.de/commandref_DE.html#DOIF_Perl_Modus
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

tfriedrich85

Hallo Damian,

das sieht super aus. Wird am Wochenende getestet. Rückmeldung folgt.

BG
Tobias