2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

76_SolarForecast: consumption fc calc switch from average to median

git-svn-id: https://svn.fhem.de/fhem/trunk@29520 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2025-01-13 20:04:05 +00:00
parent 7b9a7f1863
commit 87524638d3
3 changed files with 144 additions and 136 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
- change: 76_SolarForecast: consumption fc calc switch from average to median
- change: 76_SolarForecast: Attr graphicBeam1MaxVal, ctrlAreaFactorUsage are - change: 76_SolarForecast: Attr graphicBeam1MaxVal, ctrlAreaFactorUsage are
obsolete obsolete
- bugfix: 76_SolarForecast: fix interruptable key and some minor fixes - bugfix: 76_SolarForecast: fix interruptable key and some minor fixes

View File

@ -157,6 +157,7 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.43.3" => "13.01.2025 add Wiki icon in graphic header, _calcConsumptionForecast: switch calc from average to median, edit comref ",
"1.43.2" => "12.01.2025 _batChargeRecmd: bugfix calc socwh, Attr graphicBeam1MaxVal, (experimental) ctrlAreaFactorUsage are obsolete ". "1.43.2" => "12.01.2025 _batChargeRecmd: bugfix calc socwh, Attr graphicBeam1MaxVal, (experimental) ctrlAreaFactorUsage are obsolete ".
"trackFlex now default in DWD Model, replace title Charging recommendation by Charging release ". "trackFlex now default in DWD Model, replace title Charging recommendation by Charging release ".
"_saveEnergyConsumption: add dowrite flag, edit comref ", "_saveEnergyConsumption: add dowrite flag, edit comref ",
@ -254,7 +255,7 @@ my %vNotesIntern = (
"1.33.0" => "26.09.2024 substitute area factor hash by ___areaFactorFix function ", "1.33.0" => "26.09.2024 substitute area factor hash by ___areaFactorFix function ",
"1.32.0" => "02.09.2024 new attr setupOtherProducerXX, report calculation and storage of negative consumption values ". "1.32.0" => "02.09.2024 new attr setupOtherProducerXX, report calculation and storage of negative consumption values ".
"Forum: https://forum.fhem.de/index.php?msg=1319083 ". "Forum: https://forum.fhem.de/index.php?msg=1319083 ".
"bugfix in _estConsumptionForecast, new ctrlDebug consumption_long ", "bugfix in _calcConsumptionForecast, new ctrlDebug consumption_long ",
"1.31.0" => "20.08.2024 rename attributes ctrlWeatherDevX to setupWeatherDevX ", "1.31.0" => "20.08.2024 rename attributes ctrlWeatherDevX to setupWeatherDevX ",
"1.30.0" => "18.08.2024 new attribute flowGraphicShift, Forum:https://forum.fhem.de/index.php?msg=1318597 ", "1.30.0" => "18.08.2024 new attribute flowGraphicShift, Forum:https://forum.fhem.de/index.php?msg=1318597 ",
"1.29.4" => "03.08.2024 delete writeCacheToFile from _getRoofTopData, _specialActivities: avoid loop caused by \@widgetreadings ", "1.29.4" => "03.08.2024 delete writeCacheToFile from _getRoofTopData, _specialActivities: avoid loop caused by \@widgetreadings ",
@ -487,15 +488,15 @@ my $cfile = 'controls_solarforecast.txt';
# initiale Hashes für Stunden Consumption Forecast inkl. und exkl. Verbraucher # initiale Hashes für Stunden Consumption Forecast inkl. und exkl. Verbraucher
my $conhfc = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0, #my $conhfc = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0,
"09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0, # "09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0,
"17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0, # "17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
}; # };
my $conhfcex = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0, #my $conhfcex = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0,
"09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0, # "09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0,
"17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0, # "17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
}; # };
# mögliche Debug-Module # mögliche Debug-Module
my @dd = qw( aiProcess my @dd = qw( aiProcess
aiData aiData
@ -942,6 +943,8 @@ my %htitles = (
DE => qq{Konfigurationsprüfung der Anlage} }, DE => qq{Konfigurationsprüfung der Anlage} },
jtsfft => { EN => qq{Open the SolarForecast Forum}, jtsfft => { EN => qq{Open the SolarForecast Forum},
DE => qq{Öffne das SolarForecast Forum} }, DE => qq{Öffne das SolarForecast Forum} },
opwiki => { EN => qq{Open the Wiki (German language)},
DE => qq{Öffne das Wiki} },
scaresps => { EN => qq{API request successful}, scaresps => { EN => qq{API request successful},
DE => qq{API Abfrage erfolgreich} }, DE => qq{API Abfrage erfolgreich} },
dwfcrsu => { EN => qq{Weather data are up to date according to used DWD model}, dwfcrsu => { EN => qq{Weather data are up to date according to used DWD model},
@ -7555,7 +7558,7 @@ sub centralTask {
_batSocTarget ($centpars); # Batterie Optimum Ziel SOC berechnen _batSocTarget ($centpars); # Batterie Optimum Ziel SOC berechnen
_batChargeRecmd ($centpars); # Batterie Ladefreigabe berechnen und erstellen _batChargeRecmd ($centpars); # Batterie Ladefreigabe berechnen und erstellen
_manageConsumerData ($centpars); # Consumer Daten sammeln und Zeiten planen _manageConsumerData ($centpars); # Consumer Daten sammeln und Zeiten planen
_estConsumptionForecast ($centpars); # Verbrauchsprognose erstellen _calcConsumptionForecast ($centpars); # Verbrauchsprognose erstellen
_evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren _evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren
_calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen _calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen
_calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang) _calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang)
@ -11812,7 +11815,7 @@ return ($simpCstat, $starttime, $stoptime, $supplmnt);
################################################################ ################################################################
# Energieverbrauch Vorhersage kalkulieren # Energieverbrauch Vorhersage kalkulieren
################################################################ ################################################################
sub _estConsumptionForecast { sub _calcConsumptionForecast {
my $paref = shift; my $paref = shift;
my $name = $paref->{name}; my $name = $paref->{name};
my $type = $paref->{type}; my $type = $paref->{type};
@ -11840,10 +11843,7 @@ sub _estConsumptionForecast {
## Verbrauchsvorhersage für den kommenden Tag ## Verbrauchsvorhersage für den kommenden Tag
############################################## ##############################################
my $tomorrow = strftime "%a", localtime($t+86400); # Wochentagsname kommender Tag my $tomorrow = strftime "%a", localtime($t+86400); # Wochentagsname kommender Tag
my $totcon = 0; my (@cona, $exconfc, $csme);
my $dnum = 0;
my ($exconfc, $csme);
debugLog ($paref, 'consumption|consumption_long', "################### Consumption forecast for the next day ###################"); debugLog ($paref, 'consumption|consumption_long', "################### Consumption forecast for the next day ###################");
debugLog ($paref, 'consumption|consumption_long', "Date(s) to take note: ".join ',', @dtn) if(@dtn); debugLog ($paref, 'consumption|consumption_long', "Date(s) to take note: ".join ',', @dtn) if(@dtn);
@ -11882,15 +11882,16 @@ sub _estConsumptionForecast {
debugLog ($paref, 'consumption|consumption_long', "History Consumption day >$n< considering possible exclusions: $dcon"); debugLog ($paref, 'consumption|consumption_long', "History Consumption day >$n< considering possible exclusions: $dcon");
$totcon += $dcon; push @cona, $dcon;
$dnum++;
} }
my $dnum = scalar @cona;
if ($dnum) { if ($dnum) {
my $tomavg = int ($totcon / $dnum); my $tomcon = sprintf "%.0f", medianArray (\@cona);
$data{$name}{current}{tomorrowconsumption} = $tomavg; # prognostizierter Durchschnittsverbrauch aller (gleicher) Wochentage $data{$name}{current}{tomorrowconsumption} = $tomcon; # prognostizierter Verbrauch (Median) aller (gleicher) Wochentage
debugLog ($paref, 'consumption|consumption_long', "estimated Consumption for tomorrow: $tomavg, days for avg: $dnum"); debugLog ($paref, 'consumption|consumption_long', "estimated Consumption for tomorrow: $tomcon, days for avg: $dnum");
} }
else { else {
my $lang = $paref->{lang}; my $lang = $paref->{lang};
@ -11906,22 +11907,14 @@ sub _estConsumptionForecast {
my $nhtime = NexthoursVal ($hash, $k, "starttime", undef); # Startzeit my $nhtime = NexthoursVal ($hash, $k, "starttime", undef); # Startzeit
next if(!$nhtime); next if(!$nhtime);
$conhfc = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0,
"09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0,
"17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
};
$conhfcex = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0,
"09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0,
"17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
};
$dnum = 0; $dnum = 0;
my $consumerco = 0; my $consumerco = 0;
my $utime = timestringToTimestamp ($nhtime); my $utime = timestringToTimestamp ($nhtime);
my $nhday = strftime "%a", localtime($utime); # Wochentagsname des NextHours Key my $nhday = strftime "%a", localtime($utime); # Wochentagsname des NextHours Key
my $nhhr = sprintf("%02d", (int (strftime "%H", localtime($utime))) + 1); # Stunde des Tages vom NextHours Key (01,02,...24) my $nhhr = sprintf("%02d", (int (strftime "%H", localtime($utime))) + 1); # Stunde des Tages vom NextHours Key (01,02,...24)
my ($conhfc, $conhfcex);
for my $m (sort{$a<=>$b} keys %{$data{$name}{pvhist}}) { for my $m (sort{$a<=>$b} keys %{$data{$name}{pvhist}}) {
next if($m eq $day); # next wenn gleicher Tag (Datum) wie heute next if($m eq $day); # next wenn gleicher Tag (Datum) wie heute
@ -11966,18 +11959,19 @@ sub _estConsumptionForecast {
} }
} }
$conhfcex->{$nhhr} += ($hcon - $consumerco) if($hcon >= $consumerco); # prognostizierter Verbrauch Ex registrierter Verbraucher push @{$conhfcex->{"$nhhr"}}, ($hcon - $consumerco) if($hcon >= $consumerco); # prognostizierter Verbrauch (Median) Ex registrierter Verbraucher
$conhfc->{$nhhr} += $hcon; push @{$conhfc->{"$nhhr"}}, $hcon;
$dnum++; $dnum++;
} }
if ($dnum) { if ($dnum) {
my $conavgex = int ($conhfcex->{$nhhr} / $dnum); my $conavgex = sprintf "%.0f", medianArray (\@{$conhfcex->{$nhhr}}) if(scalar @{$conhfcex->{$nhhr}});
$data{$name}{nexthours}{$k}{confcEx} = $conavgex; $data{$name}{nexthours}{$k}{confcEx} = $conavgex;
my $conavg = int ($conhfc->{$nhhr} / $dnum); my $conavg = sprintf "%.0f", medianArray (\@{$conhfc->{$nhhr}}) if(scalar @{$conhfc->{$nhhr}});
$data{$name}{nexthours}{$k}{confc} = $conavg; # Durchschnittsverbrauch aller gleicher Wochentage pro Stunde $data{$name}{nexthours}{$k}{confc} = $conavg; # prognostizierter Verbrauch (Median) auf Grundlage aller gleicher Wochentage pro Stunde
if (NexthoursVal ($hash, $k, 'today', 0)) { # nur Werte des aktuellen Tag speichern if (NexthoursVal ($hash, $k, 'today', 0)) { # nur Werte des aktuellen Tag speichern
$data{$name}{circular}{sprintf("%02d",$nhhr)}{confc} = $conavg; $data{$name}{circular}{sprintf("%02d",$nhhr)}{confc} = $conavg;
writeToHistory ( { paref => $paref, key => 'confc', val => $conavg, hour => $nhhr } ); writeToHistory ( { paref => $paref, key => 'confc', val => $conavg, hour => $nhhr } );
} }
@ -13283,6 +13277,12 @@ sub _graphicHeader {
$img = FW_makeImage('time_note@grey'); $img = FW_makeImage('time_note@grey');
my $fthicon = "<a href='https://forum.fhem.de/index.php?topic=137058.0' target='_blank'>$img</a>"; my $fthicon = "<a href='https://forum.fhem.de/index.php?topic=137058.0' target='_blank'>$img</a>";
my $fthtitle = $htitles{jtsfft}{$lang}; my $fthtitle = $htitles{jtsfft}{$lang};
## Wiki-Icon
##############
$img = FW_makeImage ('edit_copy@grey');
my $wikicon = "<a href='https://wiki.fhem.de/wiki/SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung' target='_blank'>$img</a>";
my $wiktitle = $htitles{opwiki}{$lang};
## Update-Icon ## Update-Icon
################ ################
@ -13494,13 +13494,14 @@ sub _graphicHeader {
####################### #######################
my $alias = AttrVal ($name, "alias", $name ); # Linktext als Aliasname my $alias = AttrVal ($name, "alias", $name ); # Linktext als Aliasname
my $dlink = qq{<a href="$::FW_ME$::FW_subdir?detail=$name">$alias</a>}; my $dlink = qq{<a href="$::FW_ME$::FW_subdir?detail=$name">$alias</a>};
my $space = '&nbsp;&nbsp;&nbsp;';
my $disti = qq{<span title="$chktitle"> $chkicon </span> $space <span title="$fthtitle"> $fthicon </span> $space <span title="$wiktitle"> $wikicon </span>};
$header .= qq{<tr>}; $header .= qq{<tr>};
$header .= qq{<td colspan="1" align="left" $dstyle> <b>$dlink</b> </td>}; $header .= qq{<td colspan="1" align="left" $dstyle> <b>$dlink</b> </td>};
$header .= qq{<td colspan="1" align="right" title="$chktitle" $dstyle> $chkicon </td>}; $header .= qq{<td colspan="2" align="center" $dstyle> $disti </td>};
$header .= qq{<td colspan="1" align="left" title="$fthtitle" $dstyle> $fthicon </td>}; $header .= qq{<td colspan="3" align="left" $dstyle> $lupt $lup &nbsp; $upicon </td>};
$header .= qq{<td colspan="3" align="left" $dstyle> $lupt $lup &nbsp; $upicon </td>}; $header .= qq{<td colspan="3" align="right" $dstyle> $api </td>};
$header .= qq{<td colspan="3" align="right" $dstyle> $api </td>};
$header .= qq{</tr>}; $header .= qq{</tr>};
$header .= qq{<tr>}; $header .= qq{<tr>};
$header .= qq{<td colspan="3" align="left" $dstyle> $sriseimg &nbsp; $srisetxt &nbsp;&nbsp;&nbsp; $ssetimg &nbsp; $ssettxt &nbsp;&nbsp;&nbsp; $waicon </td>}; $header .= qq{<td colspan="3" align="left" $dstyle> $sriseimg &nbsp; $srisetxt &nbsp;&nbsp;&nbsp; $ssetimg &nbsp; $ssettxt &nbsp;&nbsp;&nbsp; $waicon </td>};
@ -22418,14 +22419,15 @@ to ensure that the system configuration is correct.
<ul> <ul>
<table> <table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup> <colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>lowSoc</b> </td><td>lower minimum SoC, the battery is not discharged lower than this value (> 0) </td></tr> <tr><td> <b>lowSoc</b> </td><td>lower minimum SoC - The battery is not discharged lower than this value (> 0) </td></tr>
<tr><td> <b>upSoC</b> </td><td>upper minimum SoC, the usual value of the optimum SoC is between 'lowSoC' </td></tr> <tr><td> <b>upSoC</b> </td><td>upper minimum SoC - The usual value of the optimum SoC tends to be </td></tr>
<tr><td> </td><td>and this value. </td></tr> <tr><td> </td><td>between 'lowSoC' and 'upSoC' in periods with a high PV surplus </td></tr>
<tr><td> <b>maxSoC</b> </td><td>Maximum minimum SoC, SoC value that must be reached at least every 'careCycle' days </td></tr> <tr><td> </td><td>and between 'upSoC' and 'maxSoC' in periods with a low PV surplus </td></tr>
<tr><td> </td><td>in order to balance the charge in the storage network. </td></tr> <tr><td> <b>maxSoC</b> </td><td>Maximum minimum SoC - SoC value that must be reached at least every 'careCycle' days </td></tr>
<tr><td> </td><td>The specification is optional (&lt;= 100, default: 95) </td></tr> <tr><td> </td><td>in order to balance the charge in the storage network. </td></tr>
<tr><td> <b>careCycle</b> </td><td>Maximum interval in days that may occur between two states of charge </td></tr> <tr><td> </td><td>The specification is optional (&lt;= 100, default: 95) </td></tr>
<tr><td> </td><td>of at least 'maxSoC'. The specification is optional (default: 20) </td></tr> <tr><td> <b>careCycle</b> </td><td>Maximum interval in days that may occur between two states of charge </td></tr>
<tr><td> </td><td>of at least 'maxSoC'. The specification is optional (default: 20) </td></tr>
</table> </table>
</ul> </ul>
<br> <br>
@ -24886,14 +24888,15 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<ul> <ul>
<table> <table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup> <colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>lowSoc</b> </td><td>unterer Mindest-SoC, die Batterie wird nicht tiefer als dieser Wert entladen (> 0) </td></tr> <tr><td> <b>lowSoc</b> </td><td>unterer Mindest-SoC - Die Batterie wird nicht tiefer als dieser Wert entladen (> 0) </td></tr>
<tr><td> <b>upSoC</b> </td><td>oberer Mindest-SoC, der übliche Wert des optimalen SoC bewegt sich zwischen 'lowSoC' </td></tr> <tr><td> <b>upSoC</b> </td><td>oberer Mindest-SoC - Der übliche Wert des optimalen SoC bewegt sich in Perioden mit hohen </td></tr>
<tr><td> </td><td>und diesem Wert. </td></tr> <tr><td> </td><td>PV-Überschuß tendenziell zwischen 'lowSoC' und 'upSoC', in Perioden mit geringem PV-Überschuß </td></tr>
<tr><td> <b>maxSoC</b> </td><td>maximaler Mindest-SoC, SoC Wert der mindestens im Abstand von 'careCycle' Tagen erreicht </td></tr> <tr><td> </td><td>tendenziell zwischen 'upSoC' und 'maxSoC' </td></tr>
<tr><td> </td><td>werden muß um den Ladungsausgleich im Speicherverbund auszuführen. </td></tr> <tr><td> <b>maxSoC</b> </td><td>maximaler Mindest-SoC - SoC Wert der mindestens im Abstand von 'careCycle' Tagen erreicht </td></tr>
<tr><td> </td><td>Die Angabe ist optional (&lt;= 100, default: 95) </td></tr> <tr><td> </td><td>werden muß um den Ladungsausgleich im Speicherverbund auszuführen. </td></tr>
<tr><td> <b>careCycle</b> </td><td>maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' </td></tr> <tr><td> </td><td>Die Angabe ist optional (&lt;= 100, default: 95) </td></tr>
<tr><td> </td><td>auftreten darf. Die Angabe ist optional (default: 20) </td></tr> <tr><td> <b>careCycle</b> </td><td>maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' </td></tr>
<tr><td> </td><td>auftreten darf. Die Angabe ist optional (default: 20) </td></tr>
</table> </table>
</ul> </ul>
<br> <br>

View File

@ -157,6 +157,7 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.43.3" => "13.01.2025 add Wiki icon in graphic header, _calcConsumptionForecast: switch calc from average to median, edit comref ",
"1.43.2" => "12.01.2025 _batChargeRecmd: bugfix calc socwh, Attr graphicBeam1MaxVal, (experimental) ctrlAreaFactorUsage are obsolete ". "1.43.2" => "12.01.2025 _batChargeRecmd: bugfix calc socwh, Attr graphicBeam1MaxVal, (experimental) ctrlAreaFactorUsage are obsolete ".
"trackFlex now default in DWD Model, replace title Charging recommendation by Charging release ". "trackFlex now default in DWD Model, replace title Charging recommendation by Charging release ".
"_saveEnergyConsumption: add dowrite flag, edit comref ", "_saveEnergyConsumption: add dowrite flag, edit comref ",
@ -254,7 +255,7 @@ my %vNotesIntern = (
"1.33.0" => "26.09.2024 substitute area factor hash by ___areaFactorFix function ", "1.33.0" => "26.09.2024 substitute area factor hash by ___areaFactorFix function ",
"1.32.0" => "02.09.2024 new attr setupOtherProducerXX, report calculation and storage of negative consumption values ". "1.32.0" => "02.09.2024 new attr setupOtherProducerXX, report calculation and storage of negative consumption values ".
"Forum: https://forum.fhem.de/index.php?msg=1319083 ". "Forum: https://forum.fhem.de/index.php?msg=1319083 ".
"bugfix in _estConsumptionForecast, new ctrlDebug consumption_long ", "bugfix in _calcConsumptionForecast, new ctrlDebug consumption_long ",
"1.31.0" => "20.08.2024 rename attributes ctrlWeatherDevX to setupWeatherDevX ", "1.31.0" => "20.08.2024 rename attributes ctrlWeatherDevX to setupWeatherDevX ",
"1.30.0" => "18.08.2024 new attribute flowGraphicShift, Forum:https://forum.fhem.de/index.php?msg=1318597 ", "1.30.0" => "18.08.2024 new attribute flowGraphicShift, Forum:https://forum.fhem.de/index.php?msg=1318597 ",
"1.29.4" => "03.08.2024 delete writeCacheToFile from _getRoofTopData, _specialActivities: avoid loop caused by \@widgetreadings ", "1.29.4" => "03.08.2024 delete writeCacheToFile from _getRoofTopData, _specialActivities: avoid loop caused by \@widgetreadings ",
@ -487,15 +488,15 @@ my $cfile = 'controls_solarforecast.txt';
# initiale Hashes für Stunden Consumption Forecast inkl. und exkl. Verbraucher # initiale Hashes für Stunden Consumption Forecast inkl. und exkl. Verbraucher
my $conhfc = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0, #my $conhfc = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0,
"09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0, # "09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0,
"17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0, # "17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
}; # };
my $conhfcex = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0, #my $conhfcex = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0,
"09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0, # "09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0,
"17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0, # "17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
}; # };
# mögliche Debug-Module # mögliche Debug-Module
my @dd = qw( aiProcess my @dd = qw( aiProcess
aiData aiData
@ -942,6 +943,8 @@ my %htitles = (
DE => qq{Konfigurationspr&#252;fung der Anlage} }, DE => qq{Konfigurationspr&#252;fung der Anlage} },
jtsfft => { EN => qq{Open the SolarForecast Forum}, jtsfft => { EN => qq{Open the SolarForecast Forum},
DE => qq{&#214;ffne das SolarForecast Forum} }, DE => qq{&#214;ffne das SolarForecast Forum} },
opwiki => { EN => qq{Open the Wiki (German language)},
DE => qq{&#214;ffne das Wiki} },
scaresps => { EN => qq{API request successful}, scaresps => { EN => qq{API request successful},
DE => qq{API Abfrage erfolgreich} }, DE => qq{API Abfrage erfolgreich} },
dwfcrsu => { EN => qq{Weather data are up to date according to used DWD model}, dwfcrsu => { EN => qq{Weather data are up to date according to used DWD model},
@ -7555,7 +7558,7 @@ sub centralTask {
_batSocTarget ($centpars); # Batterie Optimum Ziel SOC berechnen _batSocTarget ($centpars); # Batterie Optimum Ziel SOC berechnen
_batChargeRecmd ($centpars); # Batterie Ladefreigabe berechnen und erstellen _batChargeRecmd ($centpars); # Batterie Ladefreigabe berechnen und erstellen
_manageConsumerData ($centpars); # Consumer Daten sammeln und Zeiten planen _manageConsumerData ($centpars); # Consumer Daten sammeln und Zeiten planen
_estConsumptionForecast ($centpars); # Verbrauchsprognose erstellen _calcConsumptionForecast ($centpars); # Verbrauchsprognose erstellen
_evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren _evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren
_calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen _calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen
_calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang) _calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang)
@ -11812,7 +11815,7 @@ return ($simpCstat, $starttime, $stoptime, $supplmnt);
################################################################ ################################################################
# Energieverbrauch Vorhersage kalkulieren # Energieverbrauch Vorhersage kalkulieren
################################################################ ################################################################
sub _estConsumptionForecast { sub _calcConsumptionForecast {
my $paref = shift; my $paref = shift;
my $name = $paref->{name}; my $name = $paref->{name};
my $type = $paref->{type}; my $type = $paref->{type};
@ -11840,10 +11843,7 @@ sub _estConsumptionForecast {
## Verbrauchsvorhersage für den kommenden Tag ## Verbrauchsvorhersage für den kommenden Tag
############################################## ##############################################
my $tomorrow = strftime "%a", localtime($t+86400); # Wochentagsname kommender Tag my $tomorrow = strftime "%a", localtime($t+86400); # Wochentagsname kommender Tag
my $totcon = 0; my (@cona, $exconfc, $csme);
my $dnum = 0;
my ($exconfc, $csme);
debugLog ($paref, 'consumption|consumption_long', "################### Consumption forecast for the next day ###################"); debugLog ($paref, 'consumption|consumption_long', "################### Consumption forecast for the next day ###################");
debugLog ($paref, 'consumption|consumption_long', "Date(s) to take note: ".join ',', @dtn) if(@dtn); debugLog ($paref, 'consumption|consumption_long', "Date(s) to take note: ".join ',', @dtn) if(@dtn);
@ -11882,15 +11882,16 @@ sub _estConsumptionForecast {
debugLog ($paref, 'consumption|consumption_long', "History Consumption day >$n< considering possible exclusions: $dcon"); debugLog ($paref, 'consumption|consumption_long', "History Consumption day >$n< considering possible exclusions: $dcon");
$totcon += $dcon; push @cona, $dcon;
$dnum++;
} }
my $dnum = scalar @cona;
if ($dnum) { if ($dnum) {
my $tomavg = int ($totcon / $dnum); my $tomcon = sprintf "%.0f", medianArray (\@cona);
$data{$name}{current}{tomorrowconsumption} = $tomavg; # prognostizierter Durchschnittsverbrauch aller (gleicher) Wochentage $data{$name}{current}{tomorrowconsumption} = $tomcon; # prognostizierter Verbrauch (Median) aller (gleicher) Wochentage
debugLog ($paref, 'consumption|consumption_long', "estimated Consumption for tomorrow: $tomavg, days for avg: $dnum"); debugLog ($paref, 'consumption|consumption_long', "estimated Consumption for tomorrow: $tomcon, days for avg: $dnum");
} }
else { else {
my $lang = $paref->{lang}; my $lang = $paref->{lang};
@ -11906,22 +11907,14 @@ sub _estConsumptionForecast {
my $nhtime = NexthoursVal ($hash, $k, "starttime", undef); # Startzeit my $nhtime = NexthoursVal ($hash, $k, "starttime", undef); # Startzeit
next if(!$nhtime); next if(!$nhtime);
$conhfc = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0,
"09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0,
"17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
};
$conhfcex = { "01" => 0, "02" => 0, "03" => 0, "04" => 0, "05" => 0, "06" => 0, "07" => 0, "08" => 0,
"09" => 0, "10" => 0, "11" => 0, "12" => 0, "13" => 0, "14" => 0, "15" => 0, "16" => 0,
"17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
};
$dnum = 0; $dnum = 0;
my $consumerco = 0; my $consumerco = 0;
my $utime = timestringToTimestamp ($nhtime); my $utime = timestringToTimestamp ($nhtime);
my $nhday = strftime "%a", localtime($utime); # Wochentagsname des NextHours Key my $nhday = strftime "%a", localtime($utime); # Wochentagsname des NextHours Key
my $nhhr = sprintf("%02d", (int (strftime "%H", localtime($utime))) + 1); # Stunde des Tages vom NextHours Key (01,02,...24) my $nhhr = sprintf("%02d", (int (strftime "%H", localtime($utime))) + 1); # Stunde des Tages vom NextHours Key (01,02,...24)
my ($conhfc, $conhfcex);
for my $m (sort{$a<=>$b} keys %{$data{$name}{pvhist}}) { for my $m (sort{$a<=>$b} keys %{$data{$name}{pvhist}}) {
next if($m eq $day); # next wenn gleicher Tag (Datum) wie heute next if($m eq $day); # next wenn gleicher Tag (Datum) wie heute
@ -11966,18 +11959,19 @@ sub _estConsumptionForecast {
} }
} }
$conhfcex->{$nhhr} += ($hcon - $consumerco) if($hcon >= $consumerco); # prognostizierter Verbrauch Ex registrierter Verbraucher push @{$conhfcex->{"$nhhr"}}, ($hcon - $consumerco) if($hcon >= $consumerco); # prognostizierter Verbrauch (Median) Ex registrierter Verbraucher
$conhfc->{$nhhr} += $hcon; push @{$conhfc->{"$nhhr"}}, $hcon;
$dnum++; $dnum++;
} }
if ($dnum) { if ($dnum) {
my $conavgex = int ($conhfcex->{$nhhr} / $dnum); my $conavgex = sprintf "%.0f", medianArray (\@{$conhfcex->{$nhhr}}) if(scalar @{$conhfcex->{$nhhr}});
$data{$name}{nexthours}{$k}{confcEx} = $conavgex; $data{$name}{nexthours}{$k}{confcEx} = $conavgex;
my $conavg = int ($conhfc->{$nhhr} / $dnum); my $conavg = sprintf "%.0f", medianArray (\@{$conhfc->{$nhhr}}) if(scalar @{$conhfc->{$nhhr}});
$data{$name}{nexthours}{$k}{confc} = $conavg; # Durchschnittsverbrauch aller gleicher Wochentage pro Stunde $data{$name}{nexthours}{$k}{confc} = $conavg; # prognostizierter Verbrauch (Median) auf Grundlage aller gleicher Wochentage pro Stunde
if (NexthoursVal ($hash, $k, 'today', 0)) { # nur Werte des aktuellen Tag speichern if (NexthoursVal ($hash, $k, 'today', 0)) { # nur Werte des aktuellen Tag speichern
$data{$name}{circular}{sprintf("%02d",$nhhr)}{confc} = $conavg; $data{$name}{circular}{sprintf("%02d",$nhhr)}{confc} = $conavg;
writeToHistory ( { paref => $paref, key => 'confc', val => $conavg, hour => $nhhr } ); writeToHistory ( { paref => $paref, key => 'confc', val => $conavg, hour => $nhhr } );
} }
@ -13283,6 +13277,12 @@ sub _graphicHeader {
$img = FW_makeImage('time_note@grey'); $img = FW_makeImage('time_note@grey');
my $fthicon = "<a href='https://forum.fhem.de/index.php?topic=137058.0' target='_blank'>$img</a>"; my $fthicon = "<a href='https://forum.fhem.de/index.php?topic=137058.0' target='_blank'>$img</a>";
my $fthtitle = $htitles{jtsfft}{$lang}; my $fthtitle = $htitles{jtsfft}{$lang};
## Wiki-Icon
##############
$img = FW_makeImage ('edit_copy@grey');
my $wikicon = "<a href='https://wiki.fhem.de/wiki/SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung' target='_blank'>$img</a>";
my $wiktitle = $htitles{opwiki}{$lang};
## Update-Icon ## Update-Icon
################ ################
@ -13494,13 +13494,14 @@ sub _graphicHeader {
####################### #######################
my $alias = AttrVal ($name, "alias", $name ); # Linktext als Aliasname my $alias = AttrVal ($name, "alias", $name ); # Linktext als Aliasname
my $dlink = qq{<a href="$::FW_ME$::FW_subdir?detail=$name">$alias</a>}; my $dlink = qq{<a href="$::FW_ME$::FW_subdir?detail=$name">$alias</a>};
my $space = '&nbsp;&nbsp;&nbsp;';
my $disti = qq{<span title="$chktitle"> $chkicon </span> $space <span title="$fthtitle"> $fthicon </span> $space <span title="$wiktitle"> $wikicon </span>};
$header .= qq{<tr>}; $header .= qq{<tr>};
$header .= qq{<td colspan="1" align="left" $dstyle> <b>$dlink</b> </td>}; $header .= qq{<td colspan="1" align="left" $dstyle> <b>$dlink</b> </td>};
$header .= qq{<td colspan="1" align="right" title="$chktitle" $dstyle> $chkicon </td>}; $header .= qq{<td colspan="2" align="center" $dstyle> $disti </td>};
$header .= qq{<td colspan="1" align="left" title="$fthtitle" $dstyle> $fthicon </td>}; $header .= qq{<td colspan="3" align="left" $dstyle> $lupt $lup &nbsp; $upicon </td>};
$header .= qq{<td colspan="3" align="left" $dstyle> $lupt $lup &nbsp; $upicon </td>}; $header .= qq{<td colspan="3" align="right" $dstyle> $api </td>};
$header .= qq{<td colspan="3" align="right" $dstyle> $api </td>};
$header .= qq{</tr>}; $header .= qq{</tr>};
$header .= qq{<tr>}; $header .= qq{<tr>};
$header .= qq{<td colspan="3" align="left" $dstyle> $sriseimg &nbsp; $srisetxt &nbsp;&nbsp;&nbsp; $ssetimg &nbsp; $ssettxt &nbsp;&nbsp;&nbsp; $waicon </td>}; $header .= qq{<td colspan="3" align="left" $dstyle> $sriseimg &nbsp; $srisetxt &nbsp;&nbsp;&nbsp; $ssetimg &nbsp; $ssettxt &nbsp;&nbsp;&nbsp; $waicon </td>};
@ -15459,7 +15460,7 @@ END0
$cc_dummy -= $currentPower; $cc_dummy -= $currentPower;
$cicon = FW_makeImage ($cicon, ''); $cicon = FW_makeImage ($cicon, '');
($scale, $cicon) = __normIconScale ($cicon, $name); ($scale, $cicon) = __normIconScale ($name, $cicon);
$ret .= qq{<g id="consumer_${c}_$stna" transform="translate($cons_left,$y_pos),scale($scale)">}; $ret .= qq{<g id="consumer_${c}_$stna" transform="translate($cons_left,$y_pos),scale($scale)">};
$ret .= "<title>$calias</title>".$cicon; $ret .= "<title>$calias</title>".$cicon;
@ -15488,7 +15489,7 @@ END1
## Home Icon ## Home Icon
############## ##############
my $hicon = FW_makeImage ($homeicondef, ''); my $hicon = FW_makeImage ($homeicondef, '');
($scale, $hicon) = __normIconScale ($hicon, $name); ($scale, $hicon) = __normIconScale ($name, $hicon);
$ret .= qq{<g id="home_$stna" transform="translate(368,360),scale($scale)">}; # translate(X-Koordinate,Y-Koordinate), scale(<Größe>)-> Koordinaten ändern sich bei Größenänderung $ret .= qq{<g id="home_$stna" transform="translate(368,360),scale($scale)">}; # translate(X-Koordinate,Y-Koordinate), scale(<Größe>)-> Koordinaten ändern sich bei Größenänderung
$ret .= "<title>Home</title>".$hicon; $ret .= "<title>Home</title>".$hicon;
@ -15500,7 +15501,7 @@ END1
my $dumtxt = $htitles{dumtxt}{$lang}; my $dumtxt = $htitles{dumtxt}{$lang};
my $dumcol = $cc_dummy <= 0 ? '@grey' : q{}; # Einfärbung Consumer Dummy my $dumcol = $cc_dummy <= 0 ? '@grey' : q{}; # Einfärbung Consumer Dummy
my $dicon = FW_makeImage ($cicondef.$dumcol, ''); my $dicon = FW_makeImage ($cicondef.$dumcol, '');
($scale, $dicon) = __normIconScale ($dicon, $name); ($scale, $dicon) = __normIconScale ($name, $dicon);
$ret .= qq{<g id="dummy_$stna" transform="translate(660,360),scale($scale)">}; $ret .= qq{<g id="dummy_$stna" transform="translate(660,360),scale($scale)">};
$ret .= "<title>$dumtxt</title>".$dicon; $ret .= "<title>$dumtxt</title>".$dicon;
@ -15810,7 +15811,7 @@ sub __addProducerIcon {
); );
$picon = FW_makeImage ($picon, ''); $picon = FW_makeImage ($picon, '');
($scale, $picon) = __normIconScale ($picon, $name); ($scale, $picon) = __normIconScale ($name, $picon);
$ret .= qq{<g id="producer_${pn}_$stna" fill="grey" transform="translate($left,$y_coord),scale($scale)">}; $ret .= qq{<g id="producer_${pn}_$stna" fill="grey" transform="translate($left,$y_coord),scale($scale)">};
$ret .= "<title>$ptxt</title>".$picon; $ret .= "<title>$ptxt</title>".$picon;
@ -15847,7 +15848,7 @@ sub __addNodeIcon {
); );
$nicon = FW_makeImage ($nicon, ''); $nicon = FW_makeImage ($nicon, '');
($scale, $nicon) = __normIconScale ($nicon, $name); ($scale, $nicon) = __normIconScale ($name, $nicon);
my $ret = qq{<g id="node_$stna" transform="translate($x_coord,$y_coord),scale($scale)">}; # translate(X-Koordinate,Y-Koordinate), scale(<Größe>)-> Koordinaten ändern sich bei Größenänderung my $ret = qq{<g id="node_$stna" transform="translate($x_coord,$y_coord),scale($scale)">}; # translate(X-Koordinate,Y-Koordinate), scale(<Größe>)-> Koordinaten ändern sich bei Größenänderung
$ret .= "<title>$ntxt</title>".$nicon; $ret .= "<title>$ntxt</title>".$nicon;
@ -16034,8 +16035,9 @@ return $p;
# scale: 0.10 Normativ $fgscaledef # scale: 0.10 Normativ $fgscaledef
################################################################ ################################################################
sub __normIconScale { sub __normIconScale {
my $icon = shift;
my $name = shift; my $name = shift;
my $icon = shift;
my $dim = shift // 470; # Dimension
my $hscale = $fgscaledef; # Scale Normativ my $hscale = $fgscaledef; # Scale Normativ
my $wscale = $fgscaledef; my $wscale = $fgscaledef;
@ -16044,27 +16046,27 @@ sub __normIconScale {
return ($hscale, $icon) if(!$width || !$height); return ($hscale, $icon) if(!$width || !$height);
$wscale = $hunit eq 'pt' ? 470 * $wscale / $width : $wscale = $hunit eq 'pt' ? $dim * $wscale / $width :
$hunit eq 'px' ? 470 * $wscale / $width * 0.96 : $hunit eq 'px' ? $dim * $wscale / $width * 0.96 :
$hunit eq 'in' ? 470 * $wscale / $width * 0.0138889 : $hunit eq 'in' ? $dim * $wscale / $width * 0.0138889 :
$hunit eq 'mm' ? 470 * $wscale / $width * 0.352778 : $hunit eq 'mm' ? $dim * $wscale / $width * 0.352778 :
$hunit eq 'cm' ? 470 * $wscale / $width * 0.0352778 : $hunit eq 'cm' ? $dim * $wscale / $width * 0.0352778 :
$hunit eq 'pc' ? 470 * $wscale / $width * 0.0833333 : $hunit eq 'pc' ? $dim * $wscale / $width * 0.0833333 :
$wscale; $wscale;
$hscale = $hunit eq 'pt' ? 470 * $hscale / $height : $hscale = $hunit eq 'pt' ? $dim * $hscale / $height :
$hunit eq 'px' ? 470 * $hscale / $height * 0.96 : $hunit eq 'px' ? $dim * $hscale / $height * 0.96 :
$hunit eq 'in' ? 470 * $hscale / $height * 0.0138889 : $hunit eq 'in' ? $dim * $hscale / $height * 0.0138889 :
$hunit eq 'mm' ? 470 * $hscale / $height * 0.352778 : $hunit eq 'mm' ? $dim * $hscale / $height * 0.352778 :
$hunit eq 'cm' ? 470 * $hscale / $height * 0.0352778 : $hunit eq 'cm' ? $dim * $hscale / $height * 0.0352778 :
$hunit eq 'pc' ? 470 * $hscale / $height * 0.0833333 : $hunit eq 'pc' ? $dim * $hscale / $height * 0.0833333 :
$hscale; $hscale;
$wscale = sprintf "%.2f", $wscale; $wscale = sprintf "%.2f", $wscale;
$hscale = sprintf "%.2f", $hscale; $hscale = sprintf "%.2f", $hscale;
my $widthnormpt = (sprintf "%.0f", (470 * (1 + $wscale))).'pt'; # Breite auf Normativ in pt skaliert my $widthnormpt = (sprintf "%.0f", ($dim * (1 + $wscale))).'pt'; # Breite auf Normativ in pt skaliert
my $heightnormpt = (sprintf "%.0f", (470 * (1 + $hscale))).'pt'; # Höhe auf Normativ in pt skaliert my $heightnormpt = (sprintf "%.0f", ($dim * (1 + $hscale))).'pt'; # Höhe auf Normativ in pt skaliert
$icon =~ s/width="(.*?)"/width="$widthnormpt"/; $icon =~ s/width="(.*?)"/width="$widthnormpt"/;
$icon =~ s/height="(.*?)"/height="$heightnormpt"/; $icon =~ s/height="(.*?)"/height="$heightnormpt"/;
@ -22417,14 +22419,15 @@ to ensure that the system configuration is correct.
<ul> <ul>
<table> <table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup> <colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>lowSoc</b> </td><td>lower minimum SoC, the battery is not discharged lower than this value (> 0) </td></tr> <tr><td> <b>lowSoc</b> </td><td>lower minimum SoC - The battery is not discharged lower than this value (> 0) </td></tr>
<tr><td> <b>upSoC</b> </td><td>upper minimum SoC, the usual value of the optimum SoC is between 'lowSoC' </td></tr> <tr><td> <b>upSoC</b> </td><td>upper minimum SoC - The usual value of the optimum SoC tends to be </td></tr>
<tr><td> </td><td>and this value. </td></tr> <tr><td> </td><td>between 'lowSoC' and 'upSoC' in periods with a high PV surplus </td></tr>
<tr><td> <b>maxSoC</b> </td><td>Maximum minimum SoC, SoC value that must be reached at least every 'careCycle' days </td></tr> <tr><td> </td><td>and between 'upSoC' and 'maxSoC' in periods with a low PV surplus </td></tr>
<tr><td> </td><td>in order to balance the charge in the storage network. </td></tr> <tr><td> <b>maxSoC</b> </td><td>Maximum minimum SoC - SoC value that must be reached at least every 'careCycle' days </td></tr>
<tr><td> </td><td>The specification is optional (&lt;= 100, default: 95) </td></tr> <tr><td> </td><td>in order to balance the charge in the storage network. </td></tr>
<tr><td> <b>careCycle</b> </td><td>Maximum interval in days that may occur between two states of charge </td></tr> <tr><td> </td><td>The specification is optional (&lt;= 100, default: 95) </td></tr>
<tr><td> </td><td>of at least 'maxSoC'. The specification is optional (default: 20) </td></tr> <tr><td> <b>careCycle</b> </td><td>Maximum interval in days that may occur between two states of charge </td></tr>
<tr><td> </td><td>of at least 'maxSoC'. The specification is optional (default: 20) </td></tr>
</table> </table>
</ul> </ul>
<br> <br>
@ -24885,14 +24888,15 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<ul> <ul>
<table> <table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup> <colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>lowSoc</b> </td><td>unterer Mindest-SoC, die Batterie wird nicht tiefer als dieser Wert entladen (> 0) </td></tr> <tr><td> <b>lowSoc</b> </td><td>unterer Mindest-SoC - Die Batterie wird nicht tiefer als dieser Wert entladen (> 0) </td></tr>
<tr><td> <b>upSoC</b> </td><td>oberer Mindest-SoC, der übliche Wert des optimalen SoC bewegt sich zwischen 'lowSoC' </td></tr> <tr><td> <b>upSoC</b> </td><td>oberer Mindest-SoC - Der übliche Wert des optimalen SoC bewegt sich in Perioden mit hohen </td></tr>
<tr><td> </td><td>und diesem Wert. </td></tr> <tr><td> </td><td>PV-Überschuß tendenziell zwischen 'lowSoC' und 'upSoC', in Perioden mit geringem PV-Überschuß </td></tr>
<tr><td> <b>maxSoC</b> </td><td>maximaler Mindest-SoC, SoC Wert der mindestens im Abstand von 'careCycle' Tagen erreicht </td></tr> <tr><td> </td><td>tendenziell zwischen 'upSoC' und 'maxSoC' </td></tr>
<tr><td> </td><td>werden muß um den Ladungsausgleich im Speicherverbund auszuführen. </td></tr> <tr><td> <b>maxSoC</b> </td><td>maximaler Mindest-SoC - SoC Wert der mindestens im Abstand von 'careCycle' Tagen erreicht </td></tr>
<tr><td> </td><td>Die Angabe ist optional (&lt;= 100, default: 95) </td></tr> <tr><td> </td><td>werden muß um den Ladungsausgleich im Speicherverbund auszuführen. </td></tr>
<tr><td> <b>careCycle</b> </td><td>maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' </td></tr> <tr><td> </td><td>Die Angabe ist optional (&lt;= 100, default: 95) </td></tr>
<tr><td> </td><td>auftreten darf. Die Angabe ist optional (default: 20) </td></tr> <tr><td> <b>careCycle</b> </td><td>maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' </td></tr>
<tr><td> </td><td>auftreten darf. Die Angabe ist optional (default: 20) </td></tr>
</table> </table>
</ul> </ul>
<br> <br>