76_SolarForecast: showDiff can be set separately for each level

git-svn-id: https://svn.fhem.de/fhem/trunk@30095 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
DS_Starter
2025-07-04 20:35:37 +00:00
parent 2b8e8fc5cb
commit fcb7f80ed2
2 changed files with 269 additions and 191 deletions

View File

@@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it # Do not insert empty lines here, update check depends on it
- feature: 76_SolarForecast: showDiff can be set separately for each level
- bugfix: 76_SolarForecast: fix Perl warning in release 1.53.0 - bugfix: 76_SolarForecast: fix Perl warning in release 1.53.0
- feature: 76_SolarForecast: minor release 1.53.0 - feature: 76_SolarForecast: minor release 1.53.0
- feature: 76_SolarForecast: new special Reading conForecastComingNight - feature: 76_SolarForecast: new special Reading conForecastComingNight

View File

@@ -160,6 +160,9 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.53.3" => "04.07.2025 Change of the correction factor calculation to the ratio of real production and the API raw forecast ",
"1.53.2" => "03.07.2025 graphicControl->showDiff can be set separately for each level ".
"setupInverterDevXX: Check that there are no commas with spaces before and after (strings) ",
"1.53.1" => "30.06.2025 add utf8 smileys, fix Perl warning uninitialized value \$color ", "1.53.1" => "30.06.2025 add utf8 smileys, fix Perl warning uninitialized value \$color ",
"1.53.0" => "28.06.2025 new battery style (batcontainer), new key setupBatteryDevXX->label, new reading Battery_ChargeUnrestricted_XX ". "1.53.0" => "28.06.2025 new battery style (batcontainer), new key setupBatteryDevXX->label, new reading Battery_ChargeUnrestricted_XX ".
"attribute graphicShowDiff replaced by graphicControl->showDiff ". "attribute graphicShowDiff replaced by graphicControl->showDiff ".
@@ -6487,17 +6490,18 @@ sub _attrgraphicControl { ## no critic "not used"
my $cmd = $paref->{cmd}; my $cmd = $paref->{cmd};
my $valid = { my $valid = {
beamPaddingBottom => { comp => '\d+', act => 0 }, beamPaddingBottom => { comp => '\d+', act => 0 },
beamPaddingTop => { comp => '\d+', act => 0 }, beamPaddingTop => { comp => '\d+', act => 0 },
beamWidth => { comp => '([2-9][0-9]|100)', act => 0 }, beamWidth => { comp => '([2-9][0-9]|100)', act => 0 },
energyUnit => { comp => '(Wh|kWh)', act => 0 }, energyUnit => { comp => '(Wh|kWh)', act => 0 },
headerDetail => { comp => '.*', act => 1 }, headerDetail => { comp => '.*', act => 1 },
hourCount => { comp => '([4-9]|1[0-9]|2[0-4])', act => 0 }, hourCount => { comp => '([4-9]|1[0-9]|2[0-4])', act => 0 },
hourStyle => { comp => ':(0{1,2})', act => 0 }, hourStyle => { comp => ':(0{1,2})', act => 0 },
layoutType => { comp => '(single|double|diff)', act => 0 }, layoutType => { comp => '(single|double|diff)', act => 0 },
scaleMode => { comp => '(?:[1-3]:(?:log|lin))(?:,(?:[1-3]:(?:log|lin)))*', act => 0 }, scaleMode => { comp => '(?:[1-3]:(?:log|lin))(?:,(?:[1-3]:(?:log|lin)))*', act => 0 },
showDiff => { comp => '(no|top|bottom)', act => 0 }, #showDiff => { comp => '(no|top|bottom)', act => 0 },
spaceSize => { comp => '\d+', act => 0 }, showDiff => { comp => '(?:[1-3]:(?:top|bottom))(?:,(?:[1-3]:(?:top|bottom)))*', act => 0 },
spaceSize => { comp => '\d+', act => 0 },
}; };
my ($a, $h) = parseParams ($aVal); my ($a, $h) = parseParams ($aVal);
@@ -6952,7 +6956,11 @@ sub _attrInverterDev { ## no critic "not used"
asynchron => { comp => '(0|1)', act => 0 }, asynchron => { comp => '(0|1)', act => 0 },
}; };
if ($paref->{cmd} eq 'set') { if ($paref->{cmd} eq 'set') {
if ($aVal =~ /strings=/xs && $aVal !~ /strings=(?!.*(\s,|,\s)).*$/xs) {
return "The key 'string' is not specified correctly. Please refer to the command reference.";
}
my ($err, $indev, $h) = isDeviceValid ( { name => $name, obj => $aVal, method => 'string' } ); my ($err, $indev, $h) = isDeviceValid ( { name => $name, obj => $aVal, method => 'string' } );
return $err if($err); return $err if($err);
@@ -10305,9 +10313,9 @@ sub _transferAPIRadiationValues {
$sunaz = NexthoursVal ($name, $nhtstr, 'sunaz', 0); $sunaz = NexthoursVal ($name, $nhtstr, 'sunaz', 0);
} }
$paref->{sabin} = sunalt2bin ($sunalt); $paref->{sabin} = sunalt2bin ($sunalt);
my $pvapifc = __calcPVestimates ($paref); # API Wert ermitteln my ($pvapifc, $pvapifcraw) = __calcPVestimates ($paref); # API Wert mit Korrekturfaktor und ohne KF ermitteln
my ($msg, $pvaifc) = aiGetResult ($paref); # KI Entscheidungen abfragen my ($msg, $pvaifc) = aiGetResult ($paref); # KI Entscheidungen abfragen
delete $paref->{fd}; delete $paref->{fd};
delete $paref->{fh1}; delete $paref->{fh1};
@@ -10365,18 +10373,22 @@ sub _transferAPIRadiationValues {
debugLog ($paref, 'aiData', "use PV from API (no AI or AI result tolerance overflow) -> hod: $hod, Rad1h: ".(defined $rad1h ? $rad1h : '-').", pvfc: $pvfc Wh"); debugLog ($paref, 'aiData', "use PV from API (no AI or AI result tolerance overflow) -> hod: $hod, Rad1h: ".(defined $rad1h ? $rad1h : '-').", pvfc: $pvfc Wh");
} }
$data{$name}{nexthours}{$nhtstr}{pvapifc} = $pvapifc; # durch API gelieferte PV Forecast $data{$name}{nexthours}{$nhtstr}{pvapifc} = $pvapifc; # durch API gelieferte PV Forecast mit Korrekturfaktor
$data{$name}{nexthours}{$nhtstr}{pvfc} = $pvfc; # resultierende PV Forecast zuweisen $data{$name}{nexthours}{$nhtstr}{pvapifcraw} = $pvapifcraw; # durch API gelieferte PV Forecast Raw
$data{$name}{nexthours}{$nhtstr}{pvfc} = $pvfc; # resultierende PV Forecast zuweisen
my $hh1 = sprintf "%02d", $fh1;
if ($num < 23 && $fh < 24) { # Ringspeicher PV forecast Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350 if ($num < 23 && $fh < 24) { # Ringspeicher PV forecast Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$data{$name}{circular}{sprintf "%02d",$fh1}{pvapifc} = NexthoursVal ($name, $nhtstr, 'pvapifc', undef); $data{$name}{circular}{$hh1}{pvapifc} = NexthoursVal ($name, $nhtstr, 'pvapifc', undef);
$data{$name}{circular}{sprintf "%02d",$fh1}{pvfc} = $pvfc; $data{$name}{circular}{$hh1}{pvapifcraw} = NexthoursVal ($name, $nhtstr, 'pvapifcraw', undef);
$data{$name}{circular}{sprintf "%02d",$fh1}{pvaifc} = NexthoursVal ($name, $nhtstr, 'pvaifc', undef); $data{$name}{circular}{$hh1}{pvaifc} = NexthoursVal ($name, $nhtstr, 'pvaifc', undef);
$data{$name}{circular}{sprintf "%02d",$fh1}{aihit} = NexthoursVal ($name, $nhtstr, 'aihit', 0); $data{$name}{circular}{$hh1}{aihit} = NexthoursVal ($name, $nhtstr, 'aihit', 0);
$data{$name}{circular}{$hh1}{pvfc} = $pvfc;
} }
if ($fd == 0 && int $pvfc > 0) { # Vorhersagedaten des aktuellen Tages zum manuellen Vergleich in Reading speichern if ($fd == 0 && int $pvfc > 0) { # Vorhersagedaten des aktuellen Tages zum manuellen Vergleich in Reading speichern
storeReading ('Today_Hour'.sprintf ("%02d",$fh1).'_PVforecast', "$pvfc Wh"); storeReading ('Today_Hour'.$hh1.'_PVforecast', "$pvfc Wh");
} }
if ($fd == 0 && $fh1) { if ($fd == 0 && $fh1) {
@@ -10385,7 +10397,7 @@ sub _transferAPIRadiationValues {
} }
} }
storeReading ('.lastupdateForecastValues', $t); # Statusreading letzter update storeReading ('.lastupdateForecastValues', $t); # Statusreading letzter update
return; return;
} }
@@ -10463,8 +10475,9 @@ sub __calcPVestimates {
delete $paref->{wcc}; delete $paref->{wcc};
my ($lh,$sq,$peakloss, $modtemp); my ($lh,$sq,$peakloss, $modtemp);
my $pvsum = 0; my $pvsum = 0;
my $peaksum = 0; my $peaksum = 0;
my $pvsumraw = 0;
my %sum; my %sum;
for my $string (sort keys %{$data{$name}{strings}}) { for my $string (sort keys %{$data{$name}{strings}}) {
@@ -10492,6 +10505,7 @@ sub __calcPVestimates {
if ($istrings eq 'all' || grep /^$string$/, (split ',', $istrings)) { if ($istrings eq 'all' || grep /^$string$/, (split ',', $istrings)) {
$sum{$in}{pvinvsum} += $pv; $sum{$in}{pvinvsum} += $pv;
$sum{$in}{pvrawsum} += $pvest; # PV Prognose ohne Faktorenanwendung
$sum{$in}{string} = defined $sum{$in}{string} ? $sum{$in}{string}.','.$string : $string; $sum{$in}{string} = defined $sum{$in}{string} ? $sum{$in}{string}.','.$string : $string;
} }
} }
@@ -10524,6 +10538,11 @@ sub __calcPVestimates {
for my $ins (keys %sum) { for my $ins (keys %sum) {
my $cap = InverterVal ($name, $ins, 'invertercap', 0); # Max. Leistung des Inverters my $cap = InverterVal ($name, $ins, 'invertercap', 0); # Max. Leistung des Inverters
my $pvinvsum = $sum{$ins}{pvinvsum}; my $pvinvsum = $sum{$ins}{pvinvsum};
my $pvrawsum = $sum{$ins}{pvrawsum};
if ($pvrawsum > $cap) {
$pvrawsum = $cap;
}
if ($pvinvsum > $cap) { if ($pvinvsum > $cap) {
$pvinvsum = $cap; # betreffende Strings auf WR Kapazität begrenzen $pvinvsum = $cap; # betreffende Strings auf WR Kapazität begrenzen
@@ -10531,12 +10550,15 @@ sub __calcPVestimates {
debugLog ($paref, "radiationProcess", "String(s) ".$sum{$ins}{string}." in total limited to $cap Wh due to inverter $ins capacity"); debugLog ($paref, "radiationProcess", "String(s) ".$sum{$ins}{string}." in total limited to $cap Wh due to inverter $ins capacity");
} }
$pvsum += $pvinvsum; $pvsum += $pvinvsum;
$pvsumraw += $pvrawsum; # PV Prognose ohne Faktorenanwendung
} }
$data{$name}{current}{allstringspeak} = $peaksum; # temperaturbedingte Korrektur der installierten Peakleistung in W $data{$name}{current}{allstringspeak} = $peaksum; # temperaturbedingte Korrektur der installierten Peakleistung in W
$pvsum = $peaksum if($peaksum && $pvsum > $peaksum); # Vorhersage nicht größer als die Summe aller PV-Strings Peak $pvsum = $peaksum if($peaksum && $pvsum > $peaksum); # Vorhersage nicht größer als die Summe aller PV-Strings Peak
$pvsum = sprintf "%.0f", $pvsum; $pvsum = sprintf "%.0f", $pvsum;
$pvsumraw = $peaksum if($peaksum && $pvsumraw > $peaksum);
$pvsumraw = sprintf "%.0f", $pvsumraw;
if ($debug =~ /radiationProcess/xs) { if ($debug =~ /radiationProcess/xs) {
$lh = { # Log-Hash zur Ausgabe $lh = { # Log-Hash zur Ausgabe
@@ -10557,7 +10579,7 @@ sub __calcPVestimates {
Log3 ($name, 1, "$name DEBUG> PV API estimate for $reld Hour ".sprintf ("%02d", $hod)." summary: \n$sq"); Log3 ($name, 1, "$name DEBUG> PV API estimate for $reld Hour ".sprintf ("%02d", $hod)." summary: \n$sq");
} }
return $pvsum; return ($pvsum, $pvsumraw);
} }
###################################################################### ######################################################################
@@ -14092,77 +14114,6 @@ sub _calcDataEveryFullHour {
return; return;
} }
################################################################
# PV Ist/Forecast ermitteln und Korrekturfaktoren, Qualität
# in Abhängigkeit Bewölkung errechnen und speichern (komplex)
################################################################
sub _calcCaQcomplex {
my $paref = shift;
my $name = $paref->{name};
my $debug = $paref->{debug};
my $acu = $paref->{acu};
my $pvrlvd = $paref->{pvrlvd}; # PV-Wert valide 1/0
my $h = $paref->{h};
my $day = $paref->{day}; # aktueller Tag
my $yday = $paref->{yday}; # vorheriger Tag (falls gesetzt)
my $aihit = $paref->{aihit};
if (!$pvrlvd) {
debugLog ($paref, 'pvCorrectionWrite', "real PV generation is marked as invalid for hour: $h -> skip the recalculation of the complex correction factor");
return;
}
my $hh = sprintf "%02d", $h;
my $pvrl = CircularVal ($name, $hh, 'pvrl', 0); # real erzeugte PV Energie am Ende der vorherigen Stunde
my $pvfc = CircularVal ($name, $hh, 'pvapifc', 0); # vorhergesagte PV Energie am Ende der vorherigen Stunde
if (!$pvrl || !$pvfc) {
return;
}
my $chwcc = HistoryVal ($name, $day, $hh, 'wcc', 0); # Wolkenbedeckung heute & abgefragte Stunde
my $sunalt = HistoryVal ($name, $day, $hh, 'sunalt', 0); # Sonne Altitude
my $crang = cloud2bin ($chwcc);
my $sabin = sunalt2bin ($sunalt);
## Speicherarrays schreiben
#############################
push @{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}}, $pvrl;
push @{$data{$name}{circular}{$hh}{'pvfc_'.$sabin}{"$crang"}}, $pvfc;
removeMinMaxArray ($data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}, SPLSLIDEMAX);
removeMinMaxArray ($data{$name}{circular}{$hh}{'pvfc_'.$sabin}{"$crang"}, SPLSLIDEMAX);
## neuen Korrekturfaktor berechnen
####################################
$paref->{pvrl} = $pvrl;
$paref->{pvfc} = $pvfc;
$paref->{crang} = $crang;
$paref->{sabin} = $sabin;
$paref->{calc} = 'Complex';
my ($oldfac, $factor, $dnum) = __calcNewFactor_migrated ($paref); # migrierte Daten verwenden
delete $paref->{pvrl};
delete $paref->{pvfc};
delete $paref->{crang};
delete $paref->{sabin};
delete $paref->{calc};
$aihit = $aihit ? ' AI result used,' : '';
if ($acu =~ /on_complex/xs) {
if ($paref->{cpcf} !~ /manual/xs) { # pcf-Reading nur überschreiben wenn nicht 'manual xxx' gesetzt
storeReading ('pvCorrectionFactor_'.$hh, $factor." (automatic - old factor: $oldfac,$aihit Sun Alt range: $sabin, Cloud range: $crang, Days in range: $dnum)");
}
else {
storeReading ('pvCorrectionFactor_'.$hh, $paref->{cpcf}." / flexmatic result $factor for Sun Alt range: $sabin,$aihit Cloud range: $crang, Days in range: $dnum");
}
}
return;
}
################################################################ ################################################################
# PV Ist/Forecast ermitteln und Korrekturfaktoren, Qualität # PV Ist/Forecast ermitteln und Korrekturfaktoren, Qualität
# ohne Nebenfaktoren errechnen und speichern (simple) # ohne Nebenfaktoren errechnen und speichern (simple)
@@ -14183,27 +14134,30 @@ sub _calcCaQsimple {
return; return;
} }
my $hh = sprintf "%02d", $h; my $hh = sprintf "%02d", $h;
my $pvrl = CircularVal ($name, $hh, 'pvrl', 0); my $pvrl = CircularVal ($name, $hh, 'pvrl', 0);
my $pvfc = CircularVal ($name, $hh, 'pvapifc', 0); my $pvapifc = CircularVal ($name, $hh, 'pvapifc', 0); # vorhergesagte PV Energie incl. Korrekturfaktoren am Ende der vorherigen Stunde
my $pvapifcraw = CircularVal ($name, $hh, 'pvapifcraw', 0); # vorhergesagte PV Energie (raw) am Ende der vorherigen Stunde
if (!$pvrl || !$pvfc) { if (!$pvrl || !$pvapifcraw) {
return; return;
} }
my $sunalt = HistoryVal ($name, $day, $hh, 'sunalt', 0); # Sonne Altitude my $sunalt = HistoryVal ($name, $day, $hh, 'sunalt', 0); # Sonne Altitude
my $sabin = sunalt2bin ($sunalt); my $sabin = sunalt2bin ($sunalt);
$paref->{pvrl} = $pvrl; $paref->{pvrl} = $pvrl;
$paref->{pvfc} = $pvfc; $paref->{pvapifc} = $pvapifc;
$paref->{sabin} = $sabin; $paref->{pvapifcraw} = $pvapifcraw;
$paref->{crang} = 'simple'; $paref->{sabin} = $sabin;
$paref->{calc} = 'Simple'; $paref->{crang} = 'simple';
$paref->{calc} = 'Simple';
my ($oldfac, $factor, $dnum) = __calcNewFactor_migrated ($paref); # migrierte Daten verwenden my ($oldfac, $factor, $dnum) = __calcNewFactor_migrated ($paref); # migrierte Daten verwenden
delete $paref->{pvrl}; delete $paref->{pvrl};
delete $paref->{pvfc}; delete $paref->{pvapifc};
delete $paref->{pvapifcraw};
delete $paref->{sabin}; delete $paref->{sabin};
delete $paref->{crang}; delete $paref->{crang};
delete $paref->{calc}; delete $paref->{calc};
@@ -14222,6 +14176,80 @@ sub _calcCaQsimple {
return; return;
} }
################################################################
# PV Ist/Forecast ermitteln und Korrekturfaktoren, Qualität
# in Abhängigkeit Bewölkung errechnen und speichern (komplex)
################################################################
sub _calcCaQcomplex {
my $paref = shift;
my $name = $paref->{name};
my $debug = $paref->{debug};
my $acu = $paref->{acu};
my $pvrlvd = $paref->{pvrlvd}; # PV-Wert valide 1/0
my $h = $paref->{h};
my $day = $paref->{day}; # aktueller Tag
my $yday = $paref->{yday}; # vorheriger Tag (falls gesetzt)
my $aihit = $paref->{aihit};
if (!$pvrlvd) {
debugLog ($paref, 'pvCorrectionWrite', "real PV generation is marked as invalid for hour: $h -> skip the recalculation of the complex correction factor");
return;
}
my $hh = sprintf "%02d", $h;
my $pvrl = CircularVal ($name, $hh, 'pvrl', 0); # real erzeugte PV Energie am Ende der vorherigen Stunde
my $pvapifc = CircularVal ($name, $hh, 'pvapifc', 0); # vorhergesagte PV Energie incl. Korrekturfaktoren am Ende der vorherigen Stunde
my $pvapifcraw = CircularVal ($name, $hh, 'pvapifcraw', 0); # vorhergesagte PV Energie (raw) am Ende der vorherigen Stunde
if (!$pvrl || !$pvapifcraw) {
return;
}
my $chwcc = HistoryVal ($name, $day, $hh, 'wcc', 0); # Wolkenbedeckung heute & abgefragte Stunde
my $sunalt = HistoryVal ($name, $day, $hh, 'sunalt', 0); # Sonne Altitude
my $crang = cloud2bin ($chwcc);
my $sabin = sunalt2bin ($sunalt);
## Speicherarrays schreiben
#############################
push @{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}}, $pvrl;
push @{$data{$name}{circular}{$hh}{'pvfc_'.$sabin}{"$crang"}}, $pvapifcraw;
removeMinMaxArray ($data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}, SPLSLIDEMAX);
removeMinMaxArray ($data{$name}{circular}{$hh}{'pvfc_'.$sabin}{"$crang"}, SPLSLIDEMAX);
## neuen Korrekturfaktor berechnen
####################################
$paref->{pvrl} = $pvrl;
$paref->{pvapifc} = $pvapifc;
$paref->{pvapifcraw} = $pvapifcraw;
$paref->{crang} = $crang;
$paref->{sabin} = $sabin;
$paref->{calc} = 'Complex';
my ($oldfac, $factor, $dnum) = __calcNewFactor_migrated ($paref); # migrierte Daten verwenden
delete $paref->{pvrl};
delete $paref->{pvapifc};
delete $paref->{pvapifcraw};
delete $paref->{crang};
delete $paref->{sabin};
delete $paref->{calc};
$aihit = $aihit ? ' AI result used,' : '';
if ($acu =~ /on_complex/xs) {
if ($paref->{cpcf} !~ /manual/xs) { # pcf-Reading nur überschreiben wenn nicht 'manual xxx' gesetzt
storeReading ('pvCorrectionFactor_'.$hh, $factor." (automatic - old factor: $oldfac,$aihit Sun Alt range: $sabin, Cloud range: $crang, Days in range: $dnum)");
}
else {
storeReading ('pvCorrectionFactor_'.$hh, $paref->{cpcf}." / flexmatic result $factor for Sun Alt range: $sabin,$aihit Cloud range: $crang, Days in range: $dnum");
}
}
return;
}
################################################################ ################################################################
# den Hausverbrauch der vergangenen Stunde zum con-Array # den Hausverbrauch der vergangenen Stunde zum con-Array
# im Circular Speicher hinzufügen # im Circular Speicher hinzufügen
@@ -14257,14 +14285,15 @@ return;
# den neuen Korrekturfaktur berechnen (neue Median Funktion) # den neuen Korrekturfaktur berechnen (neue Median Funktion)
################################################################ ################################################################
sub __calcNewFactor_migrated { sub __calcNewFactor_migrated {
my $paref = shift; my $paref = shift;
my $name = $paref->{name}; my $name = $paref->{name};
my $pvrl = $paref->{pvrl}; my $pvrl = $paref->{pvrl};
my $pvfc = $paref->{pvfc}; my $pvapifc = $paref->{pvapifc};
my $crang = $paref->{crang}; my $pvfcraw = $paref->{pvapifcraw};
my $sabin = $paref->{sabin}; my $crang = $paref->{crang};
my $h = $paref->{h}; my $sabin = $paref->{sabin};
my $calc = $paref->{calc}; my $h = $paref->{h};
my $calc = $paref->{calc};
my $hash = $defs{$name}; my $hash = $defs{$name};
my ($factor, $pvcirc, $fccirc, $pvrlsum, $pvfcsum, $dnum); my ($factor, $pvcirc, $fccirc, $pvrlsum, $pvfcsum, $dnum);
@@ -14283,30 +14312,30 @@ sub __calcNewFactor_migrated {
if ($dnum) { # Werte in History vorhanden -> haben Prio ! if ($dnum) { # Werte in History vorhanden -> haben Prio !
$dnum++; $dnum++;
$pvrlsum = $pvrl + $pvcirc; $pvrlsum = $pvrl + $pvcirc;
$pvfcsum = $pvfc + $fccirc; $pvfcsum = $pvfcraw + $fccirc;
$pvrl = $pvrlsum / $dnum; $pvrl = $pvrlsum / $dnum;
$pvfc = $pvfcsum / $dnum; $pvfcraw = $pvfcsum / $dnum;
$factor = sprintf "%.2f", ($pvrl / $pvfc); # Faktorberechnung: reale PV / Prognose $factor = sprintf "%.2f", ($pvrl / $pvfcraw); # Faktorberechnung: reale PV / Prognose
} }
elsif ($oldfac && (!$pvcirc || !$fccirc)) { # Circular Hash liefert einen vorhandenen Korrekturfaktor aber keine gespeicherten PV-Werte elsif ($oldfac && (!$pvcirc || !$fccirc)) { # Circular Hash liefert einen vorhandenen Korrekturfaktor aber keine gespeicherten PV-Werte
$dnum = 1; $dnum = 1;
$factor = sprintf "%.2f", ($pvrl / $pvfc); $factor = sprintf "%.2f", ($pvrl / $pvfcraw);
$factor = sprintf "%.2f", ($factor + $oldfac) / 2; $factor = sprintf "%.2f", ($factor + $oldfac) / 2;
} }
else { # ganz neuer Wert else { # ganz neuer Wert
$dnum = 1; $dnum = 1;
$factor = sprintf "%.2f", ($pvrl / $pvfc); $factor = sprintf "%.2f", ($pvrl / $pvfcraw);
} }
} }
else { else {
$pvrl = medianArray (\@{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}}); # neuen Median berechnen $pvrl = medianArray (\@{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}}); # neuen Median berechnen
$pvfc = medianArray (\@{$data{$name}{circular}{$hh}{'pvfc_'.$sabin}{"$crang"}}); # neuen Median berechnen $pvfcraw = medianArray (\@{$data{$name}{circular}{$hh}{'pvfc_'.$sabin}{"$crang"}}); # neuen Median berechnen
$factor = 0; $factor = 0;
$dnum = scalar (@{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}}); $dnum = scalar (@{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}});
$factor = sprintf "%.2f", ($pvrl / $pvfc) if($pvrl && $pvfc); # devision by zero Forum: https://forum.fhem.de/index.php?msg=1341884 $factor = sprintf "%.2f", ($pvrl / $pvfcraw) if($pvrl && $pvfcraw); # devision by zero Forum: https://forum.fhem.de/index.php?msg=1341884
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> read stored values: PVreal median: $pvrl, PVforecast median: $pvfc, days: $dnum"); debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> read stored values: PVreal median: $pvrl, PVforecast median: $pvfcraw, days: $dnum");
} }
$factor = 1.00 if(1 * $factor == 0); # 0.00-Werte ignorieren (Schleifengefahr) $factor = 1.00 if(1 * $factor == 0); # 0.00-Werte ignorieren (Schleifengefahr)
@@ -14324,7 +14353,7 @@ sub __calcNewFactor_migrated {
## Qualität berechnen ## Qualität berechnen
####################### #######################
$oldfac = sprintf "%.2f", $oldfac; $oldfac = sprintf "%.2f", $oldfac;
my $qual = __calcFcQuality ($pvfc, $pvrl); # Qualität der Vorhersage für die vergangene Stunde my $qual = __calcFcQuality ($pvapifc, $pvrl); # Qualität der Vorhersage für die vergangene Stunde
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> determined values - hour: $hh, Sun Altitude range: $sabin, Cloud range: $crang, old factor: $oldfac, new factor: $factor, days: $dnum"); debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> determined values - hour: $hh, Sun Altitude range: $sabin, Cloud range: $crang, old factor: $oldfac, new factor: $factor, days: $dnum");
debugLog ($paref, 'pvCorrectionWrite|saveData2Cache', "$calc Corrf -> write correction values into Circular - hour: $hh, Sun Altitude range: $sabin, Cloud range: $crang, factor: $factor, quality: $qual, days: $dnum"); debugLog ($paref, 'pvCorrectionWrite|saveData2Cache', "$calc Corrf -> write correction values into Circular - hour: $hh, Sun Altitude range: $sabin, Cloud range: $crang, factor: $factor, quality: $qual, days: $dnum");
@@ -14351,12 +14380,12 @@ return ($oldfac, $factor, $dnum);
# Qualität der Vorhersage berechnen # Qualität der Vorhersage berechnen
################################################################ ################################################################
sub __calcFcQuality { sub __calcFcQuality {
my $pvfc = shift; # PV Vorhersagewert my $pvapifc = shift; # PV Vorhersagewert
my $pvrl = shift; # PV reale Erzeugung my $pvrl = shift; # PV reale Erzeugung
return if(!$pvfc || !$pvrl); return if(!$pvapifc || !$pvrl);
my $diff = $pvfc - $pvrl; my $diff = $pvapifc - $pvrl;
my $hdv = 1 - abs ($diff / $pvrl); # Abweichung der Stunde, 1 = bestmöglicher Wert my $hdv = 1 - abs ($diff / $pvrl); # Abweichung der Stunde, 1 = bestmöglicher Wert
$hdv = $hdv < 0 ? 0 : $hdv; $hdv = $hdv < 0 ? 0 : $hdv;
@@ -14985,7 +15014,6 @@ sub entryGraphic {
colorw => AttrVal ($name, 'graphicWeatherColor', WTHCOLDDEF), # Wetter Icon Farbe Tag colorw => AttrVal ($name, 'graphicWeatherColor', WTHCOLDDEF), # Wetter Icon Farbe Tag
colorwn => AttrVal ($name, 'graphicWeatherColorNight', WTHCOLNDEF), # Wetter Icon Farbe Nacht colorwn => AttrVal ($name, 'graphicWeatherColorNight', WTHCOLNDEF), # Wetter Icon Farbe Nacht
wlalias => AttrVal ($name, 'alias', $name), wlalias => AttrVal ($name, 'alias', $name),
show_diff => CurrentVal ($name, 'showDiff', 'no'), # zusätzliche Anzeige $di{} in allen Typen
lotype => CurrentVal ($name, 'layoutType', 'double'), lotype => CurrentVal ($name, 'layoutType', 'double'),
hourstyle => CurrentVal ($name, 'hourStyle', ''), hourstyle => CurrentVal ($name, 'hourStyle', ''),
hdrDetail => CurrentVal ($name, 'headerDetail', 'all'), # ermöglicht den Inhalt zu begrenzen, um bspw. passgenau in ftui einzubetten hdrDetail => CurrentVal ($name, 'headerDetail', 'all'), # ermöglicht den Inhalt zu begrenzen, um bspw. passgenau in ftui einzubetten
@@ -15079,7 +15107,8 @@ sub entryGraphic {
## Balkengrafiken ## Balkengrafiken
################################################################################### ###################################################################################
my $scm = _parseScaleModes ($name); # Scale Modes auflösen my $scm = _parseScaleModes ($name); # Scale Modes auflösen
my $sdf = _parseShowdiffModes ($name);
## Balkengrafik Ebene 1 ## Balkengrafik Ebene 1
######################### #########################
@@ -15087,6 +15116,7 @@ sub entryGraphic {
my %hfcg1; my %hfcg1;
$paref->{chartlvl} = 1; # Balkengrafik Ebene 1 $paref->{chartlvl} = 1; # Balkengrafik Ebene 1
$paref->{scm} = $scm->{1}; # Scale Mode Level 1 $paref->{scm} = $scm->{1}; # Scale Mode Level 1
$paref->{showdiff} = $sdf->{1}; # show Diff Mode Level 1
$paref->{hfcg} = \%hfcg1; # hfcg = hash forecast graphic $paref->{hfcg} = \%hfcg1; # hfcg = hash forecast graphic
## Werte aktuelle Stunde ## Werte aktuelle Stunde
@@ -15125,6 +15155,7 @@ sub entryGraphic {
$paref->{chartlvl} = 2; $paref->{chartlvl} = 2;
$paref->{scm} = $scm->{2}; # Scale Mode Level 2 $paref->{scm} = $scm->{2}; # Scale Mode Level 2
$paref->{showdiff} = $sdf->{2}; # show Diff Mode Level 2
$paref->{beam1cont} = $paref->{beam3cont}; $paref->{beam1cont} = $paref->{beam3cont};
$paref->{beam2cont} = $paref->{beam4cont}; $paref->{beam2cont} = $paref->{beam4cont};
$paref->{colorb1} = AttrVal ($name, 'graphicBeam3Color', B3COLDEF); $paref->{colorb1} = AttrVal ($name, 'graphicBeam3Color', B3COLDEF);
@@ -15168,6 +15199,7 @@ sub entryGraphic {
$paref->{chartlvl} = 3; $paref->{chartlvl} = 3;
$paref->{scm} = $scm->{3}; # Scale Mode Level 3 $paref->{scm} = $scm->{3}; # Scale Mode Level 3
$paref->{showdiff} = $sdf->{3}; # show Diff Mode Level 3
$paref->{beam1cont} = $paref->{beam5cont}; $paref->{beam1cont} = $paref->{beam5cont};
$paref->{beam2cont} = $paref->{beam6cont}; $paref->{beam2cont} = $paref->{beam6cont};
$paref->{colorb1} = AttrVal ($name, 'graphicBeam5Color', B5COLDEF); $paref->{colorb1} = AttrVal ($name, 'graphicBeam5Color', B5COLDEF);
@@ -15366,7 +15398,7 @@ return;
} }
################################################################ ################################################################
# Parsed den Scale Mode für jede Balkengrafik Ebene # Parse den Scale Mode für jede Balkengrafik Ebene
# z.B. scaleMode=1:log,2:lin,3:lin # z.B. scaleMode=1:log,2:lin,3:lin
################################################################ ################################################################
sub _parseScaleModes { sub _parseScaleModes {
@@ -15392,6 +15424,43 @@ sub _parseScaleModes {
return $scm; return $scm;
} }
################################################################
# Parse den Diff Mode für jede Balkengrafik Ebene
# z.B. showDiff=1:top,2:bottom,3:bottom
################################################################
sub _parseShowdiffModes {
my $name = shift;
my $sdf;
for my $bl (1..MAXBEAMLEVEL) { # Hashref Diff Modes initial mit Standard füllen
$sdf->{"$bl"} = '';
}
my $mo = CurrentVal ($name, 'showDiff', '');
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !! 03.07.
###########################################################################################
if ($mo) {
$mo = $mo eq 'no' ? qq{1:'',2:'',3:''} :
$mo eq 'top' ? qq{1:top,2:top,3:top} :
$mo eq 'bottom' ? qq{1:bottom,2:bottom,3:bottom} :
$mo;
}
##########################################################################################
if ($mo) {
my @moa = split ',', $mo;
for my $elem (@moa) {
my ($lvl, $mode) = split ':', $elem;
$sdf->{"$lvl"} = $mode;
}
}
return $sdf;
}
################################################################ ################################################################
# forecastGraphic Headerzeile generieren # forecastGraphic Headerzeile generieren
################################################################ ################################################################
@@ -16747,7 +16816,7 @@ sub _beamGraphicFirstHour {
$hfcg->{0}{beam1} //= 0; $hfcg->{0}{beam1} //= 0;
$hfcg->{0}{beam2} //= 0; $hfcg->{0}{beam2} //= 0;
$hfcg->{0}{diff} = sprintf "%.1f", ($hfcg->{0}{beam1} - $hfcg->{0}{beam2}); $hfcg->{0}{diff} = sprintf "%.1f", ($hfcg->{0}{beam1} - $hfcg->{0}{beam2});
$hfcg->{0}{diff} = sprintf "%.0f", $hfcg->{0}{diff} if(int ($hfcg->{0}{diff}) - $hfcg->{0}{diff} == 0); $hfcg->{0}{diff} = sprintf "%.0f", $hfcg->{0}{diff} if(($hfcg->{0}{beam1} - $hfcg->{0}{beam2}) * 1 == 0);
my $epc = CurrentVal ($hash, 'ePurchasePriceCcy', 0); my $epc = CurrentVal ($hash, 'ePurchasePriceCcy', 0);
my $efc = CurrentVal ($hash, 'eFeedInTariffCcy', 0); my $efc = CurrentVal ($hash, 'eFeedInTariffCcy', 0);
@@ -16957,7 +17026,7 @@ sub _beamGraphicRemainingHours {
$hfcg->{$i}{beam1} //= 0; $hfcg->{$i}{beam1} //= 0;
$hfcg->{$i}{beam2} //= 0; $hfcg->{$i}{beam2} //= 0;
$hfcg->{$i}{diff} = sprintf "%.1f", ($hfcg->{$i}{beam1} - $hfcg->{$i}{beam2}); $hfcg->{$i}{diff} = sprintf "%.1f", ($hfcg->{$i}{beam1} - $hfcg->{$i}{beam2});
$hfcg->{$i}{diff} = sprintf "%.0f", $hfcg->{$i}{diff} if(int ($hfcg->{$i}{diff}) - $hfcg->{$i}{diff} == 0); $hfcg->{$i}{diff} = sprintf "%.0f", $hfcg->{$i}{diff} if(($hfcg->{$i}{beam1} - $hfcg->{$i}{beam2}) * 1 == 0);
$maxVal = $hfcg->{$i}{beam1} if($hfcg->{$i}{beam1} > $maxVal); $maxVal = $hfcg->{$i}{beam1} if($hfcg->{$i}{beam1} > $maxVal);
$maxVal = $hfcg->{$i}{beam2} if($hfcg->{$i}{beam2} > $maxVal); $maxVal = $hfcg->{$i}{beam2} if($hfcg->{$i}{beam2} > $maxVal);
@@ -17049,7 +17118,7 @@ sub _beamGraphic {
my $maxhours = $paref->{maxhours}; my $maxhours = $paref->{maxhours};
my $weather = $paref->{weather}; my $weather = $paref->{weather};
my $show_night = $paref->{show_night}; # alle Balken (Spalten) anzeigen ? my $show_night = $paref->{show_night}; # alle Balken (Spalten) anzeigen ?
my $show_diff = $paref->{show_diff}; # zusätzliche Anzeige $di{} in allen Typen my $showdiff = $paref->{showdiff}; # zusätzliche Anzeige $di{} in allen Typen
my $scm = $paref->{scm}; # Scale Mode my $scm = $paref->{scm}; # Scale Mode
my $lotype = $paref->{lotype}; my $lotype = $paref->{lotype};
my $height = $paref->{height}; my $height = $paref->{height};
@@ -17103,7 +17172,7 @@ sub _beamGraphic {
#################################### ####################################
$ret .= __batteryOnBeam ($paref); $ret .= __batteryOnBeam ($paref);
if ($show_diff eq 'top') { # Zusätzliche Zeile Ertrag - Verbrauch if ($showdiff eq 'top') { # Zusätzliche Zeile Ertrag - Verbrauch
$ret .= "<tr class='$htr{$m}{cl}'><td class='solarfc'></td>"; $ret .= "<tr class='$htr{$m}{cl}'><td class='solarfc'></td>";
my $ii = 0; my $ii = 0;
@@ -17369,7 +17438,7 @@ sub _beamGraphic {
} }
} }
if ($show_diff eq 'bottom') { # zusätzliche diff Anzeige if ($showdiff eq 'bottom') { # zusätzliche diff Anzeige
$val = normBeamWidth ($paref, 'diff', $i, 'beam1'); $val = normBeamWidth ($paref, 'diff', $i, 'beam1');
if ($val ne '&nbsp;') { # negative Zahlen in Fettschrift, 0 aber ohne + if ($val ne '&nbsp;') { # negative Zahlen in Fettschrift, 0 aber ohne +
@@ -20631,24 +20700,25 @@ sub _listDataPoolCircular {
for my $idx (sort keys %{$h}) { for my $idx (sort keys %{$h}) {
next if($par && $idx ne $par); next if($par && $idx ne $par);
my $pvrl = CircularVal ($hash, $idx, 'pvrl', '-'); my $pvrl = CircularVal ($hash, $idx, 'pvrl', '-');
my $pvfc = CircularVal ($hash, $idx, 'pvfc', '-'); my $pvfc = CircularVal ($hash, $idx, 'pvfc', '-');
my $pvrlsum = CircularVal ($hash, $idx, 'pvrlsum', '-'); my $pvrlsum = CircularVal ($hash, $idx, 'pvrlsum', '-');
my $pvfcsum = CircularVal ($hash, $idx, 'pvfcsum', '-'); my $pvfcsum = CircularVal ($hash, $idx, 'pvfcsum', '-');
my $dnumsum = CircularVal ($hash, $idx, 'dnumsum', '-'); my $dnumsum = CircularVal ($hash, $idx, 'dnumsum', '-');
my $pvaifc = CircularVal ($hash, $idx, 'pvaifc', '-'); my $pvaifc = CircularVal ($hash, $idx, 'pvaifc', '-');
my $pvapifc = CircularVal ($hash, $idx, 'pvapifc', '-'); my $pvapifc = CircularVal ($hash, $idx, 'pvapifc', '-'); # PV Forecast der API incl. angewendeten Korrekturfaktor
my $aihit = CircularVal ($hash, $idx, 'aihit', '-'); my $pvapifcraw = CircularVal ($hash, $idx, 'pvapifcraw', '-'); # PV Forecast der API Raw
my $confc = CircularVal ($hash, $idx, 'confc', '-'); my $aihit = CircularVal ($hash, $idx, 'aihit', '-');
my $gcons = CircularVal ($hash, $idx, 'gcons', '-'); my $confc = CircularVal ($hash, $idx, 'confc', '-');
my $gfeedin = CircularVal ($hash, $idx, 'gfeedin', '-'); my $gcons = CircularVal ($hash, $idx, 'gcons', '-');
my $wid = CircularVal ($hash, $idx, 'weatherid', '-'); my $gfeedin = CircularVal ($hash, $idx, 'gfeedin', '-');
my $wtxt = CircularVal ($hash, $idx, 'weathertxt', '-'); my $wid = CircularVal ($hash, $idx, 'weatherid', '-');
my $wccv = CircularVal ($hash, $idx, 'wcc', '-'); my $wtxt = CircularVal ($hash, $idx, 'weathertxt', '-');
my $rr1c = CircularVal ($hash, $idx, 'rr1c', '-'); my $wccv = CircularVal ($hash, $idx, 'wcc', '-');
my $temp = CircularVal ($hash, $idx, 'temp', '-'); my $rr1c = CircularVal ($hash, $idx, 'rr1c', '-');
my $pvcorrf = CircularVal ($hash, $idx, 'pvcorrf', '-'); my $temp = CircularVal ($hash, $idx, 'temp', '-');
my $quality = CircularVal ($hash, $idx, 'quality', '-'); my $pvcorrf = CircularVal ($hash, $idx, 'pvcorrf', '-');
my $quality = CircularVal ($hash, $idx, 'quality', '-');
my $pvcf = _ldchash2val ( {pool => $h, idx => $idx, key => 'pvcorrf', cval => $pvcorrf} ); my $pvcf = _ldchash2val ( {pool => $h, idx => $idx, key => 'pvcorrf', cval => $pvcorrf} );
my $cfq = _ldchash2val ( {pool => $h, idx => $idx, key => 'quality', cval => $quality} ); my $cfq = _ldchash2val ( {pool => $h, idx => $idx, key => 'quality', cval => $quality} );
@@ -20720,7 +20790,7 @@ sub _listDataPoolCircular {
$gconsall .= _ldchash2val ( { pool => $h, idx => $idx, key => $gcoa, cval => $gcaref } ); $gconsall .= _ldchash2val ( { pool => $h, idx => $idx, key => $gcoa, cval => $gcaref } );
} }
$sq .= $idx." => pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit, pvrl: $pvrl"; $sq .= $idx." => pvapifcraw: $pvapifcraw, pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit, pvrl: $pvrl";
$sq .= "\n $bin"; $sq .= "\n $bin";
$sq .= "\n $bout"; $sq .= "\n $bout";
$sq .= "\n confc: $confc, gcons: $gcons, gfeedin: $gfeedin, wcc: $wccv, rr1c: $rr1c"; $sq .= "\n confc: $confc, gcons: $gcons, gfeedin: $gfeedin, wcc: $wccv, rr1c: $rr1c";
@@ -20809,29 +20879,30 @@ sub _listDataPoolNextHours {
} }
for my $idx (sort keys %{$h}) { for my $idx (sort keys %{$h}) {
my $nhts = NexthoursVal ($name, $idx, 'starttime', '-'); my $nhts = NexthoursVal ($name, $idx, 'starttime', '-');
my $day = NexthoursVal ($name, $idx, 'day', '-'); my $day = NexthoursVal ($name, $idx, 'day', '-');
my $hod = NexthoursVal ($name, $idx, 'hourofday', '-'); my $hod = NexthoursVal ($name, $idx, 'hourofday', '-');
my $today = NexthoursVal ($name, $idx, 'today', '-'); my $today = NexthoursVal ($name, $idx, 'today', '-');
my $pvfc = NexthoursVal ($name, $idx, 'pvfc', '-'); my $pvfc = NexthoursVal ($name, $idx, 'pvfc', '-');
my $pvapifc = NexthoursVal ($name, $idx, 'pvapifc', '-'); # PV Forecast der API my $pvapifc = NexthoursVal ($name, $idx, 'pvapifc', '-'); # PV Forecast der API incl. angewendeten Korrekturfaktor
my $pvaifc = NexthoursVal ($name, $idx, 'pvaifc', '-'); # PV Forecast der KI my $pvapifcraw = NexthoursVal ($name, $idx, 'pvapifcraw', '-'); # PV Forecast der API Raw
my $aihit = NexthoursVal ($name, $idx, 'aihit', '-'); # KI ForeCast Treffer Status my $pvaifc = NexthoursVal ($name, $idx, 'pvaifc', '-'); # PV Forecast der KI
my $wid = NexthoursVal ($name, $idx, 'weatherid', '-'); my $aihit = NexthoursVal ($name, $idx, 'aihit', '-'); # KI ForeCast Treffer Status
my $wcc = NexthoursVal ($name, $idx, 'wcc', '-'); my $wid = NexthoursVal ($name, $idx, 'weatherid', '-');
my $crang = NexthoursVal ($name, $idx, 'cloudrange', '-'); my $wcc = NexthoursVal ($name, $idx, 'wcc', '-');
my $rr1c = NexthoursVal ($name, $idx, 'rr1c', '-'); my $crang = NexthoursVal ($name, $idx, 'cloudrange', '-');
my $rrange = NexthoursVal ($name, $idx, 'rainrange', '-'); my $rr1c = NexthoursVal ($name, $idx, 'rr1c', '-');
my $rad1h = NexthoursVal ($name, $idx, 'rad1h', '-'); my $rrange = NexthoursVal ($name, $idx, 'rainrange', '-');
my $pvcorrf = NexthoursVal ($name, $idx, 'pvcorrf', '-'); my $rad1h = NexthoursVal ($name, $idx, 'rad1h', '-');
my $temp = NexthoursVal ($name, $idx, 'temp', '-'); my $pvcorrf = NexthoursVal ($name, $idx, 'pvcorrf', '-');
my $confc = NexthoursVal ($name, $idx, 'confc', '-'); my $temp = NexthoursVal ($name, $idx, 'temp', '-');
my $confcex = NexthoursVal ($name, $idx, 'confcEx', '-'); my $confc = NexthoursVal ($name, $idx, 'confc', '-');
my $don = NexthoursVal ($name, $idx, 'DoN', '-'); my $confcex = NexthoursVal ($name, $idx, 'confcEx', '-');
my $sunaz = NexthoursVal ($name, $idx, 'sunaz', '-'); my $don = NexthoursVal ($name, $idx, 'DoN', '-');
my $sunalt = NexthoursVal ($name, $idx, 'sunalt', '-'); my $sunaz = NexthoursVal ($name, $idx, 'sunaz', '-');
my $socprgs = NexthoursVal ($name, $idx, 'socprogwhsum', '-'); my $sunalt = NexthoursVal ($name, $idx, 'sunalt', '-');
my $dinrang = NexthoursVal ($name, $idx, 'DaysInRange', '-'); my $socprgs = NexthoursVal ($name, $idx, 'socprogwhsum', '-');
my $dinrang = NexthoursVal ($name, $idx, 'DaysInRange', '-');
my ($rcdbat, $socs, $lcintime); my ($rcdbat, $socs, $lcintime);
for my $bn (1..MAXBATTERIES) { # alle Batterien for my $bn (1..MAXBATTERIES) { # alle Batterien
@@ -20851,7 +20922,7 @@ sub _listDataPoolNextHours {
$sq .= $idx." => "; $sq .= $idx." => ";
$sq .= "starttime: $nhts, day: $day, hourofday: $hod, today: $today"; $sq .= "starttime: $nhts, day: $day, hourofday: $hod, today: $today";
$sq .= "\n "; $sq .= "\n ";
$sq .= "pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit"; $sq .= "pvapifcraw: $pvapifcraw, pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit";
$sq .= "\n "; $sq .= "\n ";
$sq .= "confc: $confc, confcEx: $confcex, weatherid: $wid, wcc: $wcc, rr1c: $rr1c, temp=$temp"; $sq .= "confc: $confc, confcEx: $confcex, weatherid: $wid, wcc: $wcc, rr1c: $rr1c, temp=$temp";
$sq .= "\n "; $sq .= "\n ";
@@ -25633,6 +25704,7 @@ to ensure that the system configuration is correct.
<tr><td> <b>DaysInRange</b> </td><td>previously recorded days with comparable sun position and clouds at this time </td></tr> <tr><td> <b>DaysInRange</b> </td><td>previously recorded days with comparable sun position and clouds at this time </td></tr>
<tr><td> <b>DoN</b> </td><td>sunrise and sunset status (0 - night, 1 - day) </td></tr> <tr><td> <b>DoN</b> </td><td>sunrise and sunset status (0 - night, 1 - day) </td></tr>
<tr><td> <b>hourofday</b> </td><td>current hour of the day </td></tr> <tr><td> <b>hourofday</b> </td><td>current hour of the day </td></tr>
<tr><td> <b>pvapifcraw</b> </td><td>expected PV generation (Wh) of the used API (raw) </td></tr>
<tr><td> <b>pvapifc</b> </td><td>expected PV generation (Wh) of the used API incl. a possible correction </td></tr> <tr><td> <b>pvapifc</b> </td><td>expected PV generation (Wh) of the used API incl. a possible correction </td></tr>
<tr><td> <b>pvaifc</b> </td><td>expected PV generation of the AI (Wh) </td></tr> <tr><td> <b>pvaifc</b> </td><td>expected PV generation of the AI (Wh) </td></tr>
<tr><td> <b>pvfc</b> </td><td>PV generation forecast used (Wh) </td></tr> <tr><td> <b>pvfc</b> </td><td>PV generation forecast used (Wh) </td></tr>
@@ -25752,7 +25824,8 @@ to ensure that the system configuration is correct.
<tr><td> <b>initdaybatouttotXX</b> </td><td>initial value of the total energy drawn from the battery XX at the beginning of the current day. (Wh) </td></tr> <tr><td> <b>initdaybatouttotXX</b> </td><td>initial value of the total energy drawn from the battery XX at the beginning of the current day. (Wh) </td></tr>
<tr><td> <b>lastTsMaxSocRchdXX</b> </td><td>Timestamp of last achievement of battery XX SoC >= maxSoC (default 95%) </td></tr> <tr><td> <b>lastTsMaxSocRchdXX</b> </td><td>Timestamp of last achievement of battery XX SoC >= maxSoC (default 95%) </td></tr>
<tr><td> <b>nextTsMaxSocChgeXX</b> </td><td>Timestamp by which the battery XX should reach maxSoC at least once </td></tr> <tr><td> <b>nextTsMaxSocChgeXX</b> </td><td>Timestamp by which the battery XX should reach maxSoC at least once </td></tr>
<tr><td> <b>pvapifc</b> </td><td>expected PV generation (Wh) of the API used </td></tr> <tr><td> <b>pvapifcraw</b> </td><td>expected PV generation (Wh) of the API used (raw) </td></tr>
<tr><td> <b>pvapifc</b> </td><td>expected PV generation (Wh) of the API used incl. correction factor applied </td></tr>
<tr><td> <b>pvaifc</b> </td><td>PV forecast (Wh) of the AI for the next 24h from the current hour of the day </td></tr> <tr><td> <b>pvaifc</b> </td><td>PV forecast (Wh) of the AI for the next 24h from the current hour of the day </td></tr>
<tr><td> <b>pvfc</b> </td><td>PV forecast used for the next 24h from the current hour of the day </td></tr> <tr><td> <b>pvfc</b> </td><td>PV forecast used for the next 24h from the current hour of the day </td></tr>
<tr><td> <b>pvfc_XX</b> </td><td>Array of predicted PV generation values depending on a certain degree of cloud cover (XX = altitude of the sun) </td></tr> <tr><td> <b>pvfc_XX</b> </td><td>Array of predicted PV generation values depending on a certain degree of cloud cover (XX = altitude of the sun) </td></tr>
@@ -26698,9 +26771,10 @@ to ensure that the system configuration is correct.
<tr><td> </td><td><b>&lt;Level&gt;:log</b> - logarithmic scaling </td></tr> <tr><td> </td><td><b>&lt;Level&gt;:log</b> - logarithmic scaling </td></tr>
<tr><td> </td><td> </td></tr> <tr><td> </td><td> </td></tr>
<tr><td> <b>showDiff</b> </td><td>Additional numerical display of the difference &lt;primary bar content&gt; - &lt;secondary bar content&gt;. </td></tr> <tr><td> <b>showDiff</b> </td><td>Additional numerical display of the difference &lt;primary bar content&gt; - &lt;secondary bar content&gt;. </td></tr>
<tr><td> </td><td><b>no</b> - no difference display (default) </td></tr> <tr><td> </td><td>The specification for each level consists of the level number (1..X), a : followed by the position top or bottom. </td></tr>
<tr><td> </td><td><b>top</b> - display above the bars </td></tr> <tr><td> </td><td>The strings for each level are separated by commas (see example). </td></tr>
<tr><td> </td><td><b>bottom</b> - display below the bars </td></tr> <tr><td> </td><td><b>&lt;Level&gt;:top</b> - display above the bars </td></tr>
<tr><td> </td><td><b>&lt;Level&gt;:bottom</b> - display below the bars </td></tr>
<tr><td> </td><td> </td></tr> <tr><td> </td><td> </td></tr>
<tr><td> <b>spaceSize</b> </td><td>Defines how much space in px is kept free above or below the bar (for display type layoutType=diff) to display the </td></tr> <tr><td> <b>spaceSize</b> </td><td>Defines how much space in px is kept free above or below the bar (for display type layoutType=diff) to display the </td></tr>
<tr><td> </td><td>values. For styles with large fonts, the default value may be too small or a bar may slide over the baseline. </td></tr> <tr><td> </td><td>values. For styles with large fonts, the default value may be too small or a bar may slide over the baseline. </td></tr>
@@ -26712,7 +26786,7 @@ to ensure that the system configuration is correct.
<ul> <ul>
<b>Example: </b> <br> <b>Example: </b> <br>
attr &lt;name&gt; graphicControl beamWidth=45 headerDetail=co,pv energyUnit=kWh hourCount=10 layoutType=diff hourStyle=:00 scaleMode=1:log,2:lin,3:log attr &lt;name&gt; graphicControl beamWidth=45 headerDetail=co,pv energyUnit=kWh hourCount=10 layoutType=diff hourStyle=:00 scaleMode=1:log,2:lin,3:log showDiff=1:top,2:bottom
</ul> </ul>
</li> </li>
@@ -28286,6 +28360,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> <b>DaysInRange</b> </td><td>bisher aufgezeichnete Tage mit vergleichbaren Sonnenstand und Bewölkungen zu dieser Zeit </td></tr> <tr><td> <b>DaysInRange</b> </td><td>bisher aufgezeichnete Tage mit vergleichbaren Sonnenstand und Bewölkungen zu dieser Zeit </td></tr>
<tr><td> <b>DoN</b> </td><td>Sonnenauf- und untergangsstatus (0 - Nacht, 1 - Tag) </td></tr> <tr><td> <b>DoN</b> </td><td>Sonnenauf- und untergangsstatus (0 - Nacht, 1 - Tag) </td></tr>
<tr><td> <b>hourofday</b> </td><td>laufende Stunde des Tages </td></tr> <tr><td> <b>hourofday</b> </td><td>laufende Stunde des Tages </td></tr>
<tr><td> <b>pvapifcraw</b> </td><td>erwartete PV Erzeugung (Wh) der verwendeten API (raw) </td></tr>
<tr><td> <b>pvapifc</b> </td><td>erwartete PV Erzeugung (Wh) der verwendeten API inkl. einer eventuellen Korrektur </td></tr> <tr><td> <b>pvapifc</b> </td><td>erwartete PV Erzeugung (Wh) der verwendeten API inkl. einer eventuellen Korrektur </td></tr>
<tr><td> <b>pvaifc</b> </td><td>erwartete PV Erzeugung der KI (Wh) </td></tr> <tr><td> <b>pvaifc</b> </td><td>erwartete PV Erzeugung der KI (Wh) </td></tr>
<tr><td> <b>pvfc</b> </td><td>verwendete PV Erzeugungsprognose (Wh) </td></tr> <tr><td> <b>pvfc</b> </td><td>verwendete PV Erzeugungsprognose (Wh) </td></tr>
@@ -28406,7 +28481,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> <b>initdaybatouttotXX</b> </td><td>initialer Wert der total aus der Batterie XX entnommenen Energie zu Beginn des aktuellen Tages (Wh) </td></tr> <tr><td> <b>initdaybatouttotXX</b> </td><td>initialer Wert der total aus der Batterie XX entnommenen Energie zu Beginn des aktuellen Tages (Wh) </td></tr>
<tr><td> <b>lastTsMaxSocRchdXX</b> </td><td>Timestamp des letzten Erreichens von Batterie XX SoC >= maxSoC (default 95%) </td></tr> <tr><td> <b>lastTsMaxSocRchdXX</b> </td><td>Timestamp des letzten Erreichens von Batterie XX SoC >= maxSoC (default 95%) </td></tr>
<tr><td> <b>nextTsMaxSocChgeXX</b> </td><td>Timestamp bis zu dem die Batterie XX mindestens einmal maxSoC erreichen soll </td></tr> <tr><td> <b>nextTsMaxSocChgeXX</b> </td><td>Timestamp bis zu dem die Batterie XX mindestens einmal maxSoC erreichen soll </td></tr>
<tr><td> <b>pvapifc</b> </td><td>erwartete PV Erzeugung (Wh) der verwendeten API </td></tr> <tr><td> <b>pvapifcraw</b> </td><td>erwartete PV Erzeugung (Wh) der verwendeten API (raw) </td></tr>
<tr><td> <b>pvapifc</b> </td><td>erwartete PV Erzeugung (Wh) der verwendeten API incl. angewendetem Korrekturfaktor </td></tr>
<tr><td> <b>pvaifc</b> </td><td>PV Vorhersage (Wh) der KI für die nächsten 24h ab aktueller Stunde des Tages </td></tr> <tr><td> <b>pvaifc</b> </td><td>PV Vorhersage (Wh) der KI für die nächsten 24h ab aktueller Stunde des Tages </td></tr>
<tr><td> <b>pvfc</b> </td><td>verwendete PV Prognose für die nächsten 24h ab aktueller Stunde des Tages </td></tr> <tr><td> <b>pvfc</b> </td><td>verwendete PV Prognose für die nächsten 24h ab aktueller Stunde des Tages </td></tr>
<tr><td> <b>pvfc_XX</b> </td><td>Array der prognostizierten PV Erzeugungswerte abhängig von einem bestimmten Bewölkungsgrad (XX = Altitude der Sonne) </td></tr> <tr><td> <b>pvfc_XX</b> </td><td>Array der prognostizierten PV Erzeugungswerte abhängig von einem bestimmten Bewölkungsgrad (XX = Altitude der Sonne) </td></tr>
@@ -29353,9 +29429,10 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> </td><td><b>&lt;Ebene&gt;:log</b> - logarithmische Skalierung </td></tr> <tr><td> </td><td><b>&lt;Ebene&gt;:log</b> - logarithmische Skalierung </td></tr>
<tr><td> </td><td> </td></tr> <tr><td> </td><td> </td></tr>
<tr><td> <b>showDiff</b> </td><td>Zusätzliche numerische Anzeige der Differenz '&lt;primärer Balkeninhalt&gt; - &lt;sekundärer Balkeninhalt&gt;'. </td></tr> <tr><td> <b>showDiff</b> </td><td>Zusätzliche numerische Anzeige der Differenz '&lt;primärer Balkeninhalt&gt; - &lt;sekundärer Balkeninhalt&gt;'. </td></tr>
<tr><td> </td><td><b>no</b> - keine Differenzanzeige (default) </td></tr> <tr><td> </td><td>Die Angabe für jede Ebene besteht aus der Ebenen-Nummer (1..X), einem ':' gefolgt von der Position 'top' oder 'bottom'. </td></tr>
<tr><td> </td><td><b>top</b> - Anzeige über den Balken </td></tr> <tr><td> </td><td>Die Strings für jede Ebene werden durch Komma getrennt (siehe Beispiel). </td></tr>
<tr><td> </td><td><b>bottom</b> - Anzeige unter den Balken </td></tr> <tr><td> </td><td><b>&lt;Ebene&gt;:top</b> - Anzeige über den Balken </td></tr>
<tr><td> </td><td><b>&lt;Ebene&gt;:bottom</b> - Anzeige unter den Balken </td></tr>
<tr><td> </td><td> </td></tr> <tr><td> </td><td> </td></tr>
<tr><td> <b>spaceSize</b> </td><td>Legt fest, wieviel Platz in px über oder unter den Balken (bei Anzeigetyp layoutType=diff) zur Anzeige der </td></tr> <tr><td> <b>spaceSize</b> </td><td>Legt fest, wieviel Platz in px über oder unter den Balken (bei Anzeigetyp layoutType=diff) zur Anzeige der </td></tr>
<tr><td> </td><td>Werte freigehalten wird. Bei Styles mit großen Fonts kann der default-Wert zu klein sein bzw. rutscht ein </td></tr> <tr><td> </td><td>Werte freigehalten wird. Bei Styles mit großen Fonts kann der default-Wert zu klein sein bzw. rutscht ein </td></tr>
@@ -29367,7 +29444,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<ul> <ul>
<b>Beispiel: </b> <br> <b>Beispiel: </b> <br>
attr &lt;name&gt; graphicControl beamWidth=45 headerDetail=co,pv energyUnit=kWh hourCount=10 layoutType=diff hourStyle=:00 scaleMode=1:log,2:lin,3:log showDiff=top attr &lt;name&gt; graphicControl beamWidth=45 headerDetail=co,pv energyUnit=kWh hourCount=10 layoutType=diff hourStyle=:00 scaleMode=1:log,2:lin,3:log showDiff=1:top,2:bottom
</ul> </ul>
</li> </li>