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.
# 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
obsolete
- bugfix: 76_SolarForecast: fix interruptable key and some minor fixes

View File

@ -157,6 +157,7 @@ BEGIN {
# Versions History intern
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 ".
"trackFlex now default in DWD Model, replace title Charging recommendation by Charging release ".
"_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.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 ".
"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.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 ",
@ -487,15 +488,15 @@ my $cfile = 'controls_solarforecast.txt';
# 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,
"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,
};
#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,
# "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,
"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,
};
#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,
# "17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
# };
# mögliche Debug-Module
my @dd = qw( aiProcess
aiData
@ -942,6 +943,8 @@ my %htitles = (
DE => qq{Konfigurationsprüfung der Anlage} },
jtsfft => { EN => qq{Open the 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},
DE => qq{API Abfrage erfolgreich} },
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
_batChargeRecmd ($centpars); # Batterie Ladefreigabe berechnen und erstellen
_manageConsumerData ($centpars); # Consumer Daten sammeln und Zeiten planen
_estConsumptionForecast ($centpars); # Verbrauchsprognose erstellen
_calcConsumptionForecast ($centpars); # Verbrauchsprognose erstellen
_evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren
_calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen
_calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang)
@ -11812,7 +11815,7 @@ return ($simpCstat, $starttime, $stoptime, $supplmnt);
################################################################
# Energieverbrauch Vorhersage kalkulieren
################################################################
sub _estConsumptionForecast {
sub _calcConsumptionForecast {
my $paref = shift;
my $name = $paref->{name};
my $type = $paref->{type};
@ -11840,10 +11843,7 @@ sub _estConsumptionForecast {
## Verbrauchsvorhersage für den kommenden Tag
##############################################
my $tomorrow = strftime "%a", localtime($t+86400); # Wochentagsname kommender Tag
my $totcon = 0;
my $dnum = 0;
my ($exconfc, $csme);
my (@cona, $exconfc, $csme);
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);
@ -11882,15 +11882,16 @@ sub _estConsumptionForecast {
debugLog ($paref, 'consumption|consumption_long', "History Consumption day >$n< considering possible exclusions: $dcon");
$totcon += $dcon;
$dnum++;
push @cona, $dcon;
}
if ($dnum) {
my $tomavg = int ($totcon / $dnum);
$data{$name}{current}{tomorrowconsumption} = $tomavg; # prognostizierter Durchschnittsverbrauch aller (gleicher) Wochentage
my $dnum = scalar @cona;
debugLog ($paref, 'consumption|consumption_long', "estimated Consumption for tomorrow: $tomavg, days for avg: $dnum");
if ($dnum) {
my $tomcon = sprintf "%.0f", medianArray (\@cona);
$data{$name}{current}{tomorrowconsumption} = $tomcon; # prognostizierter Verbrauch (Median) aller (gleicher) Wochentage
debugLog ($paref, 'consumption|consumption_long', "estimated Consumption for tomorrow: $tomcon, days for avg: $dnum");
}
else {
my $lang = $paref->{lang};
@ -11906,22 +11907,14 @@ sub _estConsumptionForecast {
my $nhtime = NexthoursVal ($hash, $k, "starttime", undef); # Startzeit
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;
my $consumerco = 0;
my $utime = timestringToTimestamp ($nhtime);
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 ($conhfc, $conhfcex);
for my $m (sort{$a<=>$b} keys %{$data{$name}{pvhist}}) {
next if($m eq $day); # next wenn gleicher Tag (Datum) wie heute
@ -11966,16 +11959,17 @@ sub _estConsumptionForecast {
}
}
$conhfcex->{$nhhr} += ($hcon - $consumerco) if($hcon >= $consumerco); # prognostizierter Verbrauch Ex registrierter Verbraucher
$conhfc->{$nhhr} += $hcon;
push @{$conhfcex->{"$nhhr"}}, ($hcon - $consumerco) if($hcon >= $consumerco); # prognostizierter Verbrauch (Median) Ex registrierter Verbraucher
push @{$conhfc->{"$nhhr"}}, $hcon;
$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;
my $conavg = int ($conhfc->{$nhhr} / $dnum);
$data{$name}{nexthours}{$k}{confc} = $conavg; # Durchschnittsverbrauch aller gleicher Wochentage pro Stunde
my $conavg = sprintf "%.0f", medianArray (\@{$conhfc->{$nhhr}}) if(scalar @{$conhfc->{$nhhr}});
$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
$data{$name}{circular}{sprintf("%02d",$nhhr)}{confc} = $conavg;
@ -13284,6 +13278,12 @@ sub _graphicHeader {
my $fthicon = "<a href='https://forum.fhem.de/index.php?topic=137058.0' target='_blank'>$img</a>";
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
################
my $upicon = __createUpdateIcon ($paref);
@ -13494,11 +13494,12 @@ sub _graphicHeader {
#######################
my $alias = AttrVal ($name, "alias", $name ); # Linktext als Aliasname
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{<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="1" align="left" title="$fthtitle" $dstyle> $fthicon </td>};
$header .= qq{<td colspan="2" align="center" $dstyle> $disti </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{</tr>};
@ -22418,10 +22419,11 @@ to ensure that the system configuration is correct.
<ul>
<table>
<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>upSoC</b> </td><td>upper minimum SoC, the usual value of the optimum SoC is between 'lowSoC' </td></tr>
<tr><td> </td><td>and this value. </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> <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 tends to be </td></tr>
<tr><td> </td><td>between 'lowSoC' and 'upSoC' in periods with a high PV surplus </td></tr>
<tr><td> </td><td>and between 'upSoC' and 'maxSoC' in periods with a low 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>in order to balance the charge in the storage network. </td></tr>
<tr><td> </td><td>The specification is optional (&lt;= 100, default: 95) </td></tr>
<tr><td> <b>careCycle</b> </td><td>Maximum interval in days that may occur between two states of charge </td></tr>
@ -24886,10 +24888,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<ul>
<table>
<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>upSoC</b> </td><td>oberer Mindest-SoC, der übliche Wert des optimalen SoC bewegt sich zwischen 'lowSoC' </td></tr>
<tr><td> </td><td>und diesem Wert. </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> <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 in Perioden mit hohen </td></tr>
<tr><td> </td><td>PV-Überschuß tendenziell zwischen 'lowSoC' und 'upSoC', in Perioden mit geringem PV-Überschuß </td></tr>
<tr><td> </td><td>tendenziell zwischen 'upSoC' und 'maxSoC' </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>werden muß um den Ladungsausgleich im Speicherverbund auszuführen. </td></tr>
<tr><td> </td><td>Die Angabe ist optional (&lt;= 100, default: 95) </td></tr>
<tr><td> <b>careCycle</b> </td><td>maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' </td></tr>

View File

@ -157,6 +157,7 @@ BEGIN {
# Versions History intern
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 ".
"trackFlex now default in DWD Model, replace title Charging recommendation by Charging release ".
"_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.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 ".
"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.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 ",
@ -487,15 +488,15 @@ my $cfile = 'controls_solarforecast.txt';
# 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,
"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,
};
#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,
# "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,
"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,
};
#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,
# "17" => 0, "18" => 0, "19" => 0, "20" => 0, "21" => 0, "22" => 0, "23" => 0, "24" => 0,
# };
# mögliche Debug-Module
my @dd = qw( aiProcess
aiData
@ -942,6 +943,8 @@ my %htitles = (
DE => qq{Konfigurationspr&#252;fung der Anlage} },
jtsfft => { EN => qq{Open the 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},
DE => qq{API Abfrage erfolgreich} },
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
_batChargeRecmd ($centpars); # Batterie Ladefreigabe berechnen und erstellen
_manageConsumerData ($centpars); # Consumer Daten sammeln und Zeiten planen
_estConsumptionForecast ($centpars); # Verbrauchsprognose erstellen
_calcConsumptionForecast ($centpars); # Verbrauchsprognose erstellen
_evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren
_calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen
_calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang)
@ -11812,7 +11815,7 @@ return ($simpCstat, $starttime, $stoptime, $supplmnt);
################################################################
# Energieverbrauch Vorhersage kalkulieren
################################################################
sub _estConsumptionForecast {
sub _calcConsumptionForecast {
my $paref = shift;
my $name = $paref->{name};
my $type = $paref->{type};
@ -11840,10 +11843,7 @@ sub _estConsumptionForecast {
## Verbrauchsvorhersage für den kommenden Tag
##############################################
my $tomorrow = strftime "%a", localtime($t+86400); # Wochentagsname kommender Tag
my $totcon = 0;
my $dnum = 0;
my ($exconfc, $csme);
my (@cona, $exconfc, $csme);
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);
@ -11882,15 +11882,16 @@ sub _estConsumptionForecast {
debugLog ($paref, 'consumption|consumption_long', "History Consumption day >$n< considering possible exclusions: $dcon");
$totcon += $dcon;
$dnum++;
push @cona, $dcon;
}
if ($dnum) {
my $tomavg = int ($totcon / $dnum);
$data{$name}{current}{tomorrowconsumption} = $tomavg; # prognostizierter Durchschnittsverbrauch aller (gleicher) Wochentage
my $dnum = scalar @cona;
debugLog ($paref, 'consumption|consumption_long', "estimated Consumption for tomorrow: $tomavg, days for avg: $dnum");
if ($dnum) {
my $tomcon = sprintf "%.0f", medianArray (\@cona);
$data{$name}{current}{tomorrowconsumption} = $tomcon; # prognostizierter Verbrauch (Median) aller (gleicher) Wochentage
debugLog ($paref, 'consumption|consumption_long', "estimated Consumption for tomorrow: $tomcon, days for avg: $dnum");
}
else {
my $lang = $paref->{lang};
@ -11906,22 +11907,14 @@ sub _estConsumptionForecast {
my $nhtime = NexthoursVal ($hash, $k, "starttime", undef); # Startzeit
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;
my $consumerco = 0;
my $utime = timestringToTimestamp ($nhtime);
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 ($conhfc, $conhfcex);
for my $m (sort{$a<=>$b} keys %{$data{$name}{pvhist}}) {
next if($m eq $day); # next wenn gleicher Tag (Datum) wie heute
@ -11966,16 +11959,17 @@ sub _estConsumptionForecast {
}
}
$conhfcex->{$nhhr} += ($hcon - $consumerco) if($hcon >= $consumerco); # prognostizierter Verbrauch Ex registrierter Verbraucher
$conhfc->{$nhhr} += $hcon;
push @{$conhfcex->{"$nhhr"}}, ($hcon - $consumerco) if($hcon >= $consumerco); # prognostizierter Verbrauch (Median) Ex registrierter Verbraucher
push @{$conhfc->{"$nhhr"}}, $hcon;
$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;
my $conavg = int ($conhfc->{$nhhr} / $dnum);
$data{$name}{nexthours}{$k}{confc} = $conavg; # Durchschnittsverbrauch aller gleicher Wochentage pro Stunde
my $conavg = sprintf "%.0f", medianArray (\@{$conhfc->{$nhhr}}) if(scalar @{$conhfc->{$nhhr}});
$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
$data{$name}{circular}{sprintf("%02d",$nhhr)}{confc} = $conavg;
@ -13284,6 +13278,12 @@ sub _graphicHeader {
my $fthicon = "<a href='https://forum.fhem.de/index.php?topic=137058.0' target='_blank'>$img</a>";
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
################
my $upicon = __createUpdateIcon ($paref);
@ -13494,11 +13494,12 @@ sub _graphicHeader {
#######################
my $alias = AttrVal ($name, "alias", $name ); # Linktext als Aliasname
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{<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="1" align="left" title="$fthtitle" $dstyle> $fthicon </td>};
$header .= qq{<td colspan="2" align="center" $dstyle> $disti </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{</tr>};
@ -15459,7 +15460,7 @@ END0
$cc_dummy -= $currentPower;
$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 .= "<title>$calias</title>".$cicon;
@ -15488,7 +15489,7 @@ END1
## Home Icon
##############
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 .= "<title>Home</title>".$hicon;
@ -15500,7 +15501,7 @@ END1
my $dumtxt = $htitles{dumtxt}{$lang};
my $dumcol = $cc_dummy <= 0 ? '@grey' : q{}; # Einfärbung Consumer Dummy
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 .= "<title>$dumtxt</title>".$dicon;
@ -15810,7 +15811,7 @@ sub __addProducerIcon {
);
$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 .= "<title>$ptxt</title>".$picon;
@ -15847,7 +15848,7 @@ sub __addNodeIcon {
);
$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
$ret .= "<title>$ntxt</title>".$nicon;
@ -16034,8 +16035,9 @@ return $p;
# scale: 0.10 Normativ $fgscaledef
################################################################
sub __normIconScale {
my $icon = shift;
my $name = shift;
my $icon = shift;
my $dim = shift // 470; # Dimension
my $hscale = $fgscaledef; # Scale Normativ
my $wscale = $fgscaledef;
@ -16044,27 +16046,27 @@ sub __normIconScale {
return ($hscale, $icon) if(!$width || !$height);
$wscale = $hunit eq 'pt' ? 470 * $wscale / $width :
$hunit eq 'px' ? 470 * $wscale / $width * 0.96 :
$hunit eq 'in' ? 470 * $wscale / $width * 0.0138889 :
$hunit eq 'mm' ? 470 * $wscale / $width * 0.352778 :
$hunit eq 'cm' ? 470 * $wscale / $width * 0.0352778 :
$hunit eq 'pc' ? 470 * $wscale / $width * 0.0833333 :
$wscale = $hunit eq 'pt' ? $dim * $wscale / $width :
$hunit eq 'px' ? $dim * $wscale / $width * 0.96 :
$hunit eq 'in' ? $dim * $wscale / $width * 0.0138889 :
$hunit eq 'mm' ? $dim * $wscale / $width * 0.352778 :
$hunit eq 'cm' ? $dim * $wscale / $width * 0.0352778 :
$hunit eq 'pc' ? $dim * $wscale / $width * 0.0833333 :
$wscale;
$hscale = $hunit eq 'pt' ? 470 * $hscale / $height :
$hunit eq 'px' ? 470 * $hscale / $height * 0.96 :
$hunit eq 'in' ? 470 * $hscale / $height * 0.0138889 :
$hunit eq 'mm' ? 470 * $hscale / $height * 0.352778 :
$hunit eq 'cm' ? 470 * $hscale / $height * 0.0352778 :
$hunit eq 'pc' ? 470 * $hscale / $height * 0.0833333 :
$hscale = $hunit eq 'pt' ? $dim * $hscale / $height :
$hunit eq 'px' ? $dim * $hscale / $height * 0.96 :
$hunit eq 'in' ? $dim * $hscale / $height * 0.0138889 :
$hunit eq 'mm' ? $dim * $hscale / $height * 0.352778 :
$hunit eq 'cm' ? $dim * $hscale / $height * 0.0352778 :
$hunit eq 'pc' ? $dim * $hscale / $height * 0.0833333 :
$hscale;
$wscale = sprintf "%.2f", $wscale;
$hscale = sprintf "%.2f", $hscale;
my $widthnormpt = (sprintf "%.0f", (470 * (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 $widthnormpt = (sprintf "%.0f", ($dim * (1 + $wscale))).'pt'; # Breite 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/height="(.*?)"/height="$heightnormpt"/;
@ -22417,10 +22419,11 @@ to ensure that the system configuration is correct.
<ul>
<table>
<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>upSoC</b> </td><td>upper minimum SoC, the usual value of the optimum SoC is between 'lowSoC' </td></tr>
<tr><td> </td><td>and this value. </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> <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 tends to be </td></tr>
<tr><td> </td><td>between 'lowSoC' and 'upSoC' in periods with a high PV surplus </td></tr>
<tr><td> </td><td>and between 'upSoC' and 'maxSoC' in periods with a low 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>in order to balance the charge in the storage network. </td></tr>
<tr><td> </td><td>The specification is optional (&lt;= 100, default: 95) </td></tr>
<tr><td> <b>careCycle</b> </td><td>Maximum interval in days that may occur between two states of charge </td></tr>
@ -24885,10 +24888,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<ul>
<table>
<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>upSoC</b> </td><td>oberer Mindest-SoC, der übliche Wert des optimalen SoC bewegt sich zwischen 'lowSoC' </td></tr>
<tr><td> </td><td>und diesem Wert. </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> <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 in Perioden mit hohen </td></tr>
<tr><td> </td><td>PV-Überschuß tendenziell zwischen 'lowSoC' und 'upSoC', in Perioden mit geringem PV-Überschuß </td></tr>
<tr><td> </td><td>tendenziell zwischen 'upSoC' und 'maxSoC' </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>werden muß um den Ladungsausgleich im Speicherverbund auszuführen. </td></tr>
<tr><td> </td><td>Die Angabe ist optional (&lt;= 100, default: 95) </td></tr>
<tr><td> <b>careCycle</b> </td><td>maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' </td></tr>