FHEM Forum

FHEM => Codeschnipsel => Thema gestartet von: rischbiter123 am 06 Juni 2020, 14:12:34

Titel: Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 06 Juni 2020, 14:12:34
Hier könnte man Anwendungsbeispiele für die Funktion countdownwatch des Moduls 60_Watches.pm sammeln.

Ich fange im nächsten Post auch gleich mal an mit einer Möglichkeit, den Wait-Timer von DOIF anzuzeigen.

LG

Andreas
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 06 Juni 2020, 14:33:21
DOIF Wait-Timer:

1. DOIF anlegen (Sollte vorhanden sein, hier nur drei Beispiele)
       Der Trigger und die sets sind in diesem Fall Dummys.

defmod Probe DOIF ([TestProbe:"on"]) (set Test2 300) DOELSEIF ([TestProbe:"off"]) (set Test2 100)
attr Probe do always
attr Probe wait 10:18


defmod Proben DOIF ([TestProben:"on"]) (set Test3 300)(set Test3 200)(set Test3 100) DOELSEIF ([TestProben:"off"]) (set Test3 250)(set Test3 150)(set Test3 50) DOELSEIF ([TestProben:"Duo"]) (set Test3 275)(set Test3 175)(set Test3 75)
attr Proben do always
attr Proben wait 20,25,28:27,24,26:24,29,22


defmod Testen DOIF ([TestTesten:"on"]) (set Test4 300)(set Test4 200) DOELSEIF ([TestTesten:"off"]) (set Test4 100)(set Test4 000)
attr Testen do always
attr Testen wait 32,36:30,39


2. Code für die 99_myUtils oder angehängte Datei aus Antwort #4 nutzen

sub TimerDo($$) {
my ($Az,$Ay) = @_; # $Az gleich Devicename
my $Bz = (AttrVal($Az,"wait",60)); # Auslesen des Wait-Attribut
$Az.="count"; # Namen der Uhr erstellen
# Erstellen der Commandsequenz
my @Dz = split(/ /,$Ay);
my $Dz = split(/ /,$Ay); # Anzahl der Sequenzen
my $Dy = @Dz[$Dz-2]; # Filtern des cmd
# Aufteilen der Commandschritte
my @Ez = split(/_/,$Dy);
my $Ez = split(/_/,$Dy);

if ($Ez == 2) # Nur ein Timer
{
my @Cz = split(/:/,$Bz); # Aufteilen in die Befehlssequenzen
my $Ey2 = $Ez[$Ez-1]; # cmd-Sequenz
my $Fy2 = $Cz[$Ey2-1]; # Inhalt des Waittimers
&Countdown($Az,$Fy2) # Stellen und starten der Uhr
}
else {
my $Ey1 = @Ez[$Ez-2]; # cmd-Nr
my $Ey2 = @Ez[$Ez-1]; # cmd-Sequenz

my @Cz = split(/:/,$Bz); # Aufteilen in die Befehlssequenzen
my $Cz = split(/:/,$Bz); # Anzahl Befehlssequenzen
my $ST1 = "";
my $Fy2 = "";
if ($Ey1 eq "no")
{
fhem ("set $Az reset")
}
else
{
my $ST1 = $Cz[($Ey1-1)];
my @Fy1 = split(/,/,$ST1); # Aufteilen in die einzelnen Wait-Argumente
$Fy2 = $Fy1[$Ey2-1];
&Countdown($Az,$Fy2) # Stellen und starten der Uhr
};
};
}

sub Countdown($$) { # Starten der Uhr
my ($Az1,$Zz) = @_; # $Az1 gleich Devicename, $Zz gleich Einstellzeit
fhem ("set $Az1 countDownInit $Zz; set $Az1 start");
}


3. Notify erstellen

defmod Watch_notify notify .*:wait_timer:.* {TimerDo($NAME,$EVENT);;}
Das erste .* kann man auch durch den Namen des DOIF ersetzen, wenn man - der Übersicht halber- mehrere notify nehmen möchte.

4. Anzeigeuhr erstellen, der Name muss den Namen des DOIF + count sein.

defmod Testencount Watches Digital
attr Testencount digitalColorBackground C7C5BD
attr Testencount digitalColorDigits 0A0FA8
attr Testencount digitalDisplayPattern countdownwatch


Wie immer sind Verbesserungsvorschläge herzlich willkommen.

LG

Andreas
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: tarum am 06 Juni 2020, 22:25:21
hallo,

gibt fehler in 99_myUtils

