2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 12:49:34 +00:00

76_SolarForecast: contrib 0.80.17

git-svn-id: https://svn.fhem.de/fhem/trunk@27801 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2023-07-27 21:44:21 +00:00
parent e1862cc480
commit 5ce01ef9fd

View File

@ -1,5 +1,5 @@
########################################################################################################################
# $Id: 76_SolarForecast.pm 21735 2023-07-26 23:53:24Z DS_Starter $
# $Id: 76_SolarForecast.pm 21735 2023-07-27 23:53:24Z DS_Starter $
#########################################################################################################################
# 76_SolarForecast.pm
#
@ -136,6 +136,7 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
"0.80.17"=> "27.07.2023 change sequence of _createSummaries in centralTask ",
"0.80.16"=> "26.07.2023 new consumer type noSchedule, expand maxconsumer to 16, minor changes/fixes ",
"0.80.15"=> "24.07.2023 new sub getDebug, new key switchdev in consumer attributes, change Debug consumtion ".
"reorg data in pvHistory when a hour of day was deleted ",
@ -3922,11 +3923,11 @@ sub centralTask {
_transferInverterValues ($centpars); # WR Werte übertragen
_transferMeterValues ($centpars); # Energy Meter auswerten
_transferBatteryValues ($centpars); # Batteriewerte einsammeln
_createSummaries ($centpars); # Zusammenfassungen erstellen
_manageConsumerData ($centpars); # Consumerdaten sammeln und planen
_estConsumptionForecast ($centpars); # Verbrauchsprognose erstellen
_evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren
_calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen
_createSummaries ($centpars); # Zusammenfassungen erstellen
_calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang)
createReadingsFromArray ($hash, \@da, $evt); # Readings erzeugen
@ -5075,6 +5076,309 @@ sub _transferMeterValues {
return;
}
################################################################
# Batteriewerte sammeln
################################################################
sub _transferBatteryValues {
my $paref = shift;
my $hash = $paref->{hash};
my $name = $paref->{name};
my $chour = $paref->{chour};
my $day = $paref->{day};
my $daref = $paref->{daref};
my ($badev,$a,$h) = useBattery ($name);
return if(!$badev);
my $type = $paref->{type};
my ($pin,$piunit) = split ":", $h->{pin}; # Readingname/Unit für aktuelle Batterieladung
my ($pou,$pounit) = split ":", $h->{pout}; # Readingname/Unit für aktuelle Batterieentladung
my ($bin,$binunit) = split ":", $h->{intotal} // "-:-"; # Readingname/Unit der total in die Batterie eingespeisten Energie (Zähler)
my ($bout,$boutunit) = split ":", $h->{outtotal} // "-:-"; # Readingname/Unit der total aus der Batterie entnommenen Energie (Zähler)
my $batchr = $h->{charge} // ""; # Readingname Ladezustand Batterie
return if(!$pin || !$pou);
$pounit //= $piunit;
$piunit //= $pounit;
$boutunit //= $binunit;
$binunit //= $boutunit;
my $piuf = $piunit =~ /^kW$/xi ? 1000 : 1;
my $pouf = $pounit =~ /^kW$/xi ? 1000 : 1;
my $binuf = $binunit =~ /^kWh$/xi ? 1000 : 1;
my $boutuf = $boutunit =~ /^kWh$/xi ? 1000 : 1;
my $pbo = ReadingsNum ($badev, $pou, 0) * $pouf; # aktuelle Batterieentladung (W)
my $pbi = ReadingsNum ($badev, $pin, 0) * $piuf; # aktueller Batterieladung (W)
my $btotout = ReadingsNum ($badev, $bout, 0) * $boutuf; # totale Batterieentladung (Wh)
my $btotin = ReadingsNum ($badev, $bin, 0) * $binuf; # totale Batterieladung (Wh)
my $soc = ReadingsNum ($badev, $batchr, 0);
my $debug = $paref->{debug};
if($debug =~ /collectData/x) {
Log3 ($name, 1, "$name DEBUG> collect Battery data: device=$badev =>");
Log3 ($name, 1, "$name DEBUG> pin=$pbi W, pout=$pbo W, totalin: $btotin Wh, totalout: $btotout Wh, soc: $soc");
}
my $params;
if ($pin eq "-pout") { # Spezialfall pin bei neg. pout
$params = {
dev => $badev,
rdg => $pou,
rdgf => $pouf
};
($pbo,$pbi) = substSpecialCases ($params);
}
if ($pou eq "-pin") { # Spezialfall pout bei neg. pin
$params = {
dev => $badev,
rdg => $pin,
rdgf => $piuf
};
($pbi,$pbo) = substSpecialCases ($params);
}
# Batterielade-, enladeenergie in Circular speichern
######################################################
if (!defined CircularVal ($hash, 99, 'initdaybatintot', undef)) {
$data{$type}{$name}{circular}{99}{initdaybatintot} = $btotin; # total Batterieladung zu Tagbeginn (Wh)
}
if (!defined CircularVal ($hash, 99, 'initdaybatouttot', undef)) { # total Batterieentladung zu Tagbeginn (Wh)
$data{$type}{$name}{circular}{99}{initdaybatouttot} = $btotout;
}
$data{$type}{$name}{circular}{99}{batintot} = $btotin; # aktuell total Batterieladung
$data{$type}{$name}{circular}{99}{batouttot} = $btotout; # aktuell total Batterieentladung
my $nhour = $chour+1;
# Batterieladung aktuelle Stunde in pvHistory speichern
#########################################################
my $histbatintot = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "batintotal", undef); # totale Batterieladung zu Beginn einer Stunde
my $batinthishour;
if (!defined $histbatintot) { # totale Batterieladung der aktuelle Stunde gesetzt ?
$paref->{batintotal} = $btotin;
$paref->{nhour} = sprintf("%02d",$nhour);
$paref->{histname} = "batintotal";
setPVhistory ($paref);
delete $paref->{histname};
my $bitot = CurrentVal ($hash, "batintotal", $btotin);
$batinthishour = int ($btotin - $bitot);
}
else {
$batinthishour = int ($btotin - $histbatintot);
}
if ($batinthishour < 0) {
$batinthishour = 0;
}
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{batin} = $batinthishour; # Ringspeicher Battery In Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$paref->{batinthishour} = $batinthishour;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = "batinthishour";
setPVhistory ($paref);
delete $paref->{histname};
# Batterieentladung aktuelle Stunde in pvHistory speichern
############################################################
my $histbatouttot = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "batouttotal", undef); # totale Betterieladung zu Beginn einer Stunde
my $batoutthishour;
if(!defined $histbatouttot) { # totale Betterieladung der aktuelle Stunde gesetzt ?
$paref->{batouttotal} = $btotout;
$paref->{nhour} = sprintf("%02d",$nhour);
$paref->{histname} = "batouttotal";
setPVhistory ($paref);
delete $paref->{histname};
my $botot = CurrentVal ($hash, "batouttotal", $btotout);
$batoutthishour = int ($btotout - $botot);
}
else {
$batoutthishour = int ($btotout - $histbatouttot);
}
if($batoutthishour < 0) {
$batoutthishour = 0;
}
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{batout} = $batoutthishour; # Ringspeicher Battery In Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$paref->{batoutthishour} = $batoutthishour;
$paref->{nhour} = sprintf("%02d",$nhour);
$paref->{histname} = "batoutthishour";
setPVhistory ($paref);
delete $paref->{histname};
######
push @$daref, "Today_Hour".sprintf("%02d",$nhour)."_BatIn<>". $batinthishour. " Wh";
push @$daref, "Today_Hour".sprintf("%02d",$nhour)."_BatOut<>". $batoutthishour." Wh";
push @$daref, "Current_PowerBatIn<>". (int $pbi)." W";
push @$daref, "Current_PowerBatOut<>". (int $pbo)." W";
push @$daref, "Current_BatCharge<>". $soc. " %";
$data{$type}{$name}{current}{powerbatin} = int $pbi; # Hilfshash Wert aktuelle Batterieladung
$data{$type}{$name}{current}{powerbatout} = int $pbo; # Hilfshash Wert aktuelle Batterieentladung
$data{$type}{$name}{current}{batcharge} = $soc; # aktuelle Batterieladung
return;
}
################################################################
# Zusammenfassungen erstellen
################################################################
sub _createSummaries {
my $paref = shift;
my $hash = $paref->{hash};
my $name = $paref->{name};
my $type = $paref->{type};
my $daref = $paref->{daref};
my $chour = $paref->{chour}; # aktuelle Stunde
my $minute = $paref->{minute}; # aktuelle Minute
$minute = (int $minute) + 1; # Minute Range umsetzen auf 1 bis 60
## Initialisierung
####################
my $next1HoursSum = { "PV" => 0, "Consumption" => 0 };
my $next2HoursSum = { "PV" => 0, "Consumption" => 0 };
my $next3HoursSum = { "PV" => 0, "Consumption" => 0 };
my $next4HoursSum = { "PV" => 0, "Consumption" => 0 };
my $restOfDaySum = { "PV" => 0, "Consumption" => 0 };
my $tomorrowSum = { "PV" => 0, "Consumption" => 0 };
my $todaySumFc = { "PV" => 0, "Consumption" => 0 };
my $todaySumRe = { "PV" => 0, "Consumption" => 0 };
my $tdConFcTillSunset = 0;
my $remainminutes = 60 - $minute; # verbleibende Minuten der aktuellen Stunde
my $restofhourpvfc = (NexthoursVal($hash, "NextHour00", "pvforecast", 0)) / 60 * $remainminutes;
my $restofhourconfc = (NexthoursVal($hash, "NextHour00", "confc", 0)) / 60 * $remainminutes;
$next1HoursSum->{PV} = $restofhourpvfc;
$next2HoursSum->{PV} = $restofhourpvfc;
$next3HoursSum->{PV} = $restofhourpvfc;
$next4HoursSum->{PV} = $restofhourpvfc;
$restOfDaySum->{PV} = $restofhourpvfc;
$next1HoursSum->{Consumption} = $restofhourconfc;
$next2HoursSum->{Consumption} = $restofhourconfc;
$next3HoursSum->{Consumption} = $restofhourconfc;
$next4HoursSum->{Consumption} = $restofhourconfc;
$restOfDaySum->{Consumption} = $restofhourconfc;
for my $h (1..47) {
my $pvfc = NexthoursVal ($hash, "NextHour".sprintf("%02d",$h), 'pvforecast', 0);
my $confc = NexthoursVal ($hash, "NextHour".sprintf("%02d",$h), 'confc', 0);
my $istdy = NexthoursVal ($hash, "NextHour".sprintf("%02d",$h), 'today', 0);
my $don = NexthoursVal ($hash, "NextHour".sprintf("%02d",$h), 'DoN', 0);
$pvfc = 0 if($pvfc < 0); # PV Prognose darf nicht negativ sein
$confc = 0 if($confc < 0); # Verbrauchsprognose darf nicht negativ sein
if($h == 1) {
$next1HoursSum->{PV} += $pvfc / 60 * $minute;
$next1HoursSum->{Consumption} += $confc / 60 * $minute;
}
if($h <= 2) {
$next2HoursSum->{PV} += $pvfc if($h < 2);
$next2HoursSum->{PV} += $pvfc / 60 * $minute if($h == 2);
$next2HoursSum->{Consumption} += $confc if($h < 2);
$next2HoursSum->{Consumption} += $confc / 60 * $minute if($h == 2);
}
if($h <= 3) {
$next3HoursSum->{PV} += $pvfc if($h < 3);
$next3HoursSum->{PV} += $pvfc / 60 * $minute if($h == 3);
$next3HoursSum->{Consumption} += $confc if($h < 3);
$next3HoursSum->{Consumption} += $confc / 60 * $minute if($h == 3);
}
if($h <= 4) {
$next4HoursSum->{PV} += $pvfc if($h < 4);
$next4HoursSum->{PV} += $pvfc / 60 * $minute if($h == 4);
$next4HoursSum->{Consumption} += $confc if($h < 4);
$next4HoursSum->{Consumption} += $confc / 60 * $minute if($h == 4);
}
if($istdy) {
$restOfDaySum->{PV} += $pvfc;
$restOfDaySum->{Consumption} += $confc;
$tdConFcTillSunset += $confc if($don);
}
else {
$tomorrowSum->{PV} += $pvfc;
}
}
for my $th (1..24) {
$todaySumFc->{PV} += ReadingsNum($name, "Today_Hour".sprintf("%02d",$th)."_PVforecast", 0);
$todaySumRe->{PV} += ReadingsNum($name, "Today_Hour".sprintf("%02d",$th)."_PVreal", 0);
}
push @{$data{$type}{$name}{current}{h4fcslidereg}}, int $next4HoursSum->{PV}; # Schieberegister 4h Summe Forecast
limitArray ($data{$type}{$name}{current}{h4fcslidereg}, $defslidenum);
my $gcon = CurrentVal ($hash, "gridconsumption", 0); # aktueller Netzbezug
my $tconsum = CurrentVal ($hash, "tomorrowconsumption", undef); # Verbrauchsprognose für folgenden Tag
my $pvgen = CurrentVal ($hash, "generation", 0);
my $gfeedin = CurrentVal ($hash, "gridfeedin", 0);
my $batin = CurrentVal ($hash, "powerbatin", 0); # aktuelle Batterieladung
my $batout = CurrentVal ($hash, "powerbatout", 0); # aktuelle Batterieentladung
my $consumption = int ($pvgen - $gfeedin + $gcon - $batin + $batout);
my $selfconsumption = int ($pvgen - $gfeedin - $batin);
$selfconsumption = $selfconsumption < 0 ? 0 : $selfconsumption;
my $surplus = int ($pvgen - $consumption); # aktueller Überschuß
$surplus = 0 if($surplus < 0); # wegen Vergleich nompower vs. surplus
my $selfconsumptionrate = 0;
my $autarkyrate = 0;
$selfconsumptionrate = sprintf "%.0f", $selfconsumption / $pvgen * 100 if($pvgen * 1 > 0);
$autarkyrate = sprintf "%.0f", ($selfconsumption + $batout) / ($selfconsumption + $batout + $gcon) * 100 if($selfconsumption + $batout);
$data{$type}{$name}{current}{consumption} = $consumption;
$data{$type}{$name}{current}{selfconsumption} = $selfconsumption;
$data{$type}{$name}{current}{selfconsumptionrate} = $selfconsumptionrate;
$data{$type}{$name}{current}{autarkyrate} = $autarkyrate;
$data{$type}{$name}{current}{surplus} = $surplus;
$data{$type}{$name}{current}{tdConFcTillSunset} = $tdConFcTillSunset;
push @$daref, "Current_Consumption<>". $consumption. " W";
push @$daref, "Current_SelfConsumption<>". $selfconsumption. " W";
push @$daref, "Current_SelfConsumptionRate<>". $selfconsumptionrate. " %";
push @$daref, "Current_Surplus<>". $surplus. " W";
push @$daref, "Current_AutarkyRate<>". $autarkyrate. " %";
push @$daref, "NextHours_Sum01_PVforecast<>". (int $next1HoursSum->{PV})." Wh";
push @$daref, "NextHours_Sum02_PVforecast<>". (int $next2HoursSum->{PV})." Wh";
push @$daref, "NextHours_Sum03_PVforecast<>". (int $next3HoursSum->{PV})." Wh";
push @$daref, "NextHours_Sum04_PVforecast<>". (int $next4HoursSum->{PV})." Wh";
push @$daref, "RestOfDayPVforecast<>". (int $restOfDaySum->{PV}). " Wh";
push @$daref, "Tomorrow_PVforecast<>". (int $tomorrowSum->{PV}). " Wh";
push @$daref, "Today_PVforecast<>". (int $todaySumFc->{PV}). " Wh";
push @$daref, "Today_PVreal<>". (int $todaySumRe->{PV}). " Wh" if(int $todaySumRe->{PV} > ReadingsNum($name, 'Today_PVreal', 0));
push @$daref, "Tomorrow_ConsumptionForecast<>". $tconsum. " Wh" if(defined $tconsum);
push @$daref, "NextHours_Sum04_ConsumptionForecast<>". (int $next4HoursSum->{Consumption})." Wh";
push @$daref, "RestOfDayConsumptionForecast<>". (int $restOfDaySum->{Consumption}). " Wh";
return;
}
################################################################
# Consumer - Energieverbrauch aufnehmen
# - Masterdata ergänzen
@ -6336,166 +6640,6 @@ sub __getPlanningStateAndTimes {
return ($pstate, $starttime, $stoptime);
}
################################################################
# Batteriewerte sammeln
################################################################
sub _transferBatteryValues {
my $paref = shift;
my $hash = $paref->{hash};
my $name = $paref->{name};
my $chour = $paref->{chour};
my $day = $paref->{day};
my $daref = $paref->{daref};
my ($badev,$a,$h) = useBattery ($name);
return if(!$badev);
my $type = $paref->{type};
my ($pin,$piunit) = split ":", $h->{pin}; # Readingname/Unit für aktuelle Batterieladung
my ($pou,$pounit) = split ":", $h->{pout}; # Readingname/Unit für aktuelle Batterieentladung
my ($bin,$binunit) = split ":", $h->{intotal} // "-:-"; # Readingname/Unit der total in die Batterie eingespeisten Energie (Zähler)
my ($bout,$boutunit) = split ":", $h->{outtotal} // "-:-"; # Readingname/Unit der total aus der Batterie entnommenen Energie (Zähler)
my $batchr = $h->{charge} // ""; # Readingname Ladezustand Batterie
return if(!$pin || !$pou);
$pounit //= $piunit;
$piunit //= $pounit;
$boutunit //= $binunit;
$binunit //= $boutunit;
my $piuf = $piunit =~ /^kW$/xi ? 1000 : 1;
my $pouf = $pounit =~ /^kW$/xi ? 1000 : 1;
my $binuf = $binunit =~ /^kWh$/xi ? 1000 : 1;
my $boutuf = $boutunit =~ /^kWh$/xi ? 1000 : 1;
my $pbo = ReadingsNum ($badev, $pou, 0) * $pouf; # aktuelle Batterieentladung (W)
my $pbi = ReadingsNum ($badev, $pin, 0) * $piuf; # aktueller Batterieladung (W)
my $btotout = ReadingsNum ($badev, $bout, 0) * $boutuf; # totale Batterieentladung (Wh)
my $btotin = ReadingsNum ($badev, $bin, 0) * $binuf; # totale Batterieladung (Wh)
my $soc = ReadingsNum ($badev, $batchr, 0);
my $debug = $paref->{debug};
if($debug =~ /collectData/x) {
Log3 ($name, 1, "$name DEBUG> collect Battery data: device=$badev =>");
Log3 ($name, 1, "$name DEBUG> pin=$pbi W, pout=$pbo W, totalin: $btotin Wh, totalout: $btotout Wh, soc: $soc");
}
my $params;
if ($pin eq "-pout") { # Spezialfall pin bei neg. pout
$params = {
dev => $badev,
rdg => $pou,
rdgf => $pouf
};
($pbo,$pbi) = substSpecialCases ($params);
}
if ($pou eq "-pin") { # Spezialfall pout bei neg. pin
$params = {
dev => $badev,
rdg => $pin,
rdgf => $piuf
};
($pbi,$pbo) = substSpecialCases ($params);
}
# Batterielade-, enladeenergie in Circular speichern
######################################################
if (!defined CircularVal ($hash, 99, 'initdaybatintot', undef)) {
$data{$type}{$name}{circular}{99}{initdaybatintot} = $btotin; # total Batterieladung zu Tagbeginn (Wh)
}
if (!defined CircularVal ($hash, 99, 'initdaybatouttot', undef)) { # total Batterieentladung zu Tagbeginn (Wh)
$data{$type}{$name}{circular}{99}{initdaybatouttot} = $btotout;
}
$data{$type}{$name}{circular}{99}{batintot} = $btotin; # aktuell total Batterieladung
$data{$type}{$name}{circular}{99}{batouttot} = $btotout; # aktuell total Batterieentladung
my $nhour = $chour+1;
# Batterieladung aktuelle Stunde in pvHistory speichern
#########################################################
my $histbatintot = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "batintotal", undef); # totale Batterieladung zu Beginn einer Stunde
my $batinthishour;
if (!defined $histbatintot) { # totale Batterieladung der aktuelle Stunde gesetzt ?
$paref->{batintotal} = $btotin;
$paref->{nhour} = sprintf("%02d",$nhour);
$paref->{histname} = "batintotal";
setPVhistory ($paref);
delete $paref->{histname};
my $bitot = CurrentVal ($hash, "batintotal", $btotin);
$batinthishour = int ($btotin - $bitot);
}
else {
$batinthishour = int ($btotin - $histbatintot);
}
if ($batinthishour < 0) {
$batinthishour = 0;
}
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{batin} = $batinthishour; # Ringspeicher Battery In Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$paref->{batinthishour} = $batinthishour;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = "batinthishour";
setPVhistory ($paref);
delete $paref->{histname};
# Batterieentladung aktuelle Stunde in pvHistory speichern
############################################################
my $histbatouttot = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "batouttotal", undef); # totale Betterieladung zu Beginn einer Stunde
my $batoutthishour;
if(!defined $histbatouttot) { # totale Betterieladung der aktuelle Stunde gesetzt ?
$paref->{batouttotal} = $btotout;
$paref->{nhour} = sprintf("%02d",$nhour);
$paref->{histname} = "batouttotal";
setPVhistory ($paref);
delete $paref->{histname};
my $botot = CurrentVal ($hash, "batouttotal", $btotout);
$batoutthishour = int ($btotout - $botot);
}
else {
$batoutthishour = int ($btotout - $histbatouttot);
}
if($batoutthishour < 0) {
$batoutthishour = 0;
}
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{batout} = $batoutthishour; # Ringspeicher Battery In Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$paref->{batoutthishour} = $batoutthishour;
$paref->{nhour} = sprintf("%02d",$nhour);
$paref->{histname} = "batoutthishour";
setPVhistory ($paref);
delete $paref->{histname};
######
push @$daref, "Today_Hour".sprintf("%02d",$nhour)."_BatIn<>". $batinthishour. " Wh";
push @$daref, "Today_Hour".sprintf("%02d",$nhour)."_BatOut<>". $batoutthishour." Wh";
push @$daref, "Current_PowerBatIn<>". (int $pbi)." W";
push @$daref, "Current_PowerBatOut<>". (int $pbo)." W";
push @$daref, "Current_BatCharge<>". $soc. " %";
$data{$type}{$name}{current}{powerbatin} = int $pbi; # Hilfshash Wert aktuelle Batterieladung
$data{$type}{$name}{current}{powerbatout} = int $pbo; # Hilfshash Wert aktuelle Batterieentladung
$data{$type}{$name}{current}{batcharge} = $soc; # aktuelle Batterieladung
return;
}
################################################################
# Energieverbrauch Vorhersage kalkulieren
#
@ -6747,149 +6891,6 @@ sub _calcReadingsTomorrowPVFc {
return;
}
################################################################
# Zusammenfassungen erstellen
################################################################
sub _createSummaries {
my $paref = shift;
my $hash = $paref->{hash};
my $name = $paref->{name};
my $type = $paref->{type};
my $daref = $paref->{daref};
my $chour = $paref->{chour}; # aktuelle Stunde
my $minute = $paref->{minute}; # aktuelle Minute
$minute = (int $minute) + 1; # Minute Range umsetzen auf 1 bis 60
## Initialisierung
####################
my $next1HoursSum = { "PV" => 0, "Consumption" => 0 };
my $next2HoursSum = { "PV" => 0, "Consumption" => 0 };
my $next3HoursSum = { "PV" => 0, "Consumption" => 0 };
my $next4HoursSum = { "PV" => 0, "Consumption" => 0 };
my $restOfDaySum = { "PV" => 0, "Consumption" => 0 };
my $tomorrowSum = { "PV" => 0, "Consumption" => 0 };
my $todaySumFc = { "PV" => 0, "Consumption" => 0 };
my $todaySumRe = { "PV" => 0, "Consumption" => 0 };
my $tdConFcTillSunset = 0;
my $remainminutes = 60 - $minute; # verbleibende Minuten der aktuellen Stunde
my $restofhourpvfc = (NexthoursVal($hash, "NextHour00", "pvforecast", 0)) / 60 * $remainminutes;
my $restofhourconfc = (NexthoursVal($hash, "NextHour00", "confc", 0)) / 60 * $remainminutes;
$next1HoursSum->{PV} = $restofhourpvfc;
$next2HoursSum->{PV} = $restofhourpvfc;
$next3HoursSum->{PV} = $restofhourpvfc;
$next4HoursSum->{PV} = $restofhourpvfc;
$restOfDaySum->{PV} = $restofhourpvfc;
$next1HoursSum->{Consumption} = $restofhourconfc;
$next2HoursSum->{Consumption} = $restofhourconfc;
$next3HoursSum->{Consumption} = $restofhourconfc;
$next4HoursSum->{Consumption} = $restofhourconfc;
$restOfDaySum->{Consumption} = $restofhourconfc;
for my $h (1..47) {
my $pvfc = NexthoursVal ($hash, "NextHour".sprintf("%02d",$h), 'pvforecast', 0);
my $confc = NexthoursVal ($hash, "NextHour".sprintf("%02d",$h), 'confc', 0);
my $istdy = NexthoursVal ($hash, "NextHour".sprintf("%02d",$h), 'today', 0);
my $don = NexthoursVal ($hash, "NextHour".sprintf("%02d",$h), 'DoN', 0);
$pvfc = 0 if($pvfc < 0); # PV Prognose darf nicht negativ sein
$confc = 0 if($confc < 0); # Verbrauchsprognose darf nicht negativ sein
if($h == 1) {
$next1HoursSum->{PV} += $pvfc / 60 * $minute;
$next1HoursSum->{Consumption} += $confc / 60 * $minute;
}
if($h <= 2) {
$next2HoursSum->{PV} += $pvfc if($h < 2);
$next2HoursSum->{PV} += $pvfc / 60 * $minute if($h == 2);
$next2HoursSum->{Consumption} += $confc if($h < 2);
$next2HoursSum->{Consumption} += $confc / 60 * $minute if($h == 2);
}
if($h <= 3) {
$next3HoursSum->{PV} += $pvfc if($h < 3);
$next3HoursSum->{PV} += $pvfc / 60 * $minute if($h == 3);
$next3HoursSum->{Consumption} += $confc if($h < 3);
$next3HoursSum->{Consumption} += $confc / 60 * $minute if($h == 3);
}
if($h <= 4) {
$next4HoursSum->{PV} += $pvfc if($h < 4);
$next4HoursSum->{PV} += $pvfc / 60 * $minute if($h == 4);
$next4HoursSum->{Consumption} += $confc if($h < 4);
$next4HoursSum->{Consumption} += $confc / 60 * $minute if($h == 4);
}
if($istdy) {
$restOfDaySum->{PV} += $pvfc;
$restOfDaySum->{Consumption} += $confc;
$tdConFcTillSunset += $confc if($don);
}
else {
$tomorrowSum->{PV} += $pvfc;
}
}
for my $th (1..24) {
$todaySumFc->{PV} += ReadingsNum($name, "Today_Hour".sprintf("%02d",$th)."_PVforecast", 0);
$todaySumRe->{PV} += ReadingsNum($name, "Today_Hour".sprintf("%02d",$th)."_PVreal", 0);
}
push @{$data{$type}{$name}{current}{h4fcslidereg}}, int $next4HoursSum->{PV}; # Schieberegister 4h Summe Forecast
limitArray ($data{$type}{$name}{current}{h4fcslidereg}, $defslidenum);
my $gcon = CurrentVal ($hash, "gridconsumption", 0); # aktueller Netzbezug
my $tconsum = CurrentVal ($hash, "tomorrowconsumption", undef); # Verbrauchsprognose für folgenden Tag
my $pvgen = CurrentVal ($hash, "generation", 0);
my $gfeedin = CurrentVal ($hash, "gridfeedin", 0);
my $batin = CurrentVal ($hash, "powerbatin", 0); # aktuelle Batterieladung
my $batout = CurrentVal ($hash, "powerbatout", 0); # aktuelle Batterieentladung
my $consumption = int ($pvgen - $gfeedin + $gcon - $batin + $batout);
my $selfconsumption = int ($pvgen - $gfeedin - $batin);
$selfconsumption = $selfconsumption < 0 ? 0 : $selfconsumption;
my $surplus = int ($pvgen - $consumption); # aktueller Überschuß
$surplus = 0 if($surplus < 0); # wegen Vergleich nompower vs. surplus
my $selfconsumptionrate = 0;
my $autarkyrate = 0;
$selfconsumptionrate = sprintf "%.0f", $selfconsumption / $pvgen * 100 if($pvgen * 1 > 0);
$autarkyrate = sprintf "%.0f", ($selfconsumption + $batout) / ($selfconsumption + $batout + $gcon) * 100 if($selfconsumption + $batout);
$data{$type}{$name}{current}{consumption} = $consumption;
$data{$type}{$name}{current}{selfconsumption} = $selfconsumption;
$data{$type}{$name}{current}{selfconsumptionrate} = $selfconsumptionrate;
$data{$type}{$name}{current}{autarkyrate} = $autarkyrate;
$data{$type}{$name}{current}{surplus} = $surplus;
$data{$type}{$name}{current}{tdConFcTillSunset} = $tdConFcTillSunset;
push @$daref, "Current_Consumption<>". $consumption. " W";
push @$daref, "Current_SelfConsumption<>". $selfconsumption. " W";
push @$daref, "Current_SelfConsumptionRate<>". $selfconsumptionrate. " %";
push @$daref, "Current_Surplus<>". $surplus. " W";
push @$daref, "Current_AutarkyRate<>". $autarkyrate. " %";
push @$daref, "NextHours_Sum01_PVforecast<>". (int $next1HoursSum->{PV})." Wh";
push @$daref, "NextHours_Sum02_PVforecast<>". (int $next2HoursSum->{PV})." Wh";
push @$daref, "NextHours_Sum03_PVforecast<>". (int $next3HoursSum->{PV})." Wh";
push @$daref, "NextHours_Sum04_PVforecast<>". (int $next4HoursSum->{PV})." Wh";
push @$daref, "RestOfDayPVforecast<>". (int $restOfDaySum->{PV}). " Wh";
push @$daref, "Tomorrow_PVforecast<>". (int $tomorrowSum->{PV}). " Wh";
push @$daref, "Today_PVforecast<>". (int $todaySumFc->{PV}). " Wh";
push @$daref, "Today_PVreal<>". (int $todaySumRe->{PV}). " Wh" if(int $todaySumRe->{PV} > ReadingsNum($name, 'Today_PVreal', 0));
push @$daref, "Tomorrow_ConsumptionForecast<>". $tconsum. " Wh" if(defined $tconsum);
push @$daref, "NextHours_Sum04_ConsumptionForecast<>". (int $next4HoursSum->{Consumption})." Wh";
push @$daref, "RestOfDayConsumptionForecast<>". (int $restOfDaySum->{Consumption}). " Wh";
return;
}
################################################################
# Kerrektur von Today_PVreal +
# berechnet die prozentuale Abweichung von Today_PVforecast