2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-25 03:44:52 +00:00

76_SolarForecast: possible Illegal division by zero if Battery SOC management is activated

git-svn-id: https://svn.fhem.de/fhem/trunk@28802 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2024-04-17 17:54:32 +00:00
parent 570c310179
commit ab3ad5f429

View File

@ -158,7 +158,9 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.17.7" => "09.04.2024 export pvHistory to CSV ", "1.17.9" => "17.04.2024 _batSocTarget: fix Illegal division by zero, Forum: https://forum.fhem.de/index.php?msg=1310930 ",
"1.17.8" => "16.04.2024 calcTodayPVdeviation: change of calculation ",
"1.17.7" => "09.04.2024 export pvHistory to CSV, making attr affectMaxDayVariance obsolete ",
"1.17.6" => "07.04.2024 new sub writeToHistory with many internal changes in pvHistory write process ". "1.17.6" => "07.04.2024 new sub writeToHistory with many internal changes in pvHistory write process ".
"_transferInverterValues: react on inverter etotal behavior ", "_transferInverterValues: react on inverter etotal behavior ",
"1.17.5" => "04.04.2024 currentInverterDev: check syntax of key capacity if set, change defmaxvar back from 0.8 to 0.5 ". "1.17.5" => "04.04.2024 currentInverterDev: check syntax of key capacity if set, change defmaxvar back from 0.8 to 0.5 ".
@ -480,7 +482,7 @@ my @rconfigs = qw( pvCorrectionFactor_Auto
); );
# Anlagenkonfiguration: maßgebliche Attribute # Anlagenkonfiguration: maßgebliche Attribute
my @aconfigs = qw( affect70percentRule affectBatteryPreferredCharge affectConsForecastIdentWeekdays my @aconfigs = qw( affect70percentRule affectBatteryPreferredCharge affectConsForecastIdentWeekdays
affectConsForecastInPlanning affectMaxDayVariance affectSolCastPercentile affectConsForecastInPlanning affectSolCastPercentile
consumerLegend consumerAdviceIcon consumerLink consumerLegend consumerAdviceIcon consumerLink
ctrlAIdataStorageDuration ctrlAutoRefresh ctrlAutoRefreshFW ctrlBackupFilesKeep ctrlAIdataStorageDuration ctrlAutoRefresh ctrlAutoRefreshFW ctrlBackupFilesKeep
ctrlBatSocManagement ctrlConsRecommendReadings ctrlGenPVdeviation ctrlInterval ctrlBatSocManagement ctrlConsRecommendReadings ctrlGenPVdeviation ctrlInterval
@ -1091,7 +1093,7 @@ sub Initialize {
"affectBatteryPreferredCharge:slider,0,1,100 ". "affectBatteryPreferredCharge:slider,0,1,100 ".
"affectConsForecastIdentWeekdays:1,0 ". "affectConsForecastIdentWeekdays:1,0 ".
"affectConsForecastInPlanning:1,0 ". "affectConsForecastInPlanning:1,0 ".
"affectMaxDayVariance ". "affectMaxDayVariance:obsolete ".
"affectSolCastPercentile:select,10,50,90 ". "affectSolCastPercentile:select,10,50,90 ".
"consumerLegend:none,icon_top,icon_bottom,text_top,text_bottom ". "consumerLegend:none,icon_top,icon_bottom,text_top,text_bottom ".
"consumerAdviceIcon ". "consumerAdviceIcon ".
@ -5301,14 +5303,14 @@ 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 eq 'affectNumHistDays') { if ($cmd eq 'set' && $aName eq 'affectMaxDayVariance') {
# if (!$init_done) { if (!$init_done) {
# return qq{Device "$name" -> The attribute '$aName' is obsolete and will be deleted soon. Please press "save config" when restart is finished.}; return qq{Device "$name" -> The attribute '$aName' is obsolete and will be deleted soon. Please press "save config" when restart is finished.};
# } }
# else { else {
# return qq{The attribute '$aName' is obsolete and will be deleted soon.}; return qq{The attribute '$aName' is obsolete and will be deleted soon.};
# } }
#} }
###################################################################################################################### ######################################################################################################################
if ($aName eq 'disable') { if ($aName eq 'disable') {
@ -5331,8 +5333,8 @@ sub Attr {
if ($aName eq 'ctrlBatSocManagement' && $init_done) { if ($aName eq 'ctrlBatSocManagement' && $init_done) {
if ($cmd eq 'set') { if ($cmd eq 'set') {
return qq{Define the key "cap" with "set $name currentBatteryDev" before this attribute.} return qq{Define the key "cap" with "set $name currentBatteryDev" before this attribute in the correct form.}
if(ReadingsVal ($name, 'currentBatteryDev', '') !~ /\s+cap=/xs); if(!CurrentVal($hash, 'batinstcap', 0)); # https://forum.fhem.de/index.php?msg=1310930
my ($lowSoc, $upSoc, $maxsoc, $careCycle) = __parseAttrBatSoc ($name, $aVal); my ($lowSoc, $upSoc, $maxsoc, $careCycle) = __parseAttrBatSoc ($name, $aVal);
@ -5376,12 +5378,6 @@ sub Attr {
} }
} }
if ($aName eq 'affectMaxDayVariance') {
unless ($aVal =~ /^[0-9.]+$/x) {
return qq{The value for $aName is not valid. Use only numbers with optional decimal places !};
}
}
if ($init_done == 1 && $aName eq "ctrlSolCastAPIoptimizeReq") { if ($init_done == 1 && $aName eq "ctrlSolCastAPIoptimizeReq") {
if (!isSolCastUsed ($hash)) { if (!isSolCastUsed ($hash)) {
return qq{The attribute $aName is only valid for device model "SolCastAPI".}; return qq{The attribute $aName is only valid for device model "SolCastAPI".};
@ -8145,13 +8141,19 @@ sub _batSocTarget {
my $hash = $paref->{hash}; my $hash = $paref->{hash};
my $name = $paref->{name}; my $name = $paref->{name};
my $type = $paref->{type}; my $type = $paref->{type};
my $t = $paref->{t}; # aktuelle Zeit my $t = $paref->{t}; # aktuelle Zeit
return if(!isBatteryUsed ($name)); return if(!isBatteryUsed ($name));
my $oldd2care = CircularVal ($hash, 99, 'days2care', 0); my $oldd2care = CircularVal ($hash, 99, 'days2care', 0);
my $ltsmsr = CircularVal ($hash, 99, 'lastTsMaxSocRchd', undef); my $ltsmsr = CircularVal ($hash, 99, 'lastTsMaxSocRchd', undef);
my $batcharge = CurrentVal ($hash, 'batcharge', 0); # aktuelle Ladung in % my $batcharge = CurrentVal ($hash, 'batcharge', 0); # aktuelle Ladung in %
my $batinstcap = CurrentVal ($hash, 'batinstcap', 0); # installierte Batteriekapazität Wh
if (!$batinstcap) {
Log3 ($name, 1, "$name - WARNING - Attribute ctrlBatSocManagement is active, but the required key 'cap' is not setup in currentBatteryDev. Exit.");
return;
}
__batSaveSocKeyFigures ($paref) if(!$ltsmsr || $batcharge >= $maxSoCdef || $oldd2care < 0); __batSaveSocKeyFigures ($paref) if(!$ltsmsr || $batcharge >= $maxSoCdef || $oldd2care < 0);
@ -8208,7 +8210,6 @@ sub _batSocTarget {
my $csopt = ReadingsNum ($name, 'Battery_OptimumTargetSoC', $lowSoc); # aktuelles SoC Optimum my $csopt = ReadingsNum ($name, 'Battery_OptimumTargetSoC', $lowSoc); # aktuelles SoC Optimum
my $pvexpect = $pvfctm > $pvfctd ? $pvfctm : $pvfctd; my $pvexpect = $pvfctm > $pvfctd ? $pvfctm : $pvfctd;
my $batinstcap = CurrentVal ($hash, 'batinstcap', 0); # installierte Batteriekapazität Wh
my $cantarget = 100 - (100 / $batinstcap) * $pvexpect; # berechneter möglicher Min SOC nach Berücksichtigung Ladewahrscheinlichkeit my $cantarget = 100 - (100 / $batinstcap) * $pvexpect; # berechneter möglicher Min SOC nach Berücksichtigung Ladewahrscheinlichkeit
my $newtarget = sprintf "%.0f", ($cantarget < $target ? $cantarget : $target); # Abgleich möglicher Min SOC gg. berechneten Min SOC my $newtarget = sprintf "%.0f", ($cantarget < $target ? $cantarget : $target); # Abgleich möglicher Min SOC gg. berechneten Min SOC
@ -10211,13 +10212,12 @@ sub calcTodayPVdeviation {
my $sstime = timestringToTimestamp ($date.' '.ReadingsVal ($name, "Today_SunSet", '22:00').':00'); my $sstime = timestringToTimestamp ($date.' '.ReadingsVal ($name, "Today_SunSet", '22:00').':00');
return if($t < $sstime); return if($t < $sstime);
my $diff = $pvfc - $pvre; $dp = sprintf "%.2f", (100 - (100 * $pvfc / $pvre));
$dp = sprintf "%.2f" , (100 * $diff / $pvre);
} }
else { else {
my $rodfc = ReadingsNum ($name, 'RestOfDayPVforecast', 0); my $rodfc = ReadingsNum ($name, 'RestOfDayPVforecast', 0);
my $dayfc = $pvre + $rodfc; # laufende Tagesprognose aus PVreal + Prognose Resttag my $fcun = $pvfc - $rodfc; # laufende PV Prognose aus Tagesprognose - Prognose Resttag
$dp = sprintf "%.2f", (100 * ($pvfc - $dayfc) / $dayfc); $dp = sprintf "%.2f", (100 - (100 * $pvre / $fcun));
} }
$data{$type}{$name}{circular}{99}{tdayDvtn} = $dp; $data{$type}{$name}{circular}{99}{tdayDvtn} = $dp;
@ -10457,12 +10457,11 @@ sub __calcNewFactor {
$factor = sprintf "%.2f", ($pvrl / $pvfc); $factor = sprintf "%.2f", ($pvrl / $pvfc);
} }
my $maxvar = AttrVal ($name, 'affectMaxDayVariance', $defmaxvar); # max. Korrekturvarianz $factor = 1.00 if(1 * $factor == 0); # 0.00-Werte ignorieren (Schleifengefahr)
$factor = 1.00 if(1 * $factor == 0); # 0.00-Werte ignorieren (Schleifengefahr)
if (abs($factor - $oldfac) > $maxvar) { if (abs($factor - $oldfac) > $defmaxvar) {
$factor = sprintf "%.2f", ($factor > $oldfac ? $oldfac + $maxvar : $oldfac - $maxvar); $factor = sprintf "%.2f", ($factor > $oldfac ? $oldfac + $defmaxvar : $oldfac - $defmaxvar);
Log3 ($name, 3, "$name - new $calc correction factor calculated (limited by affectMaxDayVariance): $factor (old: $oldfac) for hour: $h"); Log3 ($name, 3, "$name - new $calc correction factor calculated (limited by maximum Day Variance): $factor (old: $oldfac) for hour: $h");
} }
else { else {
Log3 ($name, 3, "$name - new $calc correction factor for hour $h calculated: $factor (old: $oldfac)"); Log3 ($name, 3, "$name - new $calc correction factor for hour $h calculated: $factor (old: $oldfac)");
@ -14415,30 +14414,31 @@ sub listDataPool {
my $don = HistoryVal ($hash, $day, $key, 'DoN', '-'); my $don = HistoryVal ($hash, $day, $key, 'DoN', '-');
if ($export eq 'csv') { if ($export eq 'csv') {
$hexp->{$day}{$key}{pvrl} = $pvrl; $hexp->{$day}{$key}{PVreal} = $pvrl;
$hexp->{$day}{$key}{pvrlvd} = $pvrlvd; $hexp->{$day}{$key}{PVrealValid} = $pvrlvd;
$hexp->{$day}{$key}{pvfc} = $pvfc; $hexp->{$day}{$key}{PVforecast} = $pvfc;
$hexp->{$day}{$key}{gcons} = $gcons; $hexp->{$day}{$key}{GridConsumption} = $gcons;
$hexp->{$day}{$key}{con} = $con; $hexp->{$day}{$key}{Consumption} = $con;
$hexp->{$day}{$key}{confc} = $confc; $hexp->{$day}{$key}{confc} = $confc;
$hexp->{$day}{$key}{gfeedin} = $gfeedin; $hexp->{$day}{$key}{GridFeedIn} = $gfeedin;
$hexp->{$day}{$key}{weatherid} = $wid; $hexp->{$day}{$key}{WeatherId} = $wid;
$hexp->{$day}{$key}{wcc} = $wcc; $hexp->{$day}{$key}{CoudCover} = $wcc;
$hexp->{$day}{$key}{rr1c} = $rr1c; $hexp->{$day}{$key}{TotalPrecipitation} = $rr1c;
$hexp->{$day}{$key}{temp} = $temp // ''; $hexp->{$day}{$key}{Temperature} = $temp // '';
$hexp->{$day}{$key}{pvcorrf} = $pvcorrf eq '-' ? '' : (split "/", $pvcorrf)[0]; $hexp->{$day}{$key}{PVCorrectionFactor} = $pvcorrf eq '-' ? '' : (split "/", $pvcorrf)[0];
$hexp->{$day}{$key}{quality} = $pvcorrf eq '-' ? '' : (split "/", $pvcorrf)[1]; $hexp->{$day}{$key}{Quality} = $pvcorrf eq '-' ? '' : (split "/", $pvcorrf)[1];
$hexp->{$day}{$key}{dayname} = $dayname // ''; $hexp->{$day}{$key}{DayName} = $dayname // '';
$hexp->{$day}{$key}{etotal} = $etotal; $hexp->{$day}{$key}{Etotal} = $etotal;
$hexp->{$day}{$key}{batin} = $batin; $hexp->{$day}{$key}{BatteryInTotal} = $btotin;
$hexp->{$day}{$key}{batouttotal} = $btotout; $hexp->{$day}{$key}{BatteryIn} = $batin;
$hexp->{$day}{$key}{batout} = $batout; $hexp->{$day}{$key}{BatteryOutTotal} = $btotout;
$hexp->{$day}{$key}{batmaxsoc} = $batmsoc; $hexp->{$day}{$key}{BatteryOut} = $batout;
$hexp->{$day}{$key}{batsetsoc} = $batssoc; $hexp->{$day}{$key}{BatteryMaxSoc} = $batmsoc;
$hexp->{$day}{$key}{rad1h} = $rad1h; $hexp->{$day}{$key}{BatterySetSoc} = $batssoc;
$hexp->{$day}{$key}{sunaz} = $sunaz; $hexp->{$day}{$key}{GlobalRadiation } = $rad1h;
$hexp->{$day}{$key}{sunalt} = $sunalt; $hexp->{$day}{$key}{SunAzimuth} = $sunaz;
$hexp->{$day}{$key}{DoN} = $don; $hexp->{$day}{$key}{SunAltitude} = $sunalt;
$hexp->{$day}{$key}{DayOrNight} = $don;
} }
$ret .= "\n " if($ret); $ret .= "\n " if($ret);
@ -14471,11 +14471,11 @@ sub listDataPool {
my $csmh = HistoryVal ($hash, $day, $key, "hourscsme${c}", undef); my $csmh = HistoryVal ($hash, $day, $key, "hourscsme${c}", undef);
if ($export eq 'csv') { if ($export eq 'csv') {
$hexp->{$day}{$key}{"cyclescsm${c}"} = $csmc if(defined $csmc); $hexp->{$day}{$key}{"CyclesCsm${c}"} = $csmc if(defined $csmc);
$hexp->{$day}{$key}{"csmt${c}"} = $csmt if(defined $csmt); $hexp->{$day}{$key}{"Csmt${c}"} = $csmt if(defined $csmt);
$hexp->{$day}{$key}{"csme${c}"} = $csme if(defined $csme); $hexp->{$day}{$key}{"Csme${c}"} = $csme if(defined $csme);
$hexp->{$day}{$key}{"minutescsm${c}"} = $csmm if(defined $csmm); $hexp->{$day}{$key}{"MinutesCsm${c}"} = $csmm if(defined $csmm);
$hexp->{$day}{$key}{"hourscsme${c}"} = $csmh if(defined $csmh); $hexp->{$day}{$key}{"HoursCsme${c}"} = $csmh if(defined $csmh);
} }
if (defined $csmc) { if (defined $csmc) {
@ -14905,9 +14905,7 @@ sub _writeAsCsv {
#################### ####################
for my $exd (sort{$a<=>$b} keys %{$hexp}) { for my $exd (sort{$a<=>$b} keys %{$hexp}) {
for my $exh (sort{$a<=>$b} keys %{$hexp->{$exd}}) { for my $exh (sort{$a<=>$b} keys %{$hexp->{$exd}}) {
my @aexp; push my @aexp, ($exd, $exh);
push @aexp, $exd;
push @aexp, $exh;
for my $k (sort keys %{$hexp->{$exd}{$exh}}) { for my $k (sort keys %{$hexp->{$exd}{$exh}}) {
my $val = $hexp->{$exd}{$exh}{$k}; my $val = $hexp->{$exd}{$exh}{$k};
@ -18286,9 +18284,7 @@ to ensure that the system configuration is correct.
<li><b>pvCorrectionFactor_Auto </b> <br><br> <li><b>pvCorrectionFactor_Auto </b> <br><br>
Switches the automatic prediction correction on/off. Switches the automatic prediction correction on/off.
The mode of operation differs depending on the selected method. The mode of operation differs depending on the selected method. <br>
The correction behaviour can be influenced with the
<a href="#SolarForecast-attr-affectMaxDayVariance">affectMaxDayVariance</a> attribute. <br>
(default: off) (default: off)
<br><br> <br><br>
@ -18869,16 +18865,6 @@ to ensure that the system configuration is correct.
</li> </li>
<br> <br>
<a id="SolarForecast-attr-affectMaxDayVariance"></a>
<li><b>affectMaxDayVariance &lt;Zahl&gt; </b><br>
Maximum adjustment of the PV prediction factor (Reading pvCorrectionFactor_XX) that can be made
in relation to one hour per day. <br>
This setting has no influence on the learning and forecasting behavior of any AI support used
(<a href="#SolarForecast-set-pvCorrectionFactor_Auto">pvCorrectionFactor_Auto</a>). <br>
(default: 0.8)
</li>
<br>
<a id="SolarForecast-attr-affectSolCastPercentile"></a> <a id="SolarForecast-attr-affectSolCastPercentile"></a>
<li><b>affectSolCastPercentile &lt;10 | 50 | 90&gt; </b><br> <li><b>affectSolCastPercentile &lt;10 | 50 | 90&gt; </b><br>
(only when using Model SolCastAPI) <br><br> (only when using Model SolCastAPI) <br><br>
@ -20530,8 +20516,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Schaltet die automatische Vorhersagekorrektur ein/aus. Schaltet die automatische Vorhersagekorrektur ein/aus.
Die Wirkungsweise unterscheidet sich je nach gewählter Methode. <br> Die Wirkungsweise unterscheidet sich je nach gewählter Methode. <br>
Das Korrekturverhalten kann mit dem Attribut
<a href="#SolarForecast-attr-affectMaxDayVariance">affectMaxDayVariance</a> beeinflusst werden. <br>
(default: off) (default: off)
<br><br> <br><br>
@ -21120,17 +21104,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
</li> </li>
<br> <br>
<a id="SolarForecast-attr-affectMaxDayVariance"></a>
<li><b>affectMaxDayVariance &lt;Zahl&gt; </b><br>
Maximale Anpassung des PV Vorhersagefaktors (Reading pvCorrectionFactor_XX) die bezogen auf eine
Stunde pro Tag vorgenommen werden kann. <br>
Auf das Lern- und Prognoseverhalten einer eventuell verwendeten KI-Unterstützung
(<a href="#SolarForecast-set-pvCorrectionFactor_Auto">pvCorrectionFactor_Auto</a>) hat diese Einstellung keinen
Einfluß. <br>
(default: 0.8)
</li>
<br>
<a id="SolarForecast-attr-affectSolCastPercentile"></a> <a id="SolarForecast-attr-affectSolCastPercentile"></a>
<li><b>affectSolCastPercentile &lt;10 | 50 | 90&gt; </b><br> <li><b>affectSolCastPercentile &lt;10 | 50 | 90&gt; </b><br>
(nur bei Verwendung Model SolCastAPI) <br><br> (nur bei Verwendung Model SolCastAPI) <br><br>