Schleife in DOIF/99_myUtils vorzeitig abbrechen

Begonnen von Superposchi, 28 März 2023, 09:05:38

Vorheriges Thema - Nächstes Thema

Superposchi

Hallo,
ich habe mir dank des Forums vor einiger Zeit einen Befehl geschrieben der meine Nachttischlampe in einen Wecker verwandelt in dem er das Licht stufenweise erhöht und zu weiß ändert. Zur Zeit nutze ich es als Schleife in meiner 99_myUtils.pm.

Leider passiert es immer mal wieder, dass ich aufstehe bevor die Schleife durchgelaufen ist und das Ausschalten der Nachttischlampe von der Schleife "überschrieben" wird. Ich hatte es schon innerhalb eines DOIF's probiert in der Hoffnung, dass die Schleife unterbrochen wird wenn ein anderer Zweig ausgewählt wird, aber das funktioniert auch nicht.

Der Coder im DOIF lautet:
([testdummy] eq "on")
     {
          my @sonne = ('A34472','90300A','F2A113','FFFFFF');
          my $counter = 10;
          for(my $i = 0; $i < @sonne; $i++) {
     fhem("sleep ".$counter."; set HUEDevice10 rgb ".$sonne[$i] .10);
     $counter = $counter + 10;
          }
     }
DOELSEIF ([testdummy] eq "off")
     (set HUEDevice10 rgb 000014)

Die Anzahl der Farben haben ich zu Testzwecken und der Übersichtichkeit reduziert.

Gibt es eine Möglichkeit die Schleife vorzeitig abzubrechen?
Gerne auch wieder in der 99_myUtils.pm.

rabehd

ZitatZur Zeit nutze ich es als Schleife in meiner 99_myUtils.pm.
Und das DOIF ebenfalls?
Auch funktionierende Lösungen kann man hinterfragen.

betateilchen

Prinzipiell könnte man die Schleife so verlassen (perl Grundlagen...)

          for(my $i = 0; $i < @sonne; $i++) {
            last if ([testdummy] eq "off")

Die Syntax in der Klammer wird so vermutlich nicht direkt funktionieren, aber mit der kranken Klammersetzung in einem DOIF werde ich mich in diesem Leben nicht mehr beschäftigen. Man kann da sicher auch einfach mit einem ReadingsVal() arbeiten, wenn man weiß, welches reading benötigt wird. Das geht aus dem Codeschnipsel leider nicht hervor.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Beta-User

...hat er überhaupt eine rekursive Schleife?!?
Eher nicht, es werden eine Runde benannte sleep definiert, oder?

=> "help cancel".
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Superposchi

@rabehd
Das DOIF war als Alternative gedacht, da es in der Commandref hei0t, dass ein Baum abgebrochen wird sobald ein anderer aktiv wird.
Scheint aber nicht ganz zu funktionieren wenn es sich um eine For-Schleife handelt, wird wohl offensichtich als EIN Befehl behandelt.

@betateilchen
Die Syntex bekomme ich raus, mir geht es um den Aufruf und die Positionierung in der Funktion.
last wäre also der Aufruf (das if dahinter die abgefragte Bedingung) und positioniert werden müsste es vor
fhem("sleep ".$counter."; set HUEDevice10 rgb ".$sonne[$i] .10); $counter = $counter + 10; }damit die Schleife verlassen und keine neue Farbe mehr gesetzt wird. Richtig verstanden?
Ich baue es auch gerne wieder in die myUitls ein, hatte es nur mit dem DOIF wegen der oben genannten Funktionsweise probiert und gehofft, dass die Schleife dadurch alleine schon unterbrochen wird.

Perl ist einfach nicht mein Ding, bekomme den Mist nicht in den Schädel rein.

@Beta-User
Eher nicht, es werden eine Runde benannte sleep definiert, oder?
=> "help cancel".
Wie meinst du das? In der originales For-Schleife wird nach einem Sleep einer Lampe ein rgb-Wert zugewiesen und das ca. 20 Mal (Hab es im Beispiel nur auf 4 Mal reduziert). Wie kann eine For-Schleife denn rekursiv sein? Das würde ja bedeuten, dass sie sich selbst aufruft und dadurch zu einer Endlosschleife wird.

Beta-User

Zitat von: Superposchi am 28 März 2023, 12:15:20Perl ist einfach nicht mein Ding, bekomme den Mist nicht in den Schädel rein.

@Beta-User
Eher nicht, es werden eine Runde benannte sleep definiert, oder?
=> "help cancel".
Wie meinst du das? In der originales For-Schleife wird nach einem Sleep einer Lampe ein rgb-Wert zugewiesen und das ca. 20 Mal (Hab es im Beispiel nur auf 4 Mal reduziert). Wie kann eine For-Schleife denn rekursiv sein? Das würde ja bedeuten, dass sie sich selbst aufruft und dadurch zu einer Endlosschleife wird.

Es liegt nicht an Perl, sondern an deiner Logik, aber du hast recht, die (fhem-) "sleep"-Anweisungen sind nicht benannt und können daher auch nicht per cancel wieder gelöscht werden.

Trotzdem: Dein Code legt _direkt_ eine Reihe von Timern an, die dann eben zur angegebenen Zeit ausgeführt werden. Du musst die benennen, wenn du sie abbrechen willst.

Oder eben wirklich eine "rekursive Schleife" bauen (ohne for), in der sich immer wieder derselbe Code selbst aufruft, bis eben das max. erreicht ist (oder eine andere Abbruchbedingung eingetreten ist, die intern geprüft werden muss).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

rabehd

ZitatDas DOIF war als Alternative gedacht, da es in der Commandref hei0t, dass ein Baum abgebrochen wird sobald ein anderer aktiv wird.
Beantwortet nicht meine Frage. Läuft Deine Funktion und das DOIF gleichzeitig?

Eine for-Schleife in einem DOIF-Zweig und dort ein sleep, dass finde ich schon was besonderes.

Setze doch mit dem Wecken einen Zähler, der hochzählt und die Veränderung des Zählers die Änderung des Lichtes auslöst. Das Ende kommt mit nicht mehr hochzählen. Also Ende des Zählens oder Abbrechen des Zählens.
Mit sowas mache ich Gewitter im Aquarium, wobei ich das heute schöner machen könnte als es noch ist.
Auch funktionierende Lösungen kann man hinterfragen.

Superposchi

@rabehd
Doch, es beantwortet deine Frage. Eine Alternative ist eine anders lautende Lösung für das gleiche Problem, welches die ursprüngliche Lösung ersetzt. So die Definition von Alternative.

Abgesehen davon scheinst du die Problematik gar nicht verstanden zu haben. Die For-Schleife ändert nach einem Auslöser in festgelegten Sleep-Abständen die Farbe des Lichts. Das erfolgt i  ca. 20 Schritte. Wenn ich aber beim 11 Schritt bereits aufstehe und damit die Anweisung zum Ausschalten der Lampe gebe, wird diese nach ablaufen des Sleep aber mit dem 12 Schritt wieder eingeschaltet. Die For-Schleife müsste also beim Aufstehen beendet werden.

@Beta-User
Das bedeutet anders als in allen Programmiersprachen die ich kenne wird in Fhem die For-Schleife nicht wiederholen nacheinander durchlaufen, sondern die Schleife erzeugt entsprechend viele Einzelanweisungen mit Timern, die aber ALLE parallel gestartet werden. Damit wäre das im eigentlichen Sinn gar keine Schleife.

Wie funktioniert das mit dem Benennen und killen? Hast du ein Stichwort wonach ich suchen muss.

Wernieman

Wie schon beschrieben, wird in der beschriebenen Schleife 10 Tricker definiert, welche dann das DImmen erledigen.

Um das zu lösen gibt es 3 Möglichkeiten
1. In eine Recursion  umwandeln, in der Du dann jeweils nachfragst nach Gültigkeit
2. "Names-Sleep" verwenden und dann bei bedarf Canceln (siehe Doku-Sleep
3. Anstatt slepp mit "at" und relativen Angaben Arbeiten, der Rest wie 2. (siehe Doku-At

Brauchst Du nähere Infos zu einem der Schritte?
Ich persönlich würde 1. nehmen, weil ich es logischer finde, aber wie immer gibt es mehrere Wege mit jeweils Vor/Nachteilen

Und Nein, es ist kein DOIF und/oder Perl-Problem, sondern ein Algorithmisches.
- 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: Superposchi am 28 März 2023, 13:49:07@Beta-User
Das bedeutet anders als in allen Programmiersprachen die ich kenne wird in Fhem die For-Schleife nicht wiederholen nacheinander durchlaufen, sondern die Schleife erzeugt entsprechend viele Einzelanweisungen mit Timern, die aber ALLE parallel gestartet werden. Damit wäre das im eigentlichen Sinn gar keine Schleife.

Wie funktioniert das mit dem Benennen und killen? Hast du ein Stichwort wonach ich suchen muss.
Wernieman hatte ja bereits NOCHMAL die Stichworte geliefert.

Ansonsten bist du auf dem Holzweg, was das mit der "for"-Schleife angeht. Die wird NATÜRLICH so oft durchlaufen, wie du das von einer ordentlichen Programmiersprache erwarten kannst, aber eben GLEICH, ohne jegliche Verzögerung. Alles andere würde auch FHEM blockieren...

Aber einmal mehr bin ich es echt leid, wenn gegebene Infos einfach ignoriert werden. "help cancel".
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Superposchi

Damit andere eine Hilfestellung haben, hier meine Lösung:
([testdummy] eq "on")
    {
          my @sonne = ('A34472','90300A','F2A113','FFFFFF');
          my $counter = 10;
          for(my $i = 0; $i < @sonne; $i++) {
        fhem("sleep ".$counter." LW_Marko".$i."; set HUEDevice10 rgb ".$sonne[$i] .10);
        $counter = $counter + 10;
          }
    }
DOELSEIF ([testdummy] eq "off")
    {for(my $i = 0; $i < 50; $i++) {fhem("cancel LW_Marko".$i);} fhem("set HUEDevice10 off")}