Anzahl angeschaltete Lampen in einer structure

Begonnen von dt2510, 10 Oktober 2019, 21:51:25

Vorheriges Thema - Nächstes Thema

dt2510

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.

rudolfkoenig

z.Bsp. mit perl:
{ my $cnt=0;; map { $cnt++ if($_ ne "myStruct" && Value($_) eq "on") } split(" ",$defs{myStruct}{DEF});; $cnt }

dt2510

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.

rudolfkoenig

Zitat- map kenne ich leider nicht
perldoc -f map

Zitat$_ ne "myStruct" sagt mir wiederum nix
perldoc perlop


ZitatIst das die Schreibweise direkt in FHEM (gerade wegen der ;; und Rückgabe ohne return(... ) ?
Was spricht gegen ausprobieren?

dt2510

#4
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

dt2510

#5
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

rudolfkoenig

Freut mich, dass es klappt. Uebrigens es geht auch kuerzer:{ grep { $_ ne "Lights" && Value($_) eq "on" } split(" ",$defs{Lights}{DEF}) }

dt2510

Wieder was gelernt ... ließe sich Light auch durch $name ersetzen ? Bin mir bei "Light" nicht sicher

rudolfkoenig

Was spricht gegen ausprobieren? :)
Ja, sowohl $name wie $NAME.
Ich musste aber auch erst im Code nachschauen...


dt2510

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) ?

rudolfkoenig

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.

dt2510

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})) }

rudolfkoenig

batteryPercent { minNum(100, map { $_ eq $NAME ? 100 : ReadingsVal($_,"batteryPercent",100) } split(" ",$defs{$NAME}{DEF}) ) }Das sind aber genug Raetsel fuer heute :)