Wie ermittelt man am einfachsten die Anzahl eines bestimmten Status in einer structure ?
Beispiel:
In einer structure sind 10 Lampen. 2 sind an, 8 sind aus. Der aktuelle Status der structure ist "undefined".
Wie finde ich heraus (reading oder per 99_myUtils.pm) dass genau 2 Lampen angeschaltet sind ?
Etwas komplizierter wäre die Sache bei Dimmern (dim oder pct), da wäre die Anzahl der nicht ausgeschalteten (dim 0 bzw. pct 0) interessant.
z.Bsp. mit perl:
{ my $cnt=0;; map { $cnt++ if($_ ne "myStruct" && Value($_) eq "on") } split(" ",$defs{myStruct}{DEF});; $cnt }
Vielen Dank !! Das sprengt jetzt leider nahezu meine Perl Kentnisse :)
Ich versuche es mal zu dekonstruieren
- $cnt wird auf 0 gesetzt
- die Elemente der structure werden mit split(" ",$defs{myStruct}{DEF}) vereinzelt
- map kenne ich leider nicht
- $cnt wird hier erhöht, wenn der Wert "on" ist - $_ ne "myStruct" sagt mir wiederum nix
- $cnt wird als Ergebnis vermutlich zurückgeliefert
Ist das die Schreibweise direkt in FHEM (gerade wegen der ;; und Rückgabe ohne return(... ) ?
Vielleicht kannst du noch etwas Licht ins Dunkel bringen.
Zitat- map kenne ich leider nicht
perldoc -f map (https://lmgtfy.com/?q=perl+map)
Zitat$_ ne "myStruct" sagt mir wiederum nix
perldoc perlop (https://lmgtfy.com/?q=perl+ne)
ZitatIst das die Schreibweise direkt in FHEM (gerade wegen der ;; und Rückgabe ohne return(... ) ?
Was spricht gegen ausprobieren?
Zitat von: rudolfkoenig am 10 Oktober 2019, 22:33:21
Was spricht gegen ausprobieren?
eigentlich nix, aber ich bin Anwendungsentwickler (IBM 370 Assembler - Mainframe) und wüsste gerne vorher, was ich da eigentlich mache ;)
aber ok ... jetzt ist es eigentlich klar
- map geht die vereinzelten Elemente durch
- $_ ist das aktuelle Element
- $_ ne "myStruct" übergeht den struct_type
In der Befehlszeile von FHEM funktioniert der Befehl
{ my $cnt=0;; map { $cnt++ if($_ ne "Lights" && Value($_) eq "on") } split(" ",$defs{Lights}{DEF});; $cnt }
einwandfrei. Versuche ich aber ein userReading in der Form
attr Lights userReadings lightsOn { my $cnt=0; map { $cnt++ if($_ ne "Lights" && Value($_) eq "on") } split(" ",$defs{Lights}{DEF}); $cnt }
anzulegen, passiert gar nichts (kein Reading angelegt, keine Fehlermeldung....)
Wo ist mein Fehler ?
edit
wie so oft sitzt der Fehler vor dem Bildschirm. Man sollte erst mal ein Licht an oder ausschalten, dann hat man auch ein Reading :o
Freut mich, dass es klappt. Uebrigens es geht auch kuerzer:{ grep { $_ ne "Lights" && Value($_) eq "on" } split(" ",$defs{Lights}{DEF}) }
Wieder was gelernt ... ließe sich Light auch durch $name ersetzen ? Bin mir bei "Light" nicht sicher
Was spricht gegen ausprobieren? :)
Ja, sowohl $name wie $NAME.
Ich musste aber auch erst im Code nachschauen...
Danke :)
Ich hab' es jetzt folgendermaßen gelöst - die grep-Variante gefällt mit am Besten
attr Lights userReadings lightsOn { grep { $_ ne "$NAME" && Value($_) eq "on" } split(" ",$defs{$NAME}{DEF}) },\
devices { my $dvc="";; map { if($_ ne "$NAME" && Value($_) eq "on") {if ($dvc ne "") {$dvc=$dvc.","};; $dvc=$dvc.$_ } } split(" ",$defs{$NAME}{DEF});; $dvc}
Das zweite userReading "devices" enthält die Namen aller Lampen, die eingeschaltet sind mit Komma getrennt (verwende ich später in TABLETUI in Verbindung mit einem Label Widget und data-substitution).
Hierzu hätte ich noch 2 Fragen:
- der Code zur Generierung von $dvc sieht mir noch etwas holprig aus, geht das eleganter ?
- habe ich eine Möglichkeit im grep Teil eine Anweisung auszuführen (es fehlt ja die if-Abfrage von vorher) ?
Zitat- der Code zur Generierung von $dvc sieht mir noch etwas holprig aus, geht das eleganter ?
{ join(",",grep { $_ ne "$NAME" && Value($_) eq "on" } split(" ",$defs{$NAME}{DEF})) }
Zitathabe ich eine Möglichkeit im grep Teil eine Anweisung auszuführen (es fehlt ja die if-Abfrage von vorher) ?
Klar, {} ist perl Code, muss true/false zurueckliefern.
Prima :) Hat super funktioniert ...
Ich stelle fest, ich hab' immer noch Perl Defizite - selbst für einfachste Anwendungen :-[
Eine (hoffentlich) letzte Frage hab' ich noch. Bei meinen Batterien ermittle ich zusätzlich noch den niedrigsten Wert - vermutlich auch viel zu umständlich...
batteryPercent { my $pct=100; map { if($_ ne "$NAME" && ReadingsVal($_,"batteryPercent",100) < $pct) {$pct=ReadingsVal($_,"batteryPercent",100)} } split(" ",$defs{$NAME}{DEF}); $pct },
notFull { grep { $_ ne "$NAME" && ReadingsVal($_."batteryPercent",100) < 100 } split(" ",$defs{$NAME}{DEF}) },
devices { join(",",grep { $_ ne "$NAME" && ReadingsVal($_,"batteryPercent",100) < 100 } split(" ",$defs{$NAME}{DEF})) }
batteryPercent { minNum(100, map { $_ eq $NAME ? 100 : ReadingsVal($_,"batteryPercent",100) } split(" ",$defs{$NAME}{DEF}) ) }
Das sind aber genug Raetsel fuer heute :)
Danke :)
batteryPercent in einer Structure war keine gute Idee - ich hatte das Reading auch für MAX Devices verwendet um "ok" und "low" in 100 bzw. 10 umzusetzen :-\
Ich hab' es jetzt so gelöst
attr Batteries batteryPercent {if(ReadingsVal($NAME,"battery","ok") eq "low") {return 10;} elsif (ReadingsVal($NAME,"battery","low") eq "ok") {return 100;} else {return ReadingsNum($NAME,"battery",100)} },
batteryMin { minNum(100, map { $_ eq $NAME ? 100 : ReadingsNum($_,"batteryPercent",100) } split(" ",$defs{$NAME}{DEF}) ) },
notFull { grep { $_ ne "$NAME" && ReadingsNum($_,"batteryPercent",100) < 100 } split(" ",$defs{$NAME}{DEF}) },
devices { join(",",grep { $_ ne "$NAME" && ReadingsNum($_,"batteryPercent",100) < 100 } split(" ",$defs{$NAME}{DEF})) }
Der kleinste Wert wird mir jetzt in batteryMin bereitgestellt und da batteryPercent für alle Geräte in der structure ermittelt wird stimmen auch die Angaben bei den MAX Devices wieder 8)