2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 00:36:25 +00:00

76_SolarForecast: contrib 1.44.5

git-svn-id: https://svn.fhem.de/fhem/trunk@29592 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2025-01-29 21:44:22 +00:00
parent cc5a9556e0
commit 7f1083319e

View File

@ -160,7 +160,9 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.44.4" => "26.01.2025 _getlistPVCircular: change width of output, new sub _listDataPoolPvHist ", "1.44.5" => "29.01.2025 temp2bin: expand to more negative bins ",
"1.44.4" => "26.01.2025 _getlistPVCircular: change width of output, new sub _listDataPoolPvHist, fix bug in hrepl Hash ".
"remove Attr graphicBeam1MaxVal,ctrlAreaFactorUsage ",
"1.44.3" => "25.01.2025 Notification System: minor changes, special Readings todayBatInSum todayBatOutSum ", "1.44.3" => "25.01.2025 Notification System: minor changes, special Readings todayBatInSum todayBatOutSum ",
"1.44.2" => "23.01.2025 _batChargeRecmd: user storeffdef, show historical battery SoC when displaying the battery in the bar graph ", "1.44.2" => "23.01.2025 _batChargeRecmd: user storeffdef, show historical battery SoC when displaying the battery in the bar graph ",
"1.44.1" => "20.01.2025 Notification system: minor fixes, integration of controls_solarforecast_messages_test/prod ". "1.44.1" => "20.01.2025 Notification system: minor fixes, integration of controls_solarforecast_messages_test/prod ".
@ -1390,7 +1392,6 @@ sub Initialize {
"ctrlBackupFilesKeep ". "ctrlBackupFilesKeep ".
"ctrlConsRecommendReadings:multiple-strict,$allcs ". "ctrlConsRecommendReadings:multiple-strict,$allcs ".
"ctrlDebug:multiple-strict,$dm,#10 ". "ctrlDebug:multiple-strict,$dm,#10 ".
"ctrlAreaFactorUsage ".
"ctrlGenPVdeviation:daily,continuously ". "ctrlGenPVdeviation:daily,continuously ".
"ctrlInterval ". "ctrlInterval ".
"ctrlLanguage:DE,EN ". "ctrlLanguage:DE,EN ".
@ -1450,12 +1451,11 @@ sub Initialize {
$readingFnAttributes; $readingFnAttributes;
## Hinweis: graphicBeamXContent wird in _addDynAttr hinzugefügt ## Hinweis: graphicBeamXContent wird in _addDynAttr hinzugefügt
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !! ### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
########################################################################################################################## ##########################################################################################################################
my $av1 = "obsolete#-#the#attribute#will#be#deleted#soon"; # 12.01.25 # my $av1 = "obsolete#-#the#attribute#will#be#deleted#soon";
$hash->{AttrList} .= " graphicBeam1MaxVal:$av1 ctrlAreaFactorUsage:$av1 "; # $hash->{AttrList} .= " graphicBeam1MaxVal:$av1 ctrlAreaFactorUsage:$av1 ";
########################################################################################################################## ##########################################################################################################################
$hash->{FW_hideDisplayName} = 1; # Forum 88667 $hash->{FW_hideDisplayName} = 1; # Forum 88667
@ -4745,7 +4745,7 @@ sub _getlistPVCircular {
my $hash = $defs{$name}; my $hash = $defs{$name};
my $ret = listDataPool ($hash, 'circular', $arg); my $ret = listDataPool ($hash, 'circular', $arg);
$ret .= lineFromSpaces ($ret, 5); $ret .= lineFromSpaces ($ret, -20);
return $ret; return $ret;
} }
@ -5538,16 +5538,16 @@ sub Attr {
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !! ### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
###################################################################################################################### ######################################################################################################################
if ($cmd eq 'set' && $aName =~ /^graphicBeam1MaxVal|ctrlAreaFactorUsage$/) { # 12.01.25 #if ($cmd eq 'set' && $aName =~ /^graphicBeam1MaxVal|ctrlAreaFactorUsage$/) {
my $msg = "The attribute $aName is obsolete and will be deleted soon. Please save your Configuration."; # my $msg = "The attribute $aName is obsolete and will be deleted soon. Please save your Configuration.";
if (!$init_done) { # if (!$init_done) {
Log3 ($name, 1, "$name - $msg"); # Log3 ($name, 1, "$name - $msg");
return qq{Device "$name" -> $msg}; # return qq{Device "$name" -> $msg};
} # }
else { # else {
return $msg; # return $msg;
} # }
} #}
###################################################################################################################### ######################################################################################################################
if ($aName eq 'disable') { if ($aName eq 'disable') {
@ -8291,14 +8291,6 @@ sub __delObsoleteAPIData {
delete $data{$name}{solcastapi}{$idx}{$scd} if($ds && $ds < $refts); delete $data{$name}{solcastapi}{$idx}{$scd} if($ds && $ds < $refts);
} }
} }
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
##########################################################################################################################
# 01.12.2024
for my $idx (keys %{$data{$name}{solcastapi}{'?All'}}) { # Wetterindexe löschen (kann später raus)
delete $data{$name}{solcastapi}{'?All'}{$idx} if($idx =~ /^fc?([0-9]{1,2})_?([0-9]{1,2})$/xs);
}
#####################################################################################################################
} }
## veraltete Strings aus Strings-Hash löschen ## veraltete Strings aus Strings-Hash löschen
@ -13193,8 +13185,6 @@ sub entryGraphic {
delete $paref->{maxDif}; delete $paref->{maxDif};
delete $paref->{minDif}; delete $paref->{minDif};
Log3 ($name, 4, "$name - RET nach Ebene 1:\n".$ret);
## Balkengrafik Ebene 2 ## Balkengrafik Ebene 2
######################### #########################
if ($paref->{beam3cont} || $paref->{beam4cont}) { # Balkengrafik Ebene 2 if ($paref->{beam3cont} || $paref->{beam4cont}) { # Balkengrafik Ebene 2
@ -13232,8 +13222,6 @@ sub entryGraphic {
delete $paref->{maxDif}; delete $paref->{maxDif};
delete $paref->{minDif}; delete $paref->{minDif};
} }
Log3 ($name, 4, "$name - RET nach Ebene 2:\n".$ret);
$paref->{modulo}++; $paref->{modulo}++;
} }
@ -13268,8 +13256,6 @@ sub entryGraphic {
$ret .= "</td></tr>"; $ret .= "</td></tr>";
$ret .= "</table>"; $ret .= "</table>";
Log3 ($name, 4, "$name - RET nach Ebene Flowgrafik:\n".$ret);
return $ret; return $ret;
} }
@ -14857,7 +14843,6 @@ sub _beamGraphic {
my $ret = q{}; my $ret = q{};
$ret .= __weatherOnBeam ($paref) if($weather); $ret .= __weatherOnBeam ($paref) if($weather);
$ret .= __batteryOnBeam ($paref); $ret .= __batteryOnBeam ($paref);
my $m = $paref->{modulo} % 2; my $m = $paref->{modulo} % 2;
if ($show_diff eq 'top') { # Zusätzliche Zeile Ertrag - Verbrauch if ($show_diff eq 'top') { # Zusätzliche Zeile Ertrag - Verbrauch
@ -16527,7 +16512,6 @@ sub getMessageFileNonBlocking {
Log3 ($name, 4, "$name - Notification System - Message file >$messagefile< is retrieved non blocking"); Log3 ($name, 4, "$name - Notification System - Message file >$messagefile< is retrieved non blocking");
my $paref = { name => $name, my $paref = { name => $name,
hash => $hash,
block => 1 block => 1
}; };
@ -17646,53 +17630,7 @@ sub listDataPool {
} }
if ($htol =~ /consumers|inverters|producers|strings|batteries/xs) { if ($htol =~ /consumers|inverters|producers|strings|batteries/xs) {
my $sub = $htol eq 'consumers' ? \&ConsumerVal : $sq = _listDataPoolVarious ($hash, $htol, $par);
$htol eq 'inverters' ? \&InverterVal :
$htol eq 'producers' ? \&ProducerVal :
$htol eq 'strings' ? \&StringVal :
$htol eq 'batteries' ? \&BatteryVal :
'';
$h = $data{$name}{$htol};
if (!keys %{$h}) {
return ucfirst($htol).qq{ cache is empty.};
}
for my $i (keys %{$h}) {
if ($i !~ /^[0-9]{2}$/ix && $htol ne 'strings') { # bereinigen ungültige Position, Forum: https://forum.fhem.de/index.php/topic,117864.msg1173219.html#msg1173219
delete $data{$name}{$htol}{$i};
Log3 ($name, 2, qq{$name - INFO - invalid key "$i" was deleted from }.ucfirst($htol).qq{ storage});
}
}
for my $idx (sort keys %{$h}) {
next if($par && $idx ne $par);
my ($cret, $s1);
my $sp1 = _ldpspaces ($idx, q{});
for my $ckey (sort keys %{$h->{$idx}}) {
if (ref $h->{$idx}{$ckey} eq 'ARRAY') {
my $aser = join " ", @{$h->{$idx}{$ckey}};
$cret .= ($s1 ? $sp1 : "").$ckey." => ".$aser."\n";
}
if (ref $h->{$idx}{$ckey} eq 'HASH') {
my $hk = qq{};
for my $f (sort {$a<=>$b} keys %{$h->{$idx}{$ckey}}) {
$hk .= " " if($hk);
$hk .= "$f=".$h->{$idx}{$ckey}{$f};
}
$cret .= ($s1 ? $sp1 : "").$ckey." => ".$hk."\n";
}
else {
$cret .= ($s1 ? $sp1 : "").$ckey." => ". &{$sub} ($hash, $idx, $ckey, "")."\n";
}
$s1 = 1;
}
$sq .= $idx." => ".$cret."\n";
}
} }
if ($htol eq "circular") { if ($htol eq "circular") {
@ -17700,186 +17638,19 @@ sub listDataPool {
} }
if ($htol eq "nexthours") { if ($htol eq "nexthours") {
$h = $data{$name}{nexthours}; $sq = _listDataPoolNextHours ($name, $par);
if (!keys %{$h}) {
return qq{NextHours cache is empty.};
}
for my $idx (sort keys %{$h}) {
my $nhts = NexthoursVal ($name, $idx, 'starttime', '-');
my $hod = NexthoursVal ($name, $idx, 'hourofday', '-');
my $today = NexthoursVal ($name, $idx, 'today', '-');
my $pvfc = NexthoursVal ($name, $idx, 'pvfc', '-');
my $pvapifc = NexthoursVal ($name, $idx, 'pvapifc', '-'); # PV Forecast der API
my $pvaifc = NexthoursVal ($name, $idx, 'pvaifc', '-'); # PV Forecast der KI
my $aihit = NexthoursVal ($name, $idx, 'aihit', '-'); # KI ForeCast Treffer Status
my $wid = NexthoursVal ($name, $idx, 'weatherid', '-');
my $wcc = NexthoursVal ($name, $idx, 'wcc', '-');
my $crang = NexthoursVal ($name, $idx, 'cloudrange', '-');
my $rr1c = NexthoursVal ($name, $idx, 'rr1c', '-');
my $rrange = NexthoursVal ($name, $idx, 'rainrange', '-');
my $rad1h = NexthoursVal ($name, $idx, 'rad1h', '-');
my $pvcorrf = NexthoursVal ($name, $idx, 'pvcorrf', '-');
my $temp = NexthoursVal ($name, $idx, 'temp', '-');
my $confc = NexthoursVal ($name, $idx, 'confc', '-');
my $confcex = NexthoursVal ($name, $idx, 'confcEx', '-');
my $don = NexthoursVal ($name, $idx, 'DoN', '-');
my $sunaz = NexthoursVal ($name, $idx, 'sunaz', '-');
my $sunalt = NexthoursVal ($name, $idx, 'sunalt', '-');
my ($rcdbat, $socs);
for my $bn (1..$maxbatteries) { # alle Batterien
$bn = sprintf "%02d", $bn;
my $rcdcharge = NexthoursVal ($name, $idx, 'rcdchargebat'.$bn, '-');
my $socxx = NexthoursVal ($name, $idx, 'soc'.$bn, '-');
$rcdbat .= ', ' if($rcdbat);
$rcdbat .= "rcdchargebat${bn}: $rcdcharge";
$socs .= ', ' if($socs);
$socs .= "soc${bn}: $socxx";
}
$sq .= "\n" if($sq);
$sq .= $idx." => ";
$sq .= "starttime: $nhts, hourofday: $hod, today: $today";
$sq .= "\n ";
$sq .= "pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit, confc: $confc";
$sq .= "\n ";
$sq .= "confcEx: $confcex, DoN: $don, weatherid: $wid, wcc: $wcc, rr1c: $rr1c, temp=$temp";
$sq .= "\n ";
$sq .= "rad1h: $rad1h, sunaz: $sunaz, sunalt: $sunalt";
$sq .= "\n ";
$sq .= "rrange: $rrange, crange: $crang, correff: $pvcorrf";
$sq .= "\n ";
$sq .= $socs;
$sq .= "\n ";
$sq .= $rcdbat;
}
} }
if ($htol eq "qualities") { if ($htol eq "qualities") {
$h = $data{$name}{nexthours}; $sq = _listDataPoolQualities ($name, $par);
if (!keys %{$h}) {
return qq{NextHours cache is empty.};
}
for my $idx (sort keys %{$h}) {
my $nhfc = NexthoursVal ($hash, $idx, 'pvfc', undef);
next if(!$nhfc);
my $nhts = NexthoursVal ($hash, $idx, 'starttime', '-');
my $pvcorrf = NexthoursVal ($hash, $idx, 'pvcorrf', '-/-');
my $aihit = NexthoursVal ($hash, $idx, 'aihit', '-');
my $pvfc = NexthoursVal ($hash, $idx, 'pvfc', '-');
my $wcc = NexthoursVal ($hash, $idx, 'wcc', '-');
my $sunalt = NexthoursVal ($hash, $idx, 'sunalt', '-');
my ($f,$q) = split "/", $pvcorrf;
$sq .= "\n" if($sq);
$sq .= "Start: $nhts, Quality: $q, Factor: $f, AI usage: $aihit, PV expect: $pvfc Wh, Sun Alt: $sunalt, Cloud: $wcc";
}
} }
if ($htol eq "current") { if ($htol eq "current") {
$h = $data{$name}{current}; $sq = _listDataPoolCurrent ($name, $par);
if (!keys %{$h}) {
return qq{Current values cache is empty.};
}
for my $idx (sort keys %{$h}) {
if (ref $h->{$idx} eq 'ARRAY') {
my $aser = join " ",@{$h->{$idx}};
$sq .= $idx." => ".$aser."\n";
}
elsif (ref $h->{$idx} eq 'HASH') {
my $s1;
my $sp1 = _ldpspaces ($idx, q{});
$sq .= $idx." => ";
for my $idx1 (sort keys %{$h->{$idx}}) {
if (ref $h->{$idx}{$idx1} eq 'HASH') {
my $s2;
my $sp2 = _ldpspaces ($idx1, $sp1);
$sq .= ($s1 ? $sp1 : "").$idx1." => ";
for my $idx2 (sort keys %{$h->{$idx}{$idx1}}) {
my $s3;
my $sp3 = _ldpspaces ($idx2, $sp2);
$sq .= ($s2 ? $sp2 : "").$idx2." => ";
if (ref $h->{$idx}{$idx1}{$idx2} eq 'HASH') {
for my $idx3 (sort keys %{$h->{$idx}{$idx1}{$idx2}}) {
$sq .= ($s3 ? $sp3 : "").$idx3." => ".(defined $h->{$idx}{$idx1}{$idx2}{$idx3} ? $h->{$idx}{$idx1}{$idx2}{$idx3} : '')."\n";
$s3 = 1;
}
}
else {
$sq .= (defined $h->{$idx}{$idx1}{$idx2} ? $h->{$idx}{$idx1}{$idx2} : '')."\n";
}
$s1 = 1;
$s2 = 1;
}
}
else {
$sq .= (defined $h->{$idx}{$idx1} ? $h->{$idx}{$idx1} : '')."\n";
}
}
}
else {
$sq .= $idx." => ".(defined $h->{$idx} ? $h->{$idx} : '')."\n";
}
}
} }
my $git = sub {
my $it = shift;
my @sorted = sort { $a cmp $b } keys %$it;
my $key = shift @sorted;
my $ret = {};
$ret = { $key => $it->{$key} } if($key);
return $ret;
};
if ($htol =~ /radiationApiData|weatherApiData|statusApiData/xs) { if ($htol =~ /radiationApiData|weatherApiData|statusApiData/xs) {
$h = $data{$name}{solcastapi}; $sq = _listDataPoolApiData ($name, $htol, $par);
$h = $data{$name}{weatherapi} if($htol eq 'weatherApiData');
$h = $data{$name}{statusapi} if($htol eq 'statusApiData');
if (!keys %{$h}) {
return qq{The API values cache is empty.};
}
my $pve = q{};
my $itref = dclone $h; # Deep Copy von $h
for my $idx (sort keys %{$itref}) {
my $s1;
my $sp1 = _ldpspaces ($idx, q{});
$sq .= $idx." => ";
while (my ($tag, $item) = each %{$git->($itref->{$idx})}) {
$sq .= ($s1 ? $sp1 : "").$tag." => ";
if (ref $item eq 'HASH') {
my $s2;
my $sp2 = _ldpspaces ($tag, $sp1);
while (my ($tag1, $item1) = each %{$git->($itref->{$idx}{$tag})}) {
$sq .= ($s2 ? $sp2 : "")."$tag1: ".$item1."\n";
$s2 = 1;
delete $itref->{$idx}{$tag}{$tag1};
}
}
$s1 = 1;
$sq .= "\n" if($sq !~ /\n$/xs);
delete $itref->{$idx}{$tag};
}
}
} }
if ($htol eq "aiRawData") { if ($htol eq "aiRawData") {
@ -17892,14 +17663,14 @@ sub listDataPool {
$sq = "<b>Number of datasets:</b> ".$maxcnt."\n"; $sq = "<b>Number of datasets:</b> ".$maxcnt."\n";
for my $idx (sort keys %{$h}) { for my $idx (sort keys %{$h}) {
my $hod = AiRawdataVal ($hash, $idx, 'hod', '-'); my $hod = AiRawdataVal ($name, $idx, 'hod', '-');
my $sunalt = AiRawdataVal ($hash, $idx, 'sunalt', '-'); my $sunalt = AiRawdataVal ($name, $idx, 'sunalt', '-');
my $sunaz = AiRawdataVal ($hash, $idx, 'sunaz', '-'); my $sunaz = AiRawdataVal ($name, $idx, 'sunaz', '-');
my $rad1h = AiRawdataVal ($hash, $idx, 'rad1h', '-'); my $rad1h = AiRawdataVal ($name, $idx, 'rad1h', '-');
my $wcc = AiRawdataVal ($hash, $idx, 'wcc', '-'); my $wcc = AiRawdataVal ($name, $idx, 'wcc', '-');
my $rr1c = AiRawdataVal ($hash, $idx, 'rr1c', '-'); my $rr1c = AiRawdataVal ($name, $idx, 'rr1c', '-');
my $pvrl = AiRawdataVal ($hash, $idx, 'pvrl', '-'); my $pvrl = AiRawdataVal ($name, $idx, 'pvrl', '-');
my $temp = AiRawdataVal ($hash, $idx, 'temp', '-'); my $temp = AiRawdataVal ($name, $idx, 'temp', '-');
$sq .= "\n"; $sq .= "\n";
$sq .= "$idx => hod: $hod, sunaz: $sunaz, sunalt: $sunalt, rad1h: $rad1h, wcc: $wcc, rr1c: $rr1c, pvrl: $pvrl, temp: $temp"; $sq .= "$idx => hod: $hod, sunaz: $sunaz, sunalt: $sunalt, rad1h: $rad1h, wcc: $wcc, rr1c: $rr1c, pvrl: $pvrl, temp: $temp";
} }
@ -18184,6 +17955,69 @@ sub _listDataPoolPvHist {
return $sq; return $sq;
} }
################################################################
# Listing des verschiedene Speicher
################################################################
sub _listDataPoolVarious {
my $hash = shift;
my $htol = shift;
my $par = shift // q{};
my $name = $hash->{NAME};
my $func = $htol eq 'consumers' ? \&ConsumerVal :
$htol eq 'inverters' ? \&InverterVal :
$htol eq 'producers' ? \&ProducerVal :
$htol eq 'strings' ? \&StringVal :
$htol eq 'batteries' ? \&BatteryVal :
'';
my $h = $data{$name}{$htol};
if (!keys %{$h}) {
return ucfirst($htol).qq{ cache is empty.};
}
for my $i (keys %{$h}) {
if ($i !~ /^[0-9]{2}$/ix && $htol ne 'strings') { # bereinigen ungültige Position, Forum: https://forum.fhem.de/index.php/topic,117864.msg1173219.html#msg1173219
delete $data{$name}{$htol}{$i};
Log3 ($name, 2, qq{$name - INFO - invalid key "$i" was deleted from }.ucfirst($htol).qq{ storage});
}
}
my $sq;
for my $idx (sort keys %{$h}) {
next if($par && $idx ne $par);
my ($cret, $s1);
my $sp1 = _ldpspaces ($idx, q{});
for my $ckey (sort keys %{$h->{$idx}}) {
if (ref $h->{$idx}{$ckey} eq 'ARRAY') {
my $aser = join " ", @{$h->{$idx}{$ckey}};
$cret .= ($s1 ? $sp1 : "").$ckey." => ".$aser."\n";
}
if (ref $h->{$idx}{$ckey} eq 'HASH') {
my $hk = qq{};
for my $f (sort {$a<=>$b} keys %{$h->{$idx}{$ckey}}) {
$hk .= " " if($hk);
$hk .= "$f=".$h->{$idx}{$ckey}{$f};
}
$cret .= ($s1 ? $sp1 : "").$ckey." => ".$hk."\n";
}
else {
$cret .= ($s1 ? $sp1 : "").$ckey." => ". &{$func} ($hash, $idx, $ckey, "")."\n";
}
$s1 = 1;
}
$sq .= $idx." => ".$cret."\n";
}
return $sq;
}
################################################################ ################################################################
# Listing des Circular Speichers # Listing des Circular Speichers
################################################################ ################################################################
@ -18341,6 +18175,228 @@ sub _listDataPoolCircular {
return $sq; return $sq;
} }
################################################################
# Listing des NextHours Speicher
################################################################
sub _listDataPoolNextHours {
my $name = shift;
my $par = shift // q{};
my $h = $data{$name}{nexthours};
my $sq;
if (!keys %{$h}) {
return qq{NextHours cache is empty.};
}
for my $idx (sort keys %{$h}) {
my $nhts = NexthoursVal ($name, $idx, 'starttime', '-');
my $hod = NexthoursVal ($name, $idx, 'hourofday', '-');
my $today = NexthoursVal ($name, $idx, 'today', '-');
my $pvfc = NexthoursVal ($name, $idx, 'pvfc', '-');
my $pvapifc = NexthoursVal ($name, $idx, 'pvapifc', '-'); # PV Forecast der API
my $pvaifc = NexthoursVal ($name, $idx, 'pvaifc', '-'); # PV Forecast der KI
my $aihit = NexthoursVal ($name, $idx, 'aihit', '-'); # KI ForeCast Treffer Status
my $wid = NexthoursVal ($name, $idx, 'weatherid', '-');
my $wcc = NexthoursVal ($name, $idx, 'wcc', '-');
my $crang = NexthoursVal ($name, $idx, 'cloudrange', '-');
my $rr1c = NexthoursVal ($name, $idx, 'rr1c', '-');
my $rrange = NexthoursVal ($name, $idx, 'rainrange', '-');
my $rad1h = NexthoursVal ($name, $idx, 'rad1h', '-');
my $pvcorrf = NexthoursVal ($name, $idx, 'pvcorrf', '-');
my $temp = NexthoursVal ($name, $idx, 'temp', '-');
my $confc = NexthoursVal ($name, $idx, 'confc', '-');
my $confcex = NexthoursVal ($name, $idx, 'confcEx', '-');
my $don = NexthoursVal ($name, $idx, 'DoN', '-');
my $sunaz = NexthoursVal ($name, $idx, 'sunaz', '-');
my $sunalt = NexthoursVal ($name, $idx, 'sunalt', '-');
my ($rcdbat, $socs);
for my $bn (1..$maxbatteries) { # alle Batterien
$bn = sprintf "%02d", $bn;
my $rcdcharge = NexthoursVal ($name, $idx, 'rcdchargebat'.$bn, '-');
my $socxx = NexthoursVal ($name, $idx, 'soc'.$bn, '-');
$rcdbat .= ', ' if($rcdbat);
$rcdbat .= "rcdchargebat${bn}: $rcdcharge";
$socs .= ', ' if($socs);
$socs .= "soc${bn}: $socxx";
}
$sq .= "\n" if($sq);
$sq .= $idx." => ";
$sq .= "starttime: $nhts, hourofday: $hod, today: $today";
$sq .= "\n ";
$sq .= "pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit, confc: $confc";
$sq .= "\n ";
$sq .= "confcEx: $confcex, DoN: $don, weatherid: $wid, wcc: $wcc, rr1c: $rr1c, temp=$temp";
$sq .= "\n ";
$sq .= "rad1h: $rad1h, sunaz: $sunaz, sunalt: $sunalt";
$sq .= "\n ";
$sq .= "rrange: $rrange, crange: $crang, correff: $pvcorrf";
$sq .= "\n ";
$sq .= $socs;
$sq .= "\n ";
$sq .= $rcdbat;
}
return $sq;
}
################################################################
# Listing des Qualities Speicher
################################################################
sub _listDataPoolQualities {
my $name = shift;
my $par = shift // q{};
my $h = $data{$name}{nexthours};
my $sq;
if (!keys %{$h}) {
return qq{NextHours cache is empty.};
}
for my $idx (sort keys %{$h}) {
my $nhfc = NexthoursVal ($name, $idx, 'pvfc', undef);
next if(!$nhfc);
my $nhts = NexthoursVal ($name, $idx, 'starttime', '-');
my $pvcorrf = NexthoursVal ($name, $idx, 'pvcorrf', '-/-');
my $aihit = NexthoursVal ($name, $idx, 'aihit', '-');
my $pvfc = NexthoursVal ($name, $idx, 'pvfc', '-');
my $wcc = NexthoursVal ($name, $idx, 'wcc', '-');
my $sunalt = NexthoursVal ($name, $idx, 'sunalt', '-');
my ($f,$q) = split "/", $pvcorrf;
$sq .= "\n" if($sq);
$sq .= "Start: $nhts, Quality: $q, Factor: $f, AI usage: $aihit, PV expect: $pvfc Wh, Sun Alt: $sunalt, Cloud: $wcc";
}
return $sq;
}
################################################################
# Listing des Current Speicher
################################################################
sub _listDataPoolCurrent {
my $name = shift;
my $par = shift // q{};
my $h = $data{$name}{current};
my $sq;
if (!keys %{$h}) {
return qq{Current values cache is empty.};
}
for my $idx (sort keys %{$h}) {
if (ref $h->{$idx} eq 'ARRAY') {
my $aser = join " ",@{$h->{$idx}};
$sq .= $idx." => ".$aser."\n";
}
elsif (ref $h->{$idx} eq 'HASH') {
my $s1;
my $sp1 = _ldpspaces ($idx, q{});
$sq .= $idx." => ";
for my $idx1 (sort keys %{$h->{$idx}}) {
if (ref $h->{$idx}{$idx1} eq 'HASH') {
my $s2;
my $sp2 = _ldpspaces ($idx1, $sp1);
$sq .= ($s1 ? $sp1 : "").$idx1." => ";
for my $idx2 (sort keys %{$h->{$idx}{$idx1}}) {
my $s3;
my $sp3 = _ldpspaces ($idx2, $sp2);
$sq .= ($s2 ? $sp2 : "").$idx2." => ";
if (ref $h->{$idx}{$idx1}{$idx2} eq 'HASH') {
for my $idx3 (sort keys %{$h->{$idx}{$idx1}{$idx2}}) {
$sq .= ($s3 ? $sp3 : "").$idx3." => ".(defined $h->{$idx}{$idx1}{$idx2}{$idx3} ? $h->{$idx}{$idx1}{$idx2}{$idx3} : '')."\n";
$s3 = 1;
}
}
else {
$sq .= (defined $h->{$idx}{$idx1}{$idx2} ? $h->{$idx}{$idx1}{$idx2} : '')."\n";
}
$s1 = 1;
$s2 = 1;
}
}
else {
$sq .= (defined $h->{$idx}{$idx1} ? $h->{$idx}{$idx1} : '')."\n";
}
}
}
else {
$sq .= $idx." => ".(defined $h->{$idx} ? $h->{$idx} : '')."\n";
}
}
return $sq;
}
################################################################
# Listing der APiData Speicher
################################################################
sub _listDataPoolApiData {
my $name = shift;
my $htol = shift;
my $par = shift // q{};
my $h = $data{$name}{solcastapi};
$h = $data{$name}{weatherapi} if($htol eq 'weatherApiData');
$h = $data{$name}{statusapi} if($htol eq 'statusApiData');
if (!keys %{$h}) {
return qq{The API values cache is empty.};
}
my $git = sub {
my $it = shift;
my @sorted = sort { $a cmp $b } keys %$it;
my $key = shift @sorted;
my $ret = {};
$ret = { $key => $it->{$key} } if($key);
return $ret;
};
my $sq;
my $pve = q{};
my $itref = dclone $h; # Deep Copy von $h
for my $idx (sort keys %{$itref}) {
my $s1;
my $sp1 = _ldpspaces ($idx, q{});
$sq .= $idx." => ";
while (my ($tag, $item) = each %{$git->($itref->{$idx})}) {
$sq .= ($s1 ? $sp1 : "").$tag." => ";
if (ref $item eq 'HASH') {
my $s2;
my $sp2 = _ldpspaces ($tag, $sp1);
while (my ($tag1, $item1) = each %{$git->($itref->{$idx}{$tag})}) {
$sq .= ($s2 ? $sp2 : "")."$tag1: ".$item1."\n";
$s2 = 1;
delete $itref->{$idx}{$tag}{$tag1};
}
}
$s1 = 1;
$sq .= "\n" if($sq !~ /\n$/xs);
delete $itref->{$idx}{$tag};
}
}
return $sq;
}
################################################################ ################################################################
# Hashwert aus CircularVal in formatierten String umwandeln # Hashwert aus CircularVal in formatierten String umwandeln
################################################################ ################################################################
@ -20773,22 +20829,29 @@ return ($rapi, $wapi);
sub temp2bin { sub temp2bin {
my $val = shift; my $val = shift;
my $bin = $val > 35 ? 35 : my $bin = $val > 35 ? 35 :
$val > 32 ? 35 : $val > 32 ? 35 :
$val > 30 ? 30 : $val > 30 ? 30 :
$val > 27 ? 30 : $val > 27 ? 30 :
$val > 25 ? 25 : $val > 25 ? 25 :
$val > 22 ? 25 : $val > 22 ? 25 :
$val > 20 ? 20 : $val > 20 ? 20 :
$val > 17 ? 20 : $val > 17 ? 20 :
$val > 15 ? 15 : $val > 15 ? 15 :
$val > 12 ? 15 : $val > 12 ? 15 :
$val > 10 ? 10 : $val > 10 ? 10 :
$val > 7 ? 10 : $val > 7 ? 10 :
$val > 5 ? 5 : $val > 5 ? 5 :
$val > 2 ? 5 : $val > 2 ? 5 :
$val > 0 ? 0 : $val > 0 ? 0 :
-5; $val > -2 ? 0 :
$val > -5 ? -5 :
$val > -7 ? -5 :
$val > -10 ? -10 :
$val > -12 ? -10 :
$val > -15 ? -15 :
$val > -17 ? -15 :
-20;
return $bin; return $bin;
} }