Bareword "count" not allowed while "strict subs" in use at ./FHEM/99_myUtils.pm line 485
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 07 Juni 2020, 11:09:34
Moin,
bei mir läuft es problemlos. Kann daher den Fehler leider nicht nachvollziehen.
LG
Andreas

Edit: Habe es jetzt bei mir noch mal gelöscht und aus dem Code neu eingefügt. Es wurde problemlos angenommen und auch im Logfile ist keine Fehlermeldung.
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 07 Juni 2020, 15:16:52
Habe jetzt das count im ersten Beitrag in Anführungszeichen gesetzt. Damit dürfte der Fehler bei denen, bei denen er aufgetaucht ist, hoffentlich bereinigt sein. Die geänderte myWatchUtils ist im Anhang.

LG

Andreas
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 07 Juni 2020, 15:32:43
On-for-Timer

Da on-for-timer (mWn) nicht direkt abgefragt werden kann, muß man es indirekt machen.

Statt z.B. das Device direkt per at zu setzen
defmod TestTimer2 at *15:05 set Decke on-for-timer 25

muss ein indirekter Aufruf mit z.B.
defmod TestTimer2 at *15:21 {Onfortimer("Decke",30);;}
erfolgen, wobei Decke in diesem Fall das zu schaltende Device ist.

Hier noch der Inhalt für die 99_myUtils:
sub Onfortimer($$) {
my ($Jz,$Lz) = @_; # $Jz gleich zu schaltendes Device, $Lz gleich Schaltzeit
fhem ("set $Jz on-for-timer $Lz");
$Jz.="count"; # Namen der Uhr erstellen
&Countdown($Jz,$Lz);
}

sub Countdown($$) { # Starten der Uhr
my ($Az1,$Zz) = @_; # $Az1 gleich Devicename, $Zz gleich Einstellzeit
fhem ("set $Az1 countDownInit $Zz; set $Az1 start");
}


Die sub Countdown kann gelöscht werden, wenn man das DOIF-Wait-Beispiel schon benutzt.

Eine Watch mit diesmal dem Namen des zu schaltenden Devices muss natürlich auch angelegt werden.

LG

Andreas
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 15 Juni 2020, 13:36:03
Moin,
ich habe das Ganze jetzt mal so erweitert, daß man mehrere -sich nicht überschneidende- mit nur einer, bzw. zwei, Watches anzeigen kann.
Dazu werden als erstes die beiden Watches definiert.
Für die Anzeige des Devicenamen:
defmod Devicecounter Watches Digital
attr Devicecounter digitalColorBackground C7C5BD
attr Devicecounter digitalColorDigits 0A0FA8
attr Devicecounter digitalDisplayPattern text
attr Devicecounter digitalSegmentType 16
attr Devicecounter digitalTextDigitNumber 8

Wichtig ist, daß das Attribut 'digitalTextDigitNumber' gesetzt ist, da die Länge des anzuzeigenden Namens damit verglichen wird, um die Laufschrift ein- bzw. auszuschalten.
Für die Laufzeit:
defmod Zeitcounter Watches Digital
attr Zeitcounter digitalColorBackground C7C5BD
attr Zeitcounter digitalColorDigits 0A0FA8
attr Zeitcounter digitalDisplayPattern countdownwatch

Dann bitte den Teil in den myUtils komplett austauschen, da ich auch im 'Hauptprogramm' Änderungen vorgenommen habe. (oder wieder die angehängte Datei nutzen)
sub TimerDo($$) {
my ($Az,$Ay) = @_; # $Az gleich Devicename
my $Bz = (AttrVal($Az,"wait",60)); # Auslesen des Wait-Attribut
my $Na1 = (AttrVal($Az,"MeinName","Device")); # Eigenname
# Bei langem Eigennamen die Laufschrift einschalten
&Laufschrift(Na1);
$Az.="count"; # Namen der Uhr erstellen
# Erstellen der Commandsequenz
my @Dz = split(/ /,$Ay);
my $Dz = split(/ /,$Ay); # Anzahl der Sequenzen
my $Dy = @Dz[$Dz-2]; # Filtern des cmd
# Aufteilen der Commandschritte
my @Ez = split(/_/,$Dy);
my $Ez = split(/_/,$Dy);

if ($Ez == 2) # Nur ein Timer
{
my @Cz = split(/:/,$Bz); # Aufteilen in die Befehlssequenzen
my $Ey2 = $Ez[$Ez-1]; # cmd-Sequenz
my $Fy2 = $Cz[$Ey2-1]; # Inhalt des Waittimers
&Countdown($Az,$Fy2,$Na1) # Stellen und starten der Uhr
}
else {
my $Ey1 = @Ez[$Ez-2]; # cmd-Nr
my $Ey2 = @Ez[$Ez-1]; # cmd-Sequenz

my @Cz = split(/:/,$Bz); # Aufteilen in die Befehlssequenzen
my $Cz = split(/:/,$Bz); # Anzahl Befehlssequenzen
my $ST1 = "";
my $Fy2 = "";
if ($Ey1 eq "no")
{
fhem ("set $Az reset");
fhem ("set Devicecounter displayTextDel")
}
else
{
my $ST1 = $Cz[($Ey1-1)];
my @Fy1 = split(/,/,$ST1); # Aufteilen in die einzelnen Wait-Argumente
$Fy2 = $Fy1[$Ey2-1];
&Countdown($Az,$Fy2,$Na1) # Stellen und starten der Uhr
};
};
}

sub Onfortimer($$) {
my ($Jz,$Lz) = @_; # $Jz gleich zu schaltendes Device, $Lz gleich Schaltzeit
my $Na1 = (AttrVal($Jz,"MeinName","Device")); # Eigenname
&Laufschrift(Na1);
fhem ("set $Jz on-for-timer $Lz");
$Jz.="count"; # Namen der Uhr erstellen
&Countdown($Jz,$Lz,$Na1);
}

sub Laufschrift($) {
my (Na4) = @_;
my $La1 = (AttrNum("Devicecounter","digitalTextDigitNumber",8));
my $NaD = length($Na4);
if ($NaD > $La1)
{
fhem ("set Devicecounter textTicker on")
}
else
{
fhem ("set Devicecounter textTicker off")
};
return;
}

sub Countdown($$$) { # Starten der Uhr
my ($Az1,$Zz,$Na2) = @_; # $Az1 gleich Devicename, $Zz gleich Einstellzeit, $Na2 gleich Eigenname
if ($Na2 eq "Device")
{
fhem ("set $Az1 countDownInit $Zz; set $Az1 start")
}
else
{
fhem ("set Devicecounter displayTextSet $Na2");
fhem ("set Zeitcounter countDownInit $Zz; set Zeitcounter start")
};
}

Danach werden zwei Notifys angelegt.
Eines, das auf die Wait-Timer reagiert:
defmod Watch_notify notify .*:wait_timer:.* {TimerDo($NAME,$EVENT);;}
Dann eines, das den Anzeigenamen löscht, wenn der Timer abgelaufen ist:
defmod Zeitcounter_notify_1 notify Zeitcounter:stopped set Devicecounter displayTextDel
On-for-Timer:
Am Aufruf ändert sich nichts. Allerdings muss beim zu schaltenden Device ein userattr mit dem Namen MeinName angelegt werden und mit dem Namen gefüllt werden, der im Devicecounter angezeigt werden soll.
DOIF-Wait
Auch hier muss, allerdings im Doif, das userattr angelegt werden.
Wird das Attribut nicht angelegt, funktioniert das Ganze wie vorher.

Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: WilhelmK am 05 August 2020, 07:41:44
coole Funktion-genau was ich gesucht habe.
Leider funktioniert es bei mir nicht mit readings, z.b.  wait 0,   ReadingsVal("gewaechshaustimer","Gewaechshausmin","")
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 05 August 2020, 14:09:52
Moin,
wait ist auch kein Reading sondern ein Attribut. Daher auch AttrVal.
LG
Andreas
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: WilhelmK am 05 August 2020, 14:55:52
Thx
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: WilhelmK am 19 Februar 2021, 14:27:42
Hi - habe bisher in FHEM schön mit der Countdownwatch gearbeitet und bin dabei das Ganze auf Tablet UI umzustellen.
Gibt es eine Möglichkeit die Anzeige in einem Reading auszulesen?

Habs schon selber gelöst - das Reading currtime wird ja erzeugt ;-)  - cooles Feature
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: Wzut am 20 Februar 2021, 07:32:08
Zitat von: rischbiter123 am 06 Juni 2020, 14:33:21
Wie immer sind Verbesserungsvorschläge herzlich willkommen.
da fällt mir spontan einiges ein :) Bsp :
my @Ez = split(/_/,$Dy);
my $Ez = split(/_/,$Dy);

Ist IMHO schwer lesbar und nachvollziehbar, u.a. auch weil die Variablen Namen nichts zum Inhalt sagen. Leichter wird u.a. zb so
my ($cmd, $nr) =  split(/_/, $line) ;
Wenn du magst schreibe ich dir den Abschnitt mal so um wie ich ihn einsetzen würde.
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 20 Februar 2021, 11:35:10
Moin Wzut,

gerne. Ich bin nicht sehr firm in Perl und war froh, etwas funktionierendes hinzubekommen, was ich mit anderen teilen wollte. Ich hatte auch gedacht, daß noch andere Anwendungsmöglichkeiten posten würden.

LG

Andreas
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: Wzut am 20 Februar 2021, 16:42:59
OK, und noch ein Tipp : Gib deine 99_myUtils Änderungen über den FHEMWEB Editor ein und schaue ins Log nach dem save.
Ausser den üblichen redefineds finden sich u.U. auch solche Dinge :
2021.02.20 16:36:21 1: PERL WARNING: Scalar value @Ez[...] better written as $Ez[...] at ./FHEM/99_myUtils.pm line 106.
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: Wzut am 21 Februar 2021, 17:58:34
sodele, wie versprochen :
1. Wenn du die sub bzw die subs in eine eigene 99_xxxx.pm packst musst du auch Init  auf diesen Namen anpassen -> sub myWatchUtils_Initialize
Ich finde das mit der eigenen Datei übertrieben, aber jeder nach seinem Geschmack.

2. Du hast in deiner zweiten Version noch mehr eigene Devicenamen "hardcoded" in der Datei. IMHO haben absolute Namen dort nichts verloren,
der User sollte immer die Freiheit haben seine Geräte nach seinem Geschmack zu benennen und umzubenennen ohne dafür jedesmal irgendwelche subs anpassen zu müssen. Daher ist der Weg mit dem userattr im DOIF ein Schritt in die richtige Richtung (ich habe jetzt Watches drin, aber auch noch das Fallback auf DOIF Name + count)

3. Da wir hier subs haben muss der Ausstieg aus der sub mit return erfolgen, egal ob mitendrin oder am Ende.
Stichwort return : Meine Devise ist sobald es in einer sub nichts mehr zu tun gibt, raus da. Egal ob Fehler oder irgendwelche Bedinungen erreicht sind.
Ein frühes return erspart u.U. umständliche if else Blöcke. Ein return mit Rückgabewert hat zudem noch den Vorteil einen Eintrag im Log File zu hinterlassen.

4. Prüfungen : Verlass dich nicht auf deine Werte, bei den Usern kann das ganz anders ausschauen. Daher niemals blind auf irgendwelche Werte zugreifen sondern immer prüfen ob der Wert auch Sinn macht. Ein Abbruch ggf. mit return hat zudem den Vorteil das der User keine kryptischen Perl Warnings im Log hat sondern von dir definierte Fehlermeldungen.

5. Kleinkram : keine Prototypen, wo immer es Sinn macht einfache Anführungszeichen statt doppelte, keine unützen Variablen für Zwischenwerte die genau nur einmal gebraucht werden, shift statt @_ usw. Frag einfach warum etwas so und nicht anders ist oder du deinen Code gar nicht mehr wiedererkennst :) 


sub TimerDo {

    my $doif_name  = shift;
    my $event      = shift;
    my @counts     = split(/:/, AttrVal($doif_name, 'wait', '')); # Aufteilen in die Befehlssequenzen
    my $w_device   = AttrVal($doif_name, 'Watches', $doif_name.'count'); # Name des Ziel (Watches) Device

    return "no wait found in DOIF $doif_name" if (!@counts); # keine vorhanden
    return "no valid Watches device found, check attribute Watches in $doif_name"
        if (!exists($defs{$w_device}) || ($defs{$w_device}->{TYPE} ne 'Watches') );

    if ($event !~ m{ cmd_ }xms ) { # z.B. bei no timer ist kein cmd_x vorhanden
        CommandSet(undef, $w_device.' reset');
        return;
    }

    # Erstellen der Commandsequenz
    my @vals = split(/ /,$event); # Bsp -> wait_timer: Datum Uhrzeit cmd_x <Auslöser des notify>

    # my $cmd = $vals[int(@vals)-2];  wir brauchen das vorletzte Element -> cmd_x
    # alternativ : ohne rechnen direkt $vals[3] verwenden ? kürzere Events sollte es jetzt nicht mehr geben
    # my $cmd = $vals[3]

    my (undef, $nr, $sub_nr) = split(/_/, $vals[3]); # Bsp : cmd_2 , cmd_1_2

    $nr--; # Element Nr der waits ist immer um eins kleiner als cmd_x;
   
    return Countdown($w_device, (defined($counts[$nr])) ? $counts[$nr] : -1)  if (!$sub_nr); # Nur ein Timer   
 
    $sub_nr--; # ist auch immer um eins kleiner;

    my @count_arr = split(/,/, $counts[$nr]);
    return Countdown($w_device, (defined($count_arr[$sub_nr])) ? $count_arr[$sub_nr] : -1);
}

sub Countdown { # Starten der Uhr
    my $device = shift;
    my $count  = shift // return "invalid count"; # falls $count undef

    return "invalid count" if ($count < 0);
    my $ret = CommandSet(undef, "$device countDownInit $count");  # stellen der Uhr
    return $ret if ($ret); # da ging leider etwas schief
    return CommandSet(undef, $device.' start');  # starten der Uhr
}


Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 21 Februar 2021, 18:42:54
Moin Wzut,

danke für die Arbeit. Soweit scheine ich es zu verstehen, auch Dank Deiner Kommentare im Programm. Aber daß ist auch das was ich meinte, wenn man nur ab und an mal was in Perl macht, ist man froh, wenn es für einen funktioniert. Aber ich werde es mir auf alle Fälle noch genauer zu Gemüte führen.

Ein alter Hund (54) kann zwar noch neue Tricks lernen, aber bestehende zu modifizieren (z.B. shift statt @) fällt schwer, wenn man sich nicht intensiv damit befasst.

Bei mir ist es halt so, ich überlege, was eventuell machbar ist (früher mal Basic gelernt), versuche es dann umzusetzen und wenn es klappt mit anderen zu teilen.
Wenn dann erfahrene (Hobby)Programmierer wie Du das noch verbessern oder verkürzen können oder wollen, umso schöner. Ich freue mich immer, wenn jemand anderes mit meinen Codeschnipseln etwas anfangen kann.

LG

Andreas
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: Wzut am 21 Februar 2021, 18:58:33
Zitat von: rischbiter123 am 21 Februar 2021, 18:42:54
Ein alter Hund (54) kann zwar noch neue Tricks lernen, aber bestehende zu modifizieren (z.B. shift statt @) fällt schwer
falsch , der Spruch lautet "einem alten Hund bringt man keinen Kunststückchen mehr bei"
Zumindest habe ich (60) das so immer zu meinem Chef gesagt :) und ja am Anfang muß man sich etwas umgewöhnen, aber man muß jetzt auch nicht mit Gewalt durch sämtlichen alten Code, das macht man so nebenbei wenn man ihn eh wegen irgend etwas anfassen muß.
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: rischbiter123 am 21 Februar 2021, 19:06:31
Ich weis, wie es richtig heißt, aber dann hättest Du vermutlich geschrieben, daß das falsch ist und auch ein alter Hund noch neues lernen kann.  ;)

Andreas
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: Wzut am 22 Februar 2021, 07:55:55
ich habe noch etwas gespielt und da ich keine Ahnung von DOIF habe ist mir z.Z. unklar ob man den Reset der Uhr wirklich brauch :
if ($event !~ m{ cmd_ }xms ) { # z.B. bei no timer ist kein cmd_x vorhanden
        CommandSet(undef, $w_device.' reset');
        return;
    }

oder einfach nur return if ($event !~ m{ cmd_ }xms );
Die Uhr läuft doch eh selbständig bis Null runter und bleibt da automatisch stehen oder gibt es eine Variante bei der DOIF seinen eigenen wait Timer vorzeitig abbricht ?     

Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: megadodopublications am 15 Februar 2022, 19:28:12
** sorry gehört als Frage nicht hierher, ich lösche erstmal und stelle die Frage an anderer Stelle.
Titel: Antw:Anwendungsbeispiele für die countdownwatch
Beitrag von: Damian am 15 Februar 2022, 20:52:37
In dem Zusammenhang einfacher Countdown mit Visualisierung:

defmod di_countdown DOIF start {$_sec=10;;set_Reading("count",$_sec,1);;set_Exec("countdown",1,'set_Reading ("count",$_sec-1-$count,1)','$count<$_sec')}
attr di_countdown uiState {package ui_Table}\
ring([$SELF:count],0,10,0,120,"Seconds",150,undef,0)


Animation siehe Anhang