diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm
index 571e09b6b..a7533f812 100644
--- a/fhem/contrib/DS_Starter/76_SolarForecast.pm
+++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm
@@ -38,7 +38,7 @@ use POSIX;
use GPUtils qw(GP_Import GP_Export); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
use Time::HiRes qw(gettimeofday tv_interval);
use Math::Trig;
-use List::Util qw(min max shuffle);
+use List::Util qw(sum min max shuffle);
use Scalar::Util qw(blessed weaken);
eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; ## no critic 'eval'
@@ -160,6 +160,7 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
+ "1.54.4" => "20.07.2025 replace length by new sub strlength, Consumer attr new key 'aliasshort' ",
"1.54.3" => "19.07.2025 ctrlDebug: add collectData_long ",
"1.54.2" => "18.07.2025 _createSummaries: add debug infos ",
"1.54.1" => "08.07.2025 userExit: new coding, __createReduceIcon: fix Wide character in syswrite - https://forum.fhem.de/index.php?msg=1344368 ".
@@ -5886,7 +5887,7 @@ sub __updPreFile {
return $err;
}
- if ($lencheck && length $remFile ne $cmlen) {
+ if ($lencheck && length ($remFile) ne $cmlen) {
$err = "update ERROR: length of $file is not $cmlen Bytes";
Log3 ($name, 1, "$name - $err");
return $err;
@@ -5947,22 +5948,18 @@ sub __updWriteFile {
my $content = shift;
my $fPath = "$root/$fName";
- my $err;
+
+ open my $fh, '>:raw', $fPath or return "update ERROR open $fPath failed: $!";
- if (!open(FD, ">$fPath")) {
- $err = "update ERROR open $fPath failed: $!";
- return $err;
- }
+ my $bytes = encode ('UTF-8', $content);
+ print {$fh} $bytes;
+ close $fh or return "update ERROR closing $fPath failed: $!";
+
+ my $written = -s $fPath;
+ my $expected = strlength ($bytes);
- binmode(FD);
- print FD $content;
- close(FD);
-
- my $written = -s "$fPath";
-
- if ($written != length $content) {
- $err = "update ERROR writing $fPath failed: $!";
- return $err;
+ if ($written != $expected) {
+ return "update ERROR writing $fPath failed: $!";
}
return;
@@ -6085,6 +6082,7 @@ sub _attrconsumer { ## no critic "not used"
my $hash = $defs{$name};
my $valid = {
+ aliasshort => '',
type => '',
power => '',
switchdev => '',
@@ -6143,6 +6141,11 @@ sub _attrconsumer { ## no critic "not used"
if (defined $h->{exconfc} && $h->{exconfc} !~ /^[012]$/xs) {
return qq{The key "exconfc" is not set correct. Please consider the command reference.};
}
+
+ if (exists $h->{aliasshort}) { # Kurzalias
+ return qq{The short alias "$h->{aliasshort}" longer than allowed. See command reference.}
+ if(strlength ($h->{aliasshort})> 10);
+ }
if (exists $h->{mode} && $h->{mode} !~ /^(?:can|must)$/xs) {
if ($h->{mode} =~ /.*:.*/xs) {
@@ -9236,6 +9239,7 @@ sub _collectAllRegConsumers {
$data{$name}{consumers}{$c}{name} = $consumer; # Name des Verbrauchers (Device)
$data{$name}{consumers}{$c}{alias} = $alias; # Alias des Verbrauchers (Device)
+ $data{$name}{consumers}{$c}{aliasshort} = $hc->{aliasshort} // q{}; # Kurzalias des Verbrauchers
$data{$name}{consumers}{$c}{type} = $hc->{type} // DEFCTYPE; # Typ des Verbrauchers
$data{$name}{consumers}{$c}{power} = $hc->{power}; # Leistungsaufnahme des Verbrauchers in W
$data{$name}{consumers}{$c}{avgenergy} = q{}; # Initialwert Energieverbrauch (evtl. Überschreiben in manageConsumerData)
@@ -17746,7 +17750,7 @@ sub _flowGraphic {
my $flowgxshift = $paref->{flowgxshift}; # X-Verschiebung der Flußgrafikbox (muß negiert werden)
my $flowgyshift = $paref->{flowgyshift}; # Y-Verschiebung der Flußgrafikbox (muß negiert werden)
my $flowgconsumer = $paref->{flowgconsumer}; # Verbraucher in der Energieflußgrafik anzeigen
- my $flowgconsTime = $paref->{flowgconsTime}; # Verbraucher Restlaufeit in der Energieflußgrafik anzeigen
+ my $flowgconsTime = $paref->{flowgconsTime}; # Verbraucher Restlaufzeit in der Energieflußgrafik anzeigen
my $flowgconX = $paref->{flowgconX};
my $flowgconsPower = $paref->{flowgconsPower};
my $cdist = $paref->{flowgconsDist}; # Abstand Consumer zueinander
@@ -17764,7 +17768,7 @@ sub _flowGraphic {
my $stna = $name;
$stna .= int (rand (1500));
- my ($y_pos, $y_pos1, $err);
+ my ($y_pos, $y_pos1, $y_pos2, $err);
for my $re (keys %hrepl) { # V 1.37.1 Ziffern etc. eliminieren, Forum: https://forum.fhem.de/index.php?msg=1323229
$stna =~ s/$re/$hrepl{$re}/gxs;
@@ -17913,17 +17917,23 @@ sub _flowGraphic {
## definierte Verbraucher ermitteln
#####################################
- my $cnsmr = {}; # Hashref Consumer current power
+ my $cnsmr = {}; # Consumer Hilfshash Referenz
- for my $c (sort{$a<=>$b} keys %{$data{$name}{consumers}}) { # definierte Verbraucher ermitteln
- next if(isConsumerNoshow ($hash, $c) =~ /[13]/xs); # auszublendende Consumer nicht berücksichtigen
- $cnsmr->{$c}{p} = ReadingsNum ($name, "consumer${c}_currentPower", 0);
- $cnsmr->{$c}{ptyp} = 'consumer';
+ for my $c (sort{$a<=>$b} keys %{$data{$name}{consumers}}) { # definierte Verbraucher ermitteln
+ next if(isConsumerNoshow ($hash, $c) =~ /[13]/xs); # auszublendende Consumer nicht berücksichtigen
+ $cnsmr->{$c}{p} = ReadingsNum ($name, "consumer${c}_currentPower", 0);
+ $cnsmr->{$c}{shortalias} = ConsumerVal ($name, $c, 'aliasshort', ''); # Consumer Kurzalias
+ $cnsmr->{$c}{ptyp} = 'consumer';
}
my $consumercount = keys %{$cnsmr};
- $flowgconsumer = 0 if(!$consumercount); # Consumer Anzeige ausschalten wenn keine Consumer definiert
+ $flowgconsumer = 0 if(!$consumercount); # Consumer Anzeige ausschalten wenn keine Consumer definiert
my @consumers = sort{$a<=>$b} keys %{$cnsmr};
+
+ my $total_shortalias_length = sum map { my $a = $_->{shortalias} // '';
+ strlength ($a); # Länge in Zeichen nach Zeichen-Dekodierung
+ }
+ values %{$cnsmr};
## Producer / Inverter Koordinaten Steuerhash
@@ -17951,8 +17961,9 @@ sub _flowGraphic {
$vbminy -= 150 if($showproducers); # mehr Platz oben schaffen wenn Poducerreihe angezeigt
$vbminy -= INPUTROWSHIFT if($showgenerators); # mehr Platz oben schaffen wenn Zellen/Input-Reihe angezeigt
- my $vbhight = 610;
+ my $vbhight = 630;
$vbhight -= 20 if(!$flowgconsTime);
+ $vbhight -= 20 if(!$total_shortalias_length);
$vbhight -= 230 if(!$flowgconsumer);
$vbhight += PRDCRROWSHIFT if($showproducers); # Höhe Box vergrößern wenn Poducerreihe angezeigt
@@ -18329,7 +18340,7 @@ END3
$ytext = $showproducers ? $ytext - PRDCRROWSHIFT + 5 : $ytext + PRDCRROWSHIFT - 30; # Unterscheidung wenn ProducerZeile angezeigt werden soll
my $genpow = __getGeneratorPower ( { pdcr => $pdcr, lfn => $lfn } ); # aktuelle Generatorleistung
- my $lpv1 = length $genpow;
+ my $lpv1 = strlength ($genpow);
# Leistungszahl abhängig von der Größe entsprechend auf der x-Achse verschieben
#################################################################################
@@ -18359,7 +18370,7 @@ END3
$xtext = $xtext * 2 - 70; # Korrektur Start X-Koordinate des Textes
my $pdrpow = __getProducerPower ( { pdcr => $pdcr, lfn => $lfn } );
- my $lpv1 = length $pdrpow;
+ my $lpv1 = strlength ($pdrpow);
# Leistungszahl abhängig von der Größe entsprechend auf der x-Achse verschieben
###############################################################################
@@ -18378,10 +18389,28 @@ END3
########################
if ($flowgconsumer) {
$cons_left = ($consumer_start * 2) - 50; # -XX -> Start Lage Consumer Beschriftung
- $y_pos = 1110 + 2 * $exth2cdist;
- $y_pos1 = 1170 + 2 * $exth2cdist;
+
+ my %offset = (
+ 0b00 => 0, # weder Power noch Time
+ 0b01 => 60, # nur Power
+ 0b10 => 60, # nur Time
+ 0b11 => 120, # beide
+ );
+
+ my $y_base = 1110 + 2 * $exth2cdist;
+ $y_pos = $y_base; # flowgconsPower
+ my $mask = $flowgconsPower ? 1 : 0;
+ $y_pos1 = $y_base + $offset{$mask}; # flowgconsTime
+
+ $mask = $flowgconsPower && $flowgconsTime ? 3 :
+ $flowgconsTime ? 2 :
+ $flowgconsPower ? 1 :
+ 0;
+
+ $y_pos2 = $y_base + $offset{$mask}; # shortalias
for my $c (@consumers) {
+ my $shortalias = $cnsmr->{$c}{shortalias} // '';
$cnsmrpower = sprintf "%.1f", $cnsmr->{$c}{p};
$cnsmrpower = sprintf "%.0f", $cnsmrpower if($cnsmrpower > 10);
my $consumerTime = ConsumerVal ($name, $c, 'remainTime', ''); # Restlaufzeit
@@ -18391,31 +18420,54 @@ END3
$cnsmrpower = isConsumerPhysOn($hash, $c) ? 'on' : 'off';
}
- my $lcp = length $cnsmrpower;
+ my $lcp = strlength ($cnsmrpower);
+ my $lct = strlength ($consumerTime);
+ my $lcs = strlength ($shortalias);
- #$ret .= qq{