mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-07 16:59:18 +00:00
76_SolarForecast.pm: contrib 0.68.1
git-svn-id: https://svn.fhem.de/fhem/trunk@26407 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
cdfc457c82
commit
7d54549d68
@ -126,6 +126,7 @@ BEGIN {
|
||||
|
||||
# Versions History intern
|
||||
my %vNotesIntern = (
|
||||
"0.68.1 "=> "17.09.2022 new readings Today_MaxPVforecast, Today_MaxPVforecastTime ",
|
||||
"0.68.0 "=> "15.09.2022 integrate SolCast API, change attribute Wh/kWh to Wh_kWh, rename Reading nextPolltime to ".
|
||||
"nextCycletime, rework plant config check, minor (bug)fixes ",
|
||||
"0.67.6 "=> "02.09.2022 add ___setPlanningDeleteMeth, consumer can be planned across daily boundaries ".
|
||||
@ -239,7 +240,7 @@ my %vNotesIntern = (
|
||||
"0.32.0" => "09.04.2021 currentMeterDev can have: gcon=-gfeedin ",
|
||||
"0.31.1" => "07.04.2021 write new values to pvhistory, change CO to Current_Consumption in graphic ",
|
||||
"0.31.0" => "06.04.2021 extend currentMeterDev by gfeedin, feedtotal ",
|
||||
"0.30.0" => "05.04.2021 estimate readings to the minute in sub _calcSummaries, new setter energyH4Trigger ",
|
||||
"0.30.0" => "05.04.2021 estimate readings to the minute in sub _createSummaries, new setter energyH4Trigger ",
|
||||
"0.29.0" => "03.04.2021 new setter powerTrigger ",
|
||||
"0.28.0" => "03.04.2021 new attributes beam1FontColor, beam2FontColor, rename/new some readings ",
|
||||
"0.27.0" => "02.04.2021 additional readings ",
|
||||
@ -387,6 +388,10 @@ my %hqtxt = (
|
||||
DE => qq{Aus/Ein} },
|
||||
auto => { EN => qq{Auto},
|
||||
DE => qq{Auto} },
|
||||
bnsas => { EN => qq{between the next sunrise and sunset},
|
||||
DE => qq{zwischen dem nächsten Sonnenauf- und untergang} },
|
||||
after => { EN => qq{after},
|
||||
DE => qq{nach} },
|
||||
pstate => { EN => qq{Planning status: <pstate><br>On: <start><br>Off: <stop>},
|
||||
DE => qq{Planungsstatus: <pstate><br>Ein: <start><br>Aus: <stop>} },
|
||||
strok => { EN => qq{Congratulations 😊, your system configuration has been checked and is error-free !},
|
||||
@ -524,7 +529,7 @@ my %weather_ids = (
|
||||
'79' => { s => '0', icon => 'weather_frost', txtd => 'Eiskörner (gefrorene Regentropfen)', txte => 'Ice grains (frozen raindrops)' },
|
||||
|
||||
'80' => { s => '1', icon => 'weather_rain_light', txtd => 'leichter Regenschauer', txte => 'light rain shower' },
|
||||
'81' => { s => '1', icon => 'weather_rain', txtd => 'mäßiger oder starkerRegenschauer', txte => 'moderate or heavy rain shower' },
|
||||
'81' => { s => '1', icon => 'weather_rain', txtd => 'mäßiger oder starker Regenschauer', txte => 'moderate or heavy rain shower' },
|
||||
'82' => { s => '1', icon => 'weather_rain_heavy', txtd => 'sehr starker Regenschauer', txte => 'very heavy rain shower' },
|
||||
'83' => { s => '0', icon => 'weather_snow', txtd => 'mäßiger oder starker Schneeregenschauer', txte => 'moderate or heavy sleet shower' },
|
||||
'84' => { s => '0', icon => 'weather_snow_light', txtd => 'leichter Schneeschauer', txte => 'light snow shower' },
|
||||
@ -1728,12 +1733,13 @@ sub _getRoofTopData {
|
||||
my $t = $paref->{t} // time;
|
||||
|
||||
if (!$force) { # regulärer SolCast API Abruf
|
||||
my $lang = AttrVal ('global', 'language', 'EN');
|
||||
my $date = strftime "%Y-%m-%d", localtime($t);
|
||||
my $srtime = timestringToTimestamp ($date.' '.ReadingsVal($name, "Today_SunRise", '23:59').':59');
|
||||
my $sstime = timestringToTimestamp ($date.' '.ReadingsVal($name, "Today_SunSet", '00:00').':00');
|
||||
|
||||
if ($t < $srtime || $t > $sstime) {
|
||||
readingsSingleUpdate($hash, 'nextSolCastCall', 'between next SunRise and SunSet', 1);
|
||||
readingsSingleUpdate($hash, 'nextSolCastCall', $hqtxt{bnsas}{$lang}, 1);
|
||||
return qq{The current time is not between sunrise and sunset};
|
||||
}
|
||||
|
||||
@ -1741,7 +1747,7 @@ sub _getRoofTopData {
|
||||
|
||||
if ($lrt && $t < $lrt + $scapirepeat) {
|
||||
my $rt = $lrt + $scapirepeat - $t;
|
||||
readingsSingleUpdate($hash, 'nextSolCastCall', 'after '.(timestampToTimestring ($lrt + $scapirepeat))[0], 1);
|
||||
readingsSingleUpdate($hash, 'nextSolCastCall', $hqtxt{after}{$lang}.' '.(timestampToTimestring ($lrt + $scapirepeat))[0], 1);
|
||||
return qq{The waiting time to the next SolCast API call has not expired yet. The remaining waiting time is $rt seconds};
|
||||
}
|
||||
}
|
||||
@ -1753,9 +1759,15 @@ sub _getRoofTopData {
|
||||
return;
|
||||
}
|
||||
|
||||
###############################################################
|
||||
################################################################################################
|
||||
# SolCast Api Request
|
||||
###############################################################
|
||||
#
|
||||
# noch testen und einbauen Abruf aktuelle Daten ohne Rooftops
|
||||
# (aus https://www.solarquotes.com.au/blog/how-to-use-solcast/):
|
||||
# https://api.solcast.com.au/pv_power/estimated_actuals?longitude=12.067722&latitude=51.285272&
|
||||
# capacity=5130&azimuth=180&tilt=30&format=json&api_key=....
|
||||
#
|
||||
################################################################################################
|
||||
sub __solCast_ApiRequest {
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
@ -1764,7 +1776,6 @@ sub __solCast_ApiRequest {
|
||||
|
||||
my $string;
|
||||
($string, $allstrings) = split ",", $allstrings, 2;
|
||||
#return if(!$string);
|
||||
|
||||
my $rft = ReadingsVal ($name, "moduleRoofTops", "");
|
||||
my ($a,$h) = parseParams ($rft);
|
||||
@ -2626,7 +2637,8 @@ sub centralTask {
|
||||
else {
|
||||
_transferDWDRadiationValues ($centpars); # DWD Strahlungswerte übertragen
|
||||
}
|
||||
|
||||
|
||||
_calcMaxEstimateToday ($centpars); # heutigen Max PV Estimate & dessen Tageszeit ermitteln
|
||||
_transferInverterValues ($centpars); # WR Werte übertragen
|
||||
_transferMeterValues ($centpars); # Energy Meter auswerten
|
||||
_transferBatteryValues ($centpars); # Batteriewerte einsammeln
|
||||
@ -2634,7 +2646,7 @@ sub centralTask {
|
||||
_estConsumptionForecast ($centpars); # erwarteten Verbrauch berechnen
|
||||
_evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren
|
||||
_calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen
|
||||
_calcSummaries ($centpars); # Zusammenfassungen erstellen
|
||||
_createSummaries ($centpars); # Zusammenfassungen erstellen
|
||||
|
||||
if(@da) {
|
||||
createReadingsFromArray ($hash, \@da, 1);
|
||||
@ -3472,6 +3484,116 @@ sub ___70percentRule {
|
||||
return ($pvsum, $logao);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# den Maximalwert PV Vorhersage für Heute ermitteln
|
||||
# und mit seinem Zeitparamter im current Hash speichern
|
||||
################################################################
|
||||
sub _calcMaxEstimateToday {
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
|
||||
my $type = $hash->{TYPE};
|
||||
|
||||
return if (!keys %{$data{$type}{$name}{nexthours}});
|
||||
|
||||
my $maxest = 0;
|
||||
|
||||
for my $idx (sort keys %{$data{$type}{$name}{nexthours}}) {
|
||||
my $today = NexthoursVal ($hash, $idx, 'today', 0);
|
||||
next if(!$today);
|
||||
|
||||
my $pvfc = NexthoursVal ($hash, $idx, 'pvforecast', 0);
|
||||
next if($pvfc <= $maxest);
|
||||
|
||||
my $stt = NexthoursVal ($hash, $idx, 'starttime', '');
|
||||
next if(!$stt);
|
||||
|
||||
$maxest = $pvfc;
|
||||
$data{$type}{$name}{current}{todayMaxEstValue} = $maxest;
|
||||
$data{$type}{$name}{current}{todayMaxEstTimestamp} = timestringToTimestamp ($stt);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Werte Inverter Device ermitteln und übertragen
|
||||
################################################################
|
||||
sub _transferInverterValues {
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
my $t = $paref->{t}; # aktuelle Unix-Zeit
|
||||
my $chour = $paref->{chour};
|
||||
my $day = $paref->{day};
|
||||
my $daref = $paref->{daref};
|
||||
|
||||
my $indev = ReadingsVal($name, "currentInverterDev", "");
|
||||
my ($a,$h) = parseParams ($indev);
|
||||
$indev = $a->[0] // "";
|
||||
return if(!$indev || !$defs{$indev});
|
||||
|
||||
my $type = $hash->{TYPE};
|
||||
|
||||
my ($pvread,$pvunit) = split ":", $h->{pv}; # Readingname/Unit für aktuelle PV Erzeugung
|
||||
my ($edread,$etunit) = split ":", $h->{etotal}; # Readingname/Unit für Energie total (PV Erzeugung)
|
||||
|
||||
$data{$type}{$name}{current}{invertercapacity} = $h->{capacity} if($h->{capacity}); # optionale Angabe max. WR-Leistung
|
||||
|
||||
return if(!$pvread || !$edread);
|
||||
|
||||
Log3 ($name, 5, "$name - collect Inverter data: device=$indev, pv=$pvread ($pvunit), etotal=$edread ($etunit)");
|
||||
|
||||
my $pvuf = $pvunit =~ /^kW$/xi ? 1000 : 1;
|
||||
my $pv = ReadingsNum ($indev, $pvread, 0) * $pvuf; # aktuelle Erzeugung (W)
|
||||
$pv = $pv < 0 ? 0 : sprintf("%.0f", $pv); # Forum: https://forum.fhem.de/index.php/topic,117864.msg1159718.html#msg1159718, https://forum.fhem.de/index.php/topic,117864.msg1166201.html#msg1166201
|
||||
|
||||
push @$daref, "Current_PV<>". $pv." W";
|
||||
$data{$type}{$name}{current}{generation} = $pv; # Hilfshash Wert current generation Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251
|
||||
|
||||
push @{$data{$type}{$name}{current}{genslidereg}}, $pv; # Schieberegister PV Erzeugung
|
||||
limitArray ($data{$type}{$name}{current}{genslidereg}, $defslidenum);
|
||||
|
||||
my $etuf = $etunit =~ /^kWh$/xi ? 1000 : 1;
|
||||
my $etotal = ReadingsNum ($indev, $edread, 0) * $etuf; # Erzeugung total (Wh)
|
||||
|
||||
my $nhour = $chour+1;
|
||||
|
||||
my $histetot = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "etotal", 0); # etotal zu Beginn einer Stunde
|
||||
|
||||
my $ethishour;
|
||||
if(!$histetot) { # etotal der aktuelle Stunde gesetzt ?
|
||||
$paref->{etotal} = $etotal;
|
||||
$paref->{nhour} = sprintf("%02d",$nhour);
|
||||
$paref->{histname} = "etotal";
|
||||
setPVhistory ($paref);
|
||||
delete $paref->{histname};
|
||||
|
||||
my $etot = CurrentVal ($hash, "etotal", $etotal);
|
||||
$ethishour = int ($etotal - $etot);
|
||||
}
|
||||
else {
|
||||
$ethishour = int ($etotal - $histetot);
|
||||
}
|
||||
|
||||
$data{$type}{$name}{current}{etotal} = $etotal; # aktuellen etotal des WR speichern
|
||||
|
||||
if($ethishour < 0) {
|
||||
$ethishour = 0;
|
||||
}
|
||||
|
||||
push @$daref, "Today_Hour".sprintf("%02d",$nhour)."_PVreal<>".$ethishour." Wh";
|
||||
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{pvrl} = $ethishour; # Ringspeicher PV real Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
|
||||
|
||||
$paref->{ethishour} = $ethishour;
|
||||
$paref->{nhour} = sprintf("%02d",$nhour);
|
||||
$paref->{histname} = "pvrl";
|
||||
setPVhistory ($paref);
|
||||
delete $paref->{histname};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Wetter Werte aus dem angebenen Wetterdevice extrahieren
|
||||
@ -3575,84 +3697,6 @@ sub _transferWeatherValues {
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Werte Inverter Device ermitteln und übertragen
|
||||
################################################################
|
||||
sub _transferInverterValues {
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
my $t = $paref->{t}; # aktuelle Unix-Zeit
|
||||
my $chour = $paref->{chour};
|
||||
my $day = $paref->{day};
|
||||
my $daref = $paref->{daref};
|
||||
|
||||
my $indev = ReadingsVal($name, "currentInverterDev", "");
|
||||
my ($a,$h) = parseParams ($indev);
|
||||
$indev = $a->[0] // "";
|
||||
return if(!$indev || !$defs{$indev});
|
||||
|
||||
my $type = $hash->{TYPE};
|
||||
|
||||
my ($pvread,$pvunit) = split ":", $h->{pv}; # Readingname/Unit für aktuelle PV Erzeugung
|
||||
my ($edread,$etunit) = split ":", $h->{etotal}; # Readingname/Unit für Energie total (PV Erzeugung)
|
||||
|
||||
$data{$type}{$name}{current}{invertercapacity} = $h->{capacity} if($h->{capacity}); # optionale Angabe max. WR-Leistung
|
||||
|
||||
return if(!$pvread || !$edread);
|
||||
|
||||
Log3 ($name, 5, "$name - collect Inverter data: device=$indev, pv=$pvread ($pvunit), etotal=$edread ($etunit)");
|
||||
|
||||
my $pvuf = $pvunit =~ /^kW$/xi ? 1000 : 1;
|
||||
my $pv = ReadingsNum ($indev, $pvread, 0) * $pvuf; # aktuelle Erzeugung (W)
|
||||
$pv = $pv < 0 ? 0 : sprintf("%.0f", $pv); # Forum: https://forum.fhem.de/index.php/topic,117864.msg1159718.html#msg1159718, https://forum.fhem.de/index.php/topic,117864.msg1166201.html#msg1166201
|
||||
|
||||
push @$daref, "Current_PV<>". $pv." W";
|
||||
$data{$type}{$name}{current}{generation} = $pv; # Hilfshash Wert current generation Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251
|
||||
|
||||
push @{$data{$type}{$name}{current}{genslidereg}}, $pv; # Schieberegister PV Erzeugung
|
||||
limitArray ($data{$type}{$name}{current}{genslidereg}, $defslidenum);
|
||||
|
||||
my $etuf = $etunit =~ /^kWh$/xi ? 1000 : 1;
|
||||
my $etotal = ReadingsNum ($indev, $edread, 0) * $etuf; # Erzeugung total (Wh)
|
||||
|
||||
my $nhour = $chour+1;
|
||||
|
||||
my $histetot = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "etotal", 0); # etotal zu Beginn einer Stunde
|
||||
|
||||
my $ethishour;
|
||||
if(!$histetot) { # etotal der aktuelle Stunde gesetzt ?
|
||||
$paref->{etotal} = $etotal;
|
||||
$paref->{nhour} = sprintf("%02d",$nhour);
|
||||
$paref->{histname} = "etotal";
|
||||
setPVhistory ($paref);
|
||||
delete $paref->{histname};
|
||||
|
||||
my $etot = CurrentVal ($hash, "etotal", $etotal);
|
||||
$ethishour = int ($etotal - $etot);
|
||||
}
|
||||
else {
|
||||
$ethishour = int ($etotal - $histetot);
|
||||
}
|
||||
|
||||
$data{$type}{$name}{current}{etotal} = $etotal; # aktuellen etotal des WR speichern
|
||||
|
||||
if($ethishour < 0) {
|
||||
$ethishour = 0;
|
||||
}
|
||||
|
||||
push @$daref, "Today_Hour".sprintf("%02d",$nhour)."_PVreal<>".$ethishour." Wh";
|
||||
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{pvrl} = $ethishour; # Ringspeicher PV real Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
|
||||
|
||||
$paref->{ethishour} = $ethishour;
|
||||
$paref->{nhour} = sprintf("%02d",$nhour);
|
||||
$paref->{histname} = "pvrl";
|
||||
setPVhistory ($paref);
|
||||
delete $paref->{histname};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Werte Meter Device ermitteln und übertragen
|
||||
################################################################
|
||||
@ -5267,7 +5311,7 @@ return;
|
||||
################################################################
|
||||
# Zusammenfassungen erstellen
|
||||
################################################################
|
||||
sub _calcSummaries {
|
||||
sub _createSummaries {
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
@ -5349,12 +5393,18 @@ sub _calcSummaries {
|
||||
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 $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 $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 $tdmev = CurrentVal ($hash, "todayMaxEstValue", '-'); # heute PV Estimate Wert
|
||||
my $tdmets = CurrentVal ($hash, "todayMaxEstTimestamp", '-'); # heute PV Estimate Zeitstempel
|
||||
|
||||
if ($tdmets && $tdmets ne '-') {
|
||||
$tdmets = (timestampToTimestring ($tdmets))[0];
|
||||
}
|
||||
|
||||
my $consumption = int ($pvgen - $gfeedin + $gcon - $batin + $batout);
|
||||
my $selfconsumption = int ($pvgen - $gfeedin - $batin + $batout);
|
||||
@ -5386,6 +5436,8 @@ sub _calcSummaries {
|
||||
push @$daref, "RestOfDayPVforecast<>". (int $restOfDaySum->{PV}). " Wh";
|
||||
push @$daref, "Tomorrow_PVforecast<>". (int $tomorrowSum->{PV}). " Wh";
|
||||
push @$daref, "Today_PVforecast<>". (int $todaySum->{PV}). " Wh";
|
||||
push @$daref, "Today_MaxPVforecast<>". $tdmev. " Wh";
|
||||
push @$daref, "Today_MaxPVforecastTime<>". $tdmets;
|
||||
|
||||
push @$daref, "Tomorrow_ConsumptionForecast<>". $tconsum. " Wh" if(defined $tconsum);
|
||||
push @$daref, "NextHours_Sum04_ConsumptionForecast<>". (int $next4HoursSum->{Consumption})." Wh";
|
||||
@ -6015,7 +6067,8 @@ sub _graphicHeader {
|
||||
}
|
||||
elsif ($pcfa eq "off") {
|
||||
$htitles{akorron}{$lang} =~ s/<NAME>/$name/xs;
|
||||
$acicon = "<a title='$htitles{akorron}{$lang}'</a>off";
|
||||
#$acicon = "<a title='$htitles{akorron}{$lang}'</a>-";
|
||||
$acicon = FW_makeImage('-', $htitles{akorron}{$lang});
|
||||
}
|
||||
elsif ($pcfa =~ /standby/ix) {
|
||||
my ($rtime) = $pcfa =~ /for (.*?) hours/x;
|
||||
|
Loading…
x
Reference in New Issue
Block a user