Hallo,
ich lese die Spg. von 4 Lipo-Zellen aus:
cellVoltage1 3.395
cellVoltage2 3.394
cellVoltage3 3.395
cellVoltage4 3.396
Nun würde ich gerne die maximale Spannungsdifferenz ermitteln.
Klar, es muss der größte Wert - kleinster Wert = Differenz gerechnet werden.
In Excel ist das kein Ding, da kann man das ja so: =MAX(E6:E9)-MIN(E6:E9) ziemlich einfach umsetzen.
Kann mir bitte jemand dabei helfen, wie ich das in FHEM als Reading hinbekomme!?
Vielen Dank.
Grüße
Vorweg: es geht sicher auch anders/einfacher.
Mein Lösungsvorschlag:
Alles Werte in ein Array, dann sortieren und dann sollte im ersten und im letzten Element des Arrays der größte und der kleinste Wert drin sein.
Gruß
Dan
OK, ich habe schon befürchtet, das es nicht so ganz einfach ist.
Aber mit "Array" kann ich (auch) absolut nichts anfangen.
Kannst du mir da etwas auf die Sprünge helfen?
Danke.
Grüße
Ich finde das eigentlich recht einfach! ;D
Na dann mal langsam: Woher kommen denn Deine ursprünglichen Daten bzw. wo findest Du diese in FHEM wieder?
Gruß
Dan
Die Daten werden durch ein Pyhton-Skript an FHEM über das Modul 70_GenericSmartBMS.pm geliefert.
List ergibt folgendes:
Internals:
DEF 192.168.178.153 9998 15 1
FUUID 61f9048f-f33f-563c-3335-6af24ec1e5b8d6cb
Host 192.168.178.153
Interval 15
Invalid -1
NAME BatteryPack1
NR 14
Port 9998
STATE Online
TYPE GenericSmartBMS
Timeout 1
READINGS:
2022-02-02 15:56:40 batteryBalance 0
2022-02-02 15:56:40 batteryCurrent 11.25
2022-02-02 15:56:40 batterySoC 93
2022-02-02 15:56:40 batteryVoltage 13.61
2022-02-02 15:56:40 cellVoltage1 3.403
2022-02-02 15:56:40 cellVoltage2 3.4
2022-02-02 15:56:40 cellVoltage3 3.404
2022-02-02 15:56:40 cellVoltage4 3.407
2022-02-02 15:56:40 cellVoltage5 65.174
2022-02-02 15:56:40 cellVoltage6 0
2022-02-02 15:56:40 cellVoltage7 0
2022-02-02 15:56:40 state Online
2022-02-02 15:56:40 temp1 13.1
2022-02-02 15:56:40 temp2 11.6
Attributes:
cellVoltage1 - 4 sind die relevanten Werte, aus denen die Differenz errechnet werden soll.
Okay! Und wo willst du den Differenzwert haben?
Mit einem userReading sollte es sehr gut machbar sein.
z.B. (ungetestet):
attr BatteryPack1 userReadings voltagediff:cellVoltage.* {my @ar=(ReadingsNum($NAME,"cellVoltage1",0),ReadingsNum($NAME,"cellVoltage2",0),ReadingsNum($NAME,"cellVoltage3",0),ReadingsNum($NAME,"cellVoltage4",0)); sort @ar; my $min = $ar[0]; my $max = $ar[-1]; return $max - $min;}
Gruß
Dan
Ja, genau als Userreading in dem selben Device habe ich mir das vorgestellt.
Deinen Code habe ich gerade in der Befehlszeile eingegeben.
Aber ich bekomme folgende Fehlermeldungen:
Unknown command sort, try help.
Unknown command my, try help.
Unknown command my, try help.
Unknown command return, try help.
Unknown command }, try help.
NACHTRAG: Es hat wohl am Ende eine } gefehlt.
War wohl mein Fehler! :-X
Es scheint sogar jetzt zu funktionieren.
Werde das Reading mal beobachten ob der Wert auch stimmt. :-)
Vielen Dank nochmal für die Hilfe.
Melde mich später nochmal.
Grüße
READINGS:
2022-02-02 16:50:14 batteryBalance 0
2022-02-02 16:50:14 batteryCurrent 6.66
2022-02-02 16:50:14 batterySoC 98
2022-02-02 16:50:14 batteryVoltage 13.98
2022-02-02 16:50:14 cellVoltage1 3.497
2022-02-02 16:50:14 cellVoltage2 3.491
2022-02-02 16:50:14 cellVoltage3 3.494
2022-02-02 16:50:14 cellVoltage4 3.499
2022-02-02 16:50:14 cellVoltage5 64.807
2022-02-02 16:50:14 cellVoltage6 0
2022-02-02 16:50:14 cellVoltage7 0
2022-02-02 16:50:29 state Offline
2022-02-02 16:50:14 temp1 12.7
2022-02-02 16:50:14 temp2 11.6
2022-02-02 16:50:14 voltagediff 0.00200000000000022
Das Ergebnis stimmt leider doch nicht.
Das Ergebnis müsste in dem obigen Zustand 0,008 sein.
Grüße
2022-02-02 17:07:47 cellVoltage1 3.624
2022-02-02 17:07:47 cellVoltage2 3.594
2022-02-02 17:07:47 cellVoltage3 3.614
2022-02-02 17:07:47 cellVoltage4 3.624
2022-02-02 17:07:47 cellVoltage5 65.352
2022-02-02 17:07:47 cellVoltage6 0
2022-02-02 17:07:47 cellVoltage7 0
2022-02-02 17:07:47 state Online
2022-02-02 17:07:47 temp1 12.7
2022-02-02 17:07:47 temp2 11.6
2022-02-02 17:07:47 voltagediff 0
Der Code rechnet, wie es aussieht einfach nur immer cellVoltage1 - cellVolatge4
D.h. die Sortierung scheint nicht zu funktionieren.
Grüße
NACHTRAG:
2022-02-02 17:12:04 cellVoltage1 3.631
2022-02-02 17:12:04 cellVoltage2 3.598
2022-02-02 17:12:04 cellVoltage3 3.621
2022-02-02 17:12:04 cellVoltage4 3.63
2022-02-02 17:12:04 cellVoltage5 65.328
2022-02-02 17:12:04 cellVoltage6 0
2022-02-02 17:12:04 cellVoltage7 0
2022-02-02 17:12:04 state Online
2022-02-02 17:12:04 temp1 12.7
2022-02-02 17:12:04 temp2 11.6
2022-02-02 17:12:04 voltagediff -0.00099999999999989
Es wird nur Cell1-Cell4 gerechnet.
Daher auch das Ergebnis mit "falschem" Vorzeichen.
Probier mal:
attr BatteryPack1 userReadings voltagediff:cellVoltage.* {my @ar=sort(ReadingsNum($NAME,"cellVoltage1",0),ReadingsNum($NAME,"cellVoltage2",0),ReadingsNum($NAME,"cellVoltage3",0),ReadingsNum($NAME,"cellVoltage4",0)); my $min=$ar[0]; my $max=$ar[-1]; return sprintf("%.3f",$max - $min);}
Gruß
Dan
2022-02-02 17:25:34 cellVoltage1 3.639
2022-02-02 17:25:34 cellVoltage2 3.601
2022-02-02 17:25:34 cellVoltage3 3.631
2022-02-02 17:25:34 cellVoltage4 3.64
2022-02-02 17:25:34 voltagediff 0.039
Hey, super!
Das sieht schon besser aus!
Die Zellen sind gleich voll!
Daher wird sich die Differenz wahrscheinlich nicht mehr stark verschieben.
Werde heute spät oder spätestens morgen ein Entladen anstoßen. Dann sehe ich das genau ob die Rechnung auch passt wenn die Zellen sich gegeneinander verschieben.
Ich gebe da aber dann nochmal abschließend eine Rückmeldung.
Vielen Dank für deine Hilfe. Auch wenn ich den Code ungefähr entschlüsseln kann, würde ich sowas niemals hinbekommen.
Grüße und einen schönen Abend
Sry, für das reingrätschen, interessiert mich aber. Es klappt auch wenn man das sortierte Array in einer neuen Variablen speichert und dann daraus die min/max Werte nimmt.
Was denn der Grund dafür das es nur so klappt ?
Zitat{my @ar=(ReadingsNum($NAME,"cellVoltage1",0),ReadingsNum($NAME,"cellVoltage2",0),ReadingsNum($NAME,"cellVoltage3",0),ReadingsNum($NAME,"cellVoltage4",0)); my @sar = sort @ar; my $min = $sar[0]; my $max = $sar[-1]; return $max - $min;}
Zitat von: Knallfrosch am 02 Februar 2022, 17:29:58
2022-02-02 17:25:34 cellVoltage1 3.639
2022-02-02 17:25:34 cellVoltage2 3.601
2022-02-02 17:25:34 cellVoltage3 3.631
2022-02-02 17:25:34 cellVoltage4 3.64
2022-02-02 17:25:34 voltagediff 0.039
Hey, super!
Das sieht schon besser aus!
Die Zellen sind gleich voll!
Daher wird sich die Differenz wahrscheinlich nicht mehr stark verschieben.
Werde heute spät oder spätestens morgen ein Entladen anstoßen. Dann sehe ich das genau ob die Rechnung auch passt wenn die Zellen sich gegeneinander verschieben.
Ich gebe da aber dann nochmal abschließend eine Rückmeldung.
Vielen Dank für deine Hilfe. Auch wenn ich den Code ungefähr entschlüsseln kann, würde ich sowas niemals hinbekommen.
Grüße und einen schönen Abend
Na super!
Viel Spaß damit.
Zitat von: TomLee am 02 Februar 2022, 17:38:44
Sry, für das reingrätschen, interessiert mich aber. Es klappt auch wenn man das sortierte Array in einer neuen Variablen speichert und dann daraus die min/max Werte nimmt.
Was denn der Grund dafür das es nur so klappt ?
Ja, das ist der Grund. Das sortierte Array muss in eine eigene Variable.
Deswegen habe ich das im 2. Versuch so umgebaut.
Gruß
Dan
sort{$a<=>$b}(@z))
Weil ich unterwegs bin.
Zitat von: CoolTux am 02 Februar 2022, 17:57:00
sort{$a<=>$b}(@z))
"{$a<=>$b}" ist doch die "default" Sortierung wenn man es weglässt, oder!?
Gruß
Dan
Schneller ist es vermutlich, wenn man ohne das Zwischenarray arbeitet und dann nur die Startwerte aus Reading1 nimmt {my $min = ReadingsNum($name,'cellVoltage1',100000); my $max = ReadingsNum($name,'cellVoltage1',0); for (2..4) { $min = minNum(ReadingsNum($name,"cellVoltage$_",$min),$min); $max = maxNum(ReadingsNum($name,"cellVoltage$_",$max),$max);} return $max - $min }
"sort" muss ja intern auch (mehrfach!, aber ggf. gegen mehr Werte) vergleichen.
Zitat von: Beta-User am 02 Februar 2022, 18:04:58
Schneller ist es vermutlich, wenn man ohne das Zwischenarray arbeitet und dann nur die Startwerte aus Reading1 nimmt {my $min = ReadingsNum($name,'cellVoltage1',100000); my $max = ReadingsNum($name,'cellVoltage1',0); for (2..4) { $min = minNum(ReadingsNum($name,"cellVoltage$_",$min),$min); $max = maxNum(ReadingsNum($name,"cellVoltage$_",$max),$max);} return $max - $min }
"sort" muss ja intern auch (mehrfach!, aber ggf. gegen mehr Werte) vergleichen.
Ich finde es immer wieder klasse zu sehen wie andere so etwas lösen.
Man lernt immer dazu!
Gruß
Dan
Zitat von: DeeSPe am 02 Februar 2022, 18:00:55
"{$a<=>$b}" ist doch die "default" Sortierung wenn man es weglässt, oder!?
Gruß
Dan
Möglich aus dem Kopf weiß ich das gerade ehrlich gesagt nicht.
Zitat"{$a<=>$b}" ist doch die "default" Sortierung wenn man es weglässt, oder!?
Nö, 8).
{my @ar=sort(14,12,2,23,3 );; return join ',',@ar}
12,14,2,23,3
{my @ar=sort { $a <=> $b } (14,12,2,23,3 );; return join ',',@ar}
2,3,12,14,23
https://perlmaven.com/sorting-arrays-in-perl
Und dann einfach den ersten und den letzten Index aus dem sortier Array raus ziehen. War so meine Idee.
Zitat von: TomLee am 02 Februar 2022, 18:29:13
Nö, 8).
{my @ar=sort(14,12,2,23,3 );; return join ',',@ar}
12,14,2,23,3
{my @ar=sort { $a <=> $b } (14,12,2,23,3 );; return join ',',@ar}
2,3,12,14,23
https://perlmaven.com/sorting-arrays-in-perl
Ahh, verstehe! Klappt hier aber dennoch da es nur um die Nachkommastellen geht.
Zitat von: CoolTux am 02 Februar 2022, 18:56:31
Und dann einfach den ersten und den letzten Index aus dem sortier Array raus ziehen. War so meine Idee.
Das ist doch auch meine Herangehensweise gewesen. ;)
Wusste nur nicht das die "default" Sortierung nur auf die erste Ziffer der Zahlen achtet.
Gruß
Dan
Zitat#!/usr/bin/perl
#
use strict;
use warnings;
use feature qw /say/;
my @zahlen = ( 34, 76, 23, 1, 5, 9, 4, 7, 234, 98, 34 );
say join ',', ( sort { $a <=> $b } (@zahlen) )[ 0, -1 ];
exit;
Bin jetzt zu Hause.
Zum anschauen und rumspielen.
So weiter geht es
return join ', ', ( sort { $a <=> $b } ( @{ $defs{'BatteryPack1'}->{READINGS} }{ ( 'cellVoltage1', 'cellVoltage2', 'cellVoltage3', 'cellVoltage4' ) } ) )[ 0, -1 ];
Das als userreadings und Du bekommst Deine 2 Werte. Den kleinsten und den größten aus Deinen Readings cellVoltage 1-4
Grüße
PS: Nachträgliche Korrektur bei den READINGS
Mein Beispiel wird ohne weitere Anpassung nicht gehen. Siehe unten Beispiel zum Aufbau des Hash einer Geräteinstanz
$hash->{READINGS}{<readingname>}{VAL}
Ich lasse mein Beispiel aber stehen als Ansatz zum weiterprobieren.
Mal für nen Rookie: warum sind min() und max() (https://perlmaven.com/min-max-sum-using-list-util) keine Optionen?
voltagediff:cellVoltage.* {my @ar= (ReadingsNum($NAME,"cellVoltage1",0), ReadingsNum($NAME,"cellVoltage2",0), ReadingsNum($NAME,"cellVoltage3",0), ReadingsNum($NAME,"cellVoltage4",0));
return sprintf("%.3f",max(@ar) - min(@ar));}
Zitat von: yersinia am 03 Februar 2022, 07:43:33
Mal für nen Rookie: warum sind min() und max() (https://perlmaven.com/min-max-sum-using-list-util) keine Optionen?
voltagediff:cellVoltage.* {my @ar= (ReadingsNum($NAME,"cellVoltage1",0), ReadingsNum($NAME,"cellVoltage2",0), ReadingsNum($NAME,"cellVoltage3",0), ReadingsNum($NAME,"cellVoltage4",0));
return sprintf("%.3f",max(@ar) - min(@ar));}
Wer hat gesagt das min und max keine Optionen sind. Es gibt viele Wege. Persönlich finde ich es gut auch andere Wege zu kennen. Für das was Du vorhast ist min und max voll ausreichend. Wenn jemand mehr machen möchte, größere Mengen mehr Perl Code findet er das hier beim suchen und erfreut sich der unterschiedlichen Möglichkeiten.
Meine Lösung sollte laut meiner Einbildung effizienter sein. Was aber nur bei größeren Datenmengen auffallen dürfte und im ms Bereich liegt.
Grüße
:P Meiner einer....
Aber beschränkt auf main.
Zitat von: Beta-User am 03 Februar 2022, 08:09:34
:P Meiner einer....
Nanu? Keine unmittelbare Reaktion?!?
Sorry vorab, am Handy war nur nicht gut zu sehen, dass es da einen Link auf List::Util gab, und das ist an sich durchaus eine Option.
Ansonsten mal vergleichen:
{min 3,9,12}
{List::Util::min 3,9,12}
Das Problem damit ist nur, dass man aufpassen muss, dass man sich nicht versehentlich was anderes damit zerhaut:
Es gibt nämlich im main-Kontext schon eine Funktion "min", und wenn man im falschen lexikalischen Kontext ein "use List::Util;" einbaut, funktionieren eventuell auch einzelne FHEM-Module oder eigener Code wie erwartet...
Und noch ein Nachtrag: Das mit dem Ersatzwert "0" ist schwierig, wenn (anders als hier) tatsächlich mal kein Wert vorhanden sein könnte. Da hier anscheinend der Code des Moduls immer numerische Werte bringt, kann man auf den "num"-Overhead übrigens auch verzichten...
Zitat von: Beta-User am 03 Februar 2022, 08:54:34
Nanu? Keine unmittelbare Reaktion?!?
Sorry vorab, am Handy war nur nicht gut zu sehen, dass es da einen Link auf List::Util gab, und das ist an sich durchaus eine Option.
Das Problem damit ist nur, dass man aufpassen muss, dass man sich nicht versehentlich was anderes damit zerhaut:
Es gibt nämlich im main-Kontext schon eine Funktion "min", und wenn man im falschen lexikalischen Kontext ein "use List::Util;" einbaut, funktionieren eventuell auch einzelne FHEM-Module oder eigener Code wie erwartet...
Ich habe es still zur Kenntnis genommen :D Hätte da aber auch nichts weiter zu sagen können da ich mir nicht alles im ganzen an gelesen habe was hier im Thread steht.
@Knallfrosch
falls Du noch Möglichkeiten suchst, hier mal eine Version in "DOIF":
defmod di_BatteryPack1 DOIF ##\
attr di_BatteryPack1 event-on-change-reading maxDiff
attr di_BatteryPack1 event_Readings maxDiff:sprintf("%.3f",[#max:"^BatteryPack1$":"^cellVoltage[1-4]"] - [#min:"^BatteryPack1$":"^cellVoltage[1-4]"])
realisiert mit einem event_Readings. Sobald sich einer der 4 Werte im Device BatteryPack1 ändert wird neu gerechnet. Der neue Wert erzeugt ein event. Solltest Du z.B. innerhalb dieses DOIF den Wert verwenden wollen (z.B. Anzeige mittels uiTable) dann könntest Du auch statt event_Readings DOIF_Readings nehmen. Macht das gleiche, nur ohne event "nach draussen".
Viel Erfolg!
Sany
Hallo,
interessant, wie viel mit 1-2 Zeilen Code möglich ist und das es wohl einige unterschiedliche Lösungen für das Problem gibt.
Die Lösung von DeeSpe funktioniert einwandfrei. Danke nochmal!
Aktuell werde ich nichts mehr umbauen, auch wenn die anderen Vorschläge sicherlich auch funktionieren. :-)
Ich schließe das Thema einfach mal als gelöst ab.
Grüße
Ich stand vor dem gleichen Problem und bin hier fündig geworden. Danke dafür :)
Manfred