FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: ocbraun am 22 Dezember 2020, 19:55:47

Titel: Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: ocbraun am 22 Dezember 2020, 19:55:47
Hallo,

bitte nehmt es mir nicht übel... das ist hier bestimmt eine Anfängerfrage wie sie im Buche steht..... vielleicht möchte mir jemand helfen. Wäre stark !


Ich möchte für meine PhilipsHue- Beleuchtung eine Farbwechselroutine erstellen und habe in eine "99_xy.pm" folgende Subroutine ausgelagert.


##############################################
# $Id: myUtilsTemplate.pm 7570 2015-01-14 18:31:44Z rudolfkoenig $
#
# Save this file as 99_myUtils.pm, and create your own functions in the new
# file. They are then available in every Perl expression.

package main;

use strict;
use warnings;
use POSIX;

sub
LightUtils_Initialize()
{
  my ($hash) = @_;
}

# Enter you functions below _this_ line.

sub startColorEffect() {


## green   
    my $hueGreen = 23665;
    my $satGreen = 245;
    my $briGreen = 215;
## DeepBlue
my $hueBlue = 47330;   
my $satBlue = 254;
    my $briBlue = 254;
## BigRed
my $hueRed = 0;
    my $satRed = 254;
    my $briRed = 254;
## Yellow
my $hueYellow = 9102;
    my $satYellow = 254;
    my $briYellow = 254;

    my $sleep = 10;
   
fhem("set SZCandleE14 hue $hueGreen : sat $satGreen : bri $briGreen; sleep $sleep; set SZCandleE14 hue $hueBlue : sat $satBlue : bri $briBlue; sleep $sleep; set SZCandleE14 hue $hueRed : sat $satRed : bri $briRed; sleep $sleep; set SZCandleE14 hue $hueYellow : sat $satYellow : bri $briYellow");

 
}

1;


Die Subroutine starte ich über eine Fernbedienung und das funktioniert auch soweit. Als Wartezeit / Umschalter für die einzelnen Farben verwende ich "sleep ()".

Jetzt möchte ich den Anweisungsblock an FEHM "endlos" durchlaufen lassen, also am Ende immer wieder von Vorne beginnen lassen, bis ich dies manuell mit einem Befehl (Dummy-Schalter; Fernbedienung) ausschalte.

Wie kann / muss ich so etwas realisieren ?  Ich habe es schon so probiert:



[....]

my $sleep = 10;
   
while (1) {

fhem("set SZCandleE14 hue $hueGreen : sat $satGreen : bri $briGreen; sleep $sleep; set SZCandleE14 hue $hueBlue : sat $satBlue : bri $briBlue; sleep $sleep; set SZCandleE14 hue $hueRed : sat $satRed : bri $briRed; sleep $sleep; set SZCandleE14 hue $hueYellow : sat $satYellow : bri $briYellow");

}

[...]




dabei ist nichts passiert, außer das FHEM eingefroren ist....  (bis zum Steckerziehen)

Wie kann man dies realisieren?



Viele herzliche Weihnachtsgrüße

Chris

Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: amenomade am 23 Dezember 2020, 00:51:38
Der sleep Befehl macht nichts anderes, als ein internes at anzulegen, um das nächste Kommando du verzögern. Dann macht fhem weiter.

Wenn Du dein while(1) schreibst, macht er ohne Ende und so schnell wie er kann das ganze wieder (Befehl, und at anlegen). Das heisst, er legt innerhalb von Sekunden Tausende von ATs, und zwar ohne Ende bis zum Absturz

Statt while(1) würde ich ein wiederholendes AT anlegen (at +* 00:00:30 ...), der deine Befehlskette wiederholt. Etwas in der Art:
fhem("set SZCandleE14 hue $hueGreen : sat $satGreen : bri $briGreen; sleep $sleep; set SZCandleE14 hue $hueBlue : sat $satBlue : bri $briBlue; sleep $sleep; set SZCandleE14 hue $hueRed : sat $satRed : bri $briRed; sleep $sleep; set SZCandleE14 hue $hueYellow : sat $satYellow : bri $briYellow");
fhem("define wiederholung at +* 00:00:30 set SZCandleE14 hue $hueGreen : sat $satGreen...");


Oder Du löst das eine Ebene höher beim Aufruf von der Perl Routine (auch mit AT oder mit DOIF z.B.)
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: ocbraun am 23 Dezember 2020, 17:02:24
Danke für die Antwort,

ich weiß nur nicht, ob dies so funktionieren kann.

Die Anforderung lautet: 

1. Manuell einschalten --> Dummy-Schalter oder Fernbedienung welches die SubRoutine aufruft

2. Farbwechsler: Nach dem einschalten leuchtet grün; nach einer Zeitspanne X leuchtet Blau, dann rot und dann gelb.... wenn alle Farben durch sind, soll es wieder bei rot beginnen und soweiter..... ---> [grün -- 2min -- blau -- 2min -- rot -- 2min --gelb --2min (Sprung auf Anfang) --  grün-- usw...]

3. Das soll so lange durchlaufen, bis man wieder mit einem manuellen Tasterdruck die SubRoutine "abschaltet"..




Ich möchte also erreichen, dass


fhem("set SZCandleE14 hue $hueGreen : sat $satGreen : bri $briGreen; sleep $sleep; set SZCandleE14 hue $hueBlue : sat $satBlue : bri $briBlue; sleep $sleep; set SZCandleE14 hue $hueRed : sat $satRed : bri $briRed; sleep $sleep; set SZCandleE14 hue $hueYellow : sat $satYellow : bri $briYellow");


wenn es abgearbeitet ist wieder von vorne startet und dies so lange macht, bis ich es ausschalte....


Gibt es einen besseren Befehl als das sleep() ?


viele Grüße

Chris



Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Beta-User am 23 Dezember 2020, 18:04:16
Wenn du auf die Perl-Ebene runtergehst, rufst du einfach über einen InternalTimer die Funktion wieder auf. Hier ist es aber uU. schwieriger, weil da ja schon viele (FHEM-)sleep drin sind.
Da könntest du am Ende auch ein "trigger"-Kommando absetzen, das dann (d)ein norify wieder von vorne auslöst. Dann müßtest du ggf. im Code dann zu Beginn schauen, ob die 2. Eingangsbedingung noch gegeben ist (der "Schalter").

Das while(1) ist in jedem Fall Käse, das sollte dann einfach nur einmal durchlaufen beendet sein, bis es von woanders her wieder aufgerufen wird!
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: amenomade am 23 Dezember 2020, 18:05:45
Wie gesagt: ein at +* 00:00:30 definieren (oder InternalTimer benutzen), der den Befehl beliebig mit 30 Sek Abstand wiederholt

Oder dein dummy mit einem DOIF abfragen, und die Attribute wait und repeatsame des DOIFs benutzen.

define schalter dummy
attr schalter setList on off
define di_repeat DOIF ([dummy] eq "on") {meineperlroutine()} DOELSE
attr di_repeat repeatcmd 30


EDIT: noch besser ohne sleep und ohne dummy
define di_repeat DOIF ([$SELF:schalter] eq "on") \
   (set SZCandleE14 hue [$SELF:hueGreen] : sat [$SELF:satGreen] : bri [$SELF:briGreen]) \
   (set SZCandleE14 hue [$SELF:hueBlue] : sat [$SELF:satBlue] : bri [$SELF:briBlue]) \
   (set SZCandleE14 hue [$SELF:hueRed] : sat [$SELF:satRed] : bri [$SELF:briRed]) \
DOELSE
setreading di_repeat schalter off
attr di_repeat setList schalter:on,off satGreen briGreen hueGreen satBlue briBlue hueBlue satRed briRed hueRed
attr di_repeat readingList schalter satGreen briGreen hueGreen satBlue briBlue hueBlue satRed briRed hueRed
setreading di_repeat hueGreen 23665
setreading di_repeat satGreen 245
setreading di_repeat briGreen 215
setreading di_repeat hueBlue 47330 
setreading di_repeat satBlue 254
setreading di_repeat briBlue 254
setreading di_repeat hueRed 0
setreading di_repeat satRed 254
setreading di_repeat briRed 254
attr di_repeat wait 0,10,10
attr di_repeat repeatcmd 10:0


2020-12-23 18:33:59 DOIF di_repeat schalter: on
2020-12-23 18:33:59 DOIF di_repeat e_di_repeat_schalter: on
2020-12-23 18:33:59 DOIF di_repeat cmd: 1.1
2020-12-23 18:34:09 DOIF di_repeat cmd: 1.2
2020-12-23 18:34:19 DOIF di_repeat cmd: 1.3
2020-12-23 18:34:29 DOIF di_repeat cmd: 1.1
2020-12-23 18:34:39 DOIF di_repeat cmd: 1.2
2020-12-23 18:34:49 DOIF di_repeat cmd: 1.3
2020-12-23 18:34:59 DOIF di_repeat cmd: 1.1
2020-12-23 18:35:09 DOIF di_repeat cmd: 1.2
2020-12-23 18:35:19 DOIF di_repeat cmd: 1.3
2020-12-23 18:35:29 DOIF di_repeat cmd: 1.1
2020-12-23 18:35:39 DOIF di_repeat cmd: 1.2
2020-12-23 18:35:49 DOIF di_repeat cmd: 1.3
2020-12-23 18:35:59 DOIF di_repeat cmd: 1.1
2020-12-23 18:36:09 DOIF di_repeat cmd: 1.2
2020-12-23 18:36:13 DOIF di_repeat schalter: off
2020-12-23 18:36:13 DOIF di_repeat e_di_repeat_schalter: off
2020-12-23 18:36:13 DOIF di_repeat cmd: 2

EDIT: Korrektur (= Zeichen in setreadings)
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: ocbraun am 23 Dezember 2020, 18:09:51
Wenn ich den Befehl alle 30sec mit einem at wiederhole.... bricht es dann nicht an der Stelle ab und beginnt von vorne.... kommt es dann überhaupt zum durchlauf aller Farben?

Sry, dass ich nerve :-)

Wie würde es mit einem InternalTimer aussehen?

Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Beta-User am 23 Dezember 2020, 18:46:31
Mit einem InternalTimer würde ich auf die sleep verzichten und dann nur z.B. das erste mal aus einem notify raus eben mit einem "Durchlaufstatus" 0 starten.

Bei einem "rekursiven Aufruf" kannst du dann jedes mal 1 addieren und dann den passenden Befehl wählen, bis du eben durch bist und wieder bei 0 anfängst.

Ohne Zusammenhang ist das immer schwierig... Beispiel für unendlich alle 30 Sekunden:
sub meineperlroutine {
my $loopnumber = shift // 0;

machirgendwas...
$loopnumber = $loopnumber == 20 ? 0: $loopnumber+1; return InternalTimer(gettimeofday()+30,"meineperlroutine",$loopnumber);
}
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: ocbraun am 23 Dezember 2020, 18:52:14
Vielen Dank für die vielen Antworten und die Lösungsvorschläge !!! Super !

Ich muss das in Ruhe durchprobieren und das kann bis nach die Feiertage dauern :-)

Ich wünsche Euch eine schönes Weihnachtsfest ...

Grüße Chris
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: amenomade am 23 Dezember 2020, 19:05:50
Zitat von: ocbraun am 23 Dezember 2020, 18:52:14
Vielen Dank für die vielen Antworten und die Lösungsvorschläge !!! Super !

Ich muss das in Ruhe durchprobieren und das kann bis nach die Feiertage dauern :-)

Ich wünsche Euch eine schönes Weihnachtsfest ...

Grüße Chris
Das mit InternalTimer oder at ist eine gute Übung, aber ich habe dir eine fertige und elegante  Lösung mit einem einzigen DOIF geliefert ;) Ok, nicht jeder mag DOIF :D (ich aber schon! Für solche Einsätze ist es mächtig)

Jedenfalls dir auch frohe Weichnachten.
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Wernieman am 23 Dezember 2020, 19:22:19
Du könntest auch mit einem Dummy arbeiten, wo praktisch der letzte Stand drin steht.

Dann mit einem at den Dummy weiterschalten, aktuelle Farbe setzen und den at neu definieren. Praktisch wie Beta-User es auf Perl Ebene geschrieben hat, nur eben eine Ebene "höher". Zum Ausschalten einfach den at "abschießen"

OT:
Das liebe ich bei FHEM, ist wie bei einem Guten Betriebssystem: Viele Wege führen zum Ziel
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Beta-User am 23 Dezember 2020, 19:45:09
Falls mit dummy: Each() (aus fhem.pl)

Was DOIF angeht, habe ich bekennendermaßen keinen Schimmer von der Syntax und jedesmal, wenn ich es damit versuche, falle ich auf die Nase >:( . Von daher werde ich doch keinen alleine lassen, der nach einer Perl-only-Lösung (mit fhem.pl-Bordmitteln) fragt ;) .
Am Ende ist DOIF auch nur ein wrapper für Perl-Funktionen und selbst der Entwickler empfiehlt, für komplexe Probleme den Perl-Modus zu nutzen. Das kann man auch direkter haben ;) .
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: amenomade am 23 Dezember 2020, 19:52:14
Zitat von: Beta-User am 23 Dezember 2020, 19:45:09
Falls mit dummy: Each() (aus fhem.pl)

Was DOIF angeht, habe ich bekennendermaßen keinen Schimmer von der Syntax und jedesmal, wenn ich es damit versuche, falle ich auf die Nase >:( . Von daher werde ich doch keinen alleine lassen, der nach einer Perl-only-Lösung (mit fhem.pl-Bordmitteln) fragt ;) .
Am Ende ist DOIF auch nur ein wrapper für Perl-Funktionen und selbst der Entwickler empfiehlt, für komplexe Probleme den Perl-Modus zu nutzen. Das kann man auch direkter haben ;) .

Jaja... ich weiss ;)
Ist DOIF kein Bordmittel für dich?
Zitatwenn ich es damit versuche, falle ich auf die Nase >:(
Doku lesen!  ;D :D 8)
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Beta-User am 23 Dezember 2020, 20:11:22
Nein, DOIF ist kein _fhem.pl_-Bordmittel, und nach meinem Dafürhalten nicht mal "Bordmittel" in einem etwas weiteren Sinne; da gehören nach meiner Auffassung nur die Dinge dazu, die in fhem.pl vercodet sind und ein paar "Core"-Module, die Rudi betreut (v.a. at + notify, watchdog).

DOIF hat eine spezielle Syntax, und ich habe ehrlich keine Lust, mich durch eine unübersichtliche Vielzahl von Beispielen zu wühlen, nur um am Ende festzustellen, dass das knapp neben dem ist, was ich eigentlich brauche... (oder ich mal wieder die Syntax missverstanden habe). Kurz: Ich persönlich finde diese Doku unleserlich :P . (Und ich glaube nicht, dass ich dafür bekannt bin, notorischer _Adressat_ von RTFM-"Anregungen" zu sein... ::) )

Aber jeder wie er kann und mag. ;D
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: amenomade am 23 Dezember 2020, 20:13:10
Na dann... bleibt nur übrig, dem TE eine fertige Lösung mit 'Bordmittel' zu liefern ;) Bin mal gespannt, wie es aussieht ;)
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Wernieman am 23 Dezember 2020, 20:17:08
Auch wenn es jetzt eine Diskussion über DOIF wird, kann Beta-User nur Zustimmen.

DOIF macht es in "meinen" Augen komplizierter. Es sieht mir "zu sehr" nach einer "Einzeilerlösung" aus. Auch muß man die Zusätze lernen ... da ist mir "klassisches" Fhem lieber ...

FHEM ist doch eigentlich ein "Event Basiertes" System. Dieses wird mit jedem notivy/at sehr klar abstrahiert. Dieses verstehe ich bei DOIF nicht ... aber wie schon gesagt: Ist "meine persönliche Meinung" und sagt nichts über DOIF aus.

Wie ich oben schrieb: Es ist doch toll, wenn es mehrere Lösungswege gibt ... ;o)

Edit:
Nachtrag:
Es ist besser, wenn der TE SEINE Lösung selber ermittelt. Dann kann er lernen und braucht beim nächsten mal nicht Fragen ...
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Beta-User am 23 Dezember 2020, 20:18:06
Zitat von: amenomade am 23 Dezember 2020, 20:13:10
Na dann... bleibt nur übrig, dem TE eine fertige Lösung mit 'Bordmittel' zu liefern ;)
Jein.

Der TE wollte Hilfe zur Selbsthilfe, oder ;) ?

Das war die vorrangige Aufgabe des Forums, oder habe ich die Doku missverstanden :) ?

(Sonst fange ich noch an, Farbangaben in Hashes umzuwandeln und so ::) ).
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: amenomade am 23 Dezember 2020, 20:22:53
Zitat von: Beta-User am 23 Dezember 2020, 20:18:06
Jein.

Der TE wollte Hilfe zur Selbsthilfe, oder ;) ?

Das war die vorrangige Aufgabe des Forums, oder habe ich die Doku missverstanden :) ?

(Sonst fange ich noch an, Farbangaben in Hashes umzuwandeln und so ::) ).

Ja, Hilfe zur Selbshilfe hab ich schon geliefert. Aber es ist schwierig für diesen Anwendungsfall es umzusetzen. Die DOIF Lösung finde ich besser (aber ok, das ist meine persönliche Meinung - und somit bin ich weg von diesem Thread :) zumindest was DOIF Vorteile/Nachteile angeht)
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Beta-User am 23 Dezember 2020, 20:33:53
Na ja, "eigentlich" sollte man dann bei der InternalTimer-Lösung auch noch eventuell vorhandene "alte Timer" löschen, wenn sich rekursive Aufrufe und ein "getriggerter" Aufruf in die Quere kommen könnten.
Aber ansonsten muss man halt einfach nur verstanden haben, wie InternalTimer "tickt"; und dazu muss man eigentlich nur mal in den Quelltext in fhem.pl schauen und da mal nach den Funktionen für sleep und cancel fahnden ;) .
(Hilft ggf. auch für das Verständnis von DOIF, btw. ;) )
Titel: Antw:Subroutine / Perl: Schleife bis zum manuellen Ausschalten.
Beitrag von: Damian am 23 Dezember 2020, 21:20:03
Ich würde es mit einem Einzeiler machen:

defmod di_rgb DOIF {["button:on"];;@{$_rgb}=("FF0000","00FF00","FFFF00","0000FF");;set_Exec("timer",120,'fhem_set"lamp rgb  ".$_rgb[$count%4]','ReadingsVal("button","state","") eq "on"')}

Die Farben kannst du im RGB-Array definieren, button ist dein Schalter, lamp ist deine Lampe, mehr Boardmittel braucht man dafür nicht ;)

Doku dazu mit Beispielen siehe: https://fhem.de/commandref_DE.html#DOIF_set_Exec