From 92f6833bb02675969c369f0de603112c4154c661 Mon Sep 17 00:00:00 2001 From: nasseeder1 Date: Sun, 18 Apr 2021 16:37:33 +0000 Subject: [PATCH] 76_SolarForecast.pm: contrib 0.38.0 git-svn-id: https://svn.fhem.de/fhem/trunk@24273 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/DS_Starter/76_SolarForecast.pm | 136 ++++++++++++++------ 1 file changed, 100 insertions(+), 36 deletions(-) diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm index ea2a99ca0..4c054a7dd 100644 --- a/fhem/contrib/DS_Starter/76_SolarForecast.pm +++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm @@ -119,6 +119,7 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "0.38.0" => "18.04.2021 consumption forecast for the next hours prepared ", "0.37.0" => "17.04.2021 estConsumptionForecast, new getter forecastQualities, new setter currentRadiationDev ". "language sensitive setup hints ", "0.36.1" => "14.04.2021 add dayname to pvHistory ", @@ -381,10 +382,10 @@ my @dweattrmust = qw(TTT Neff R101 ww SunUp SunRise SunSet); my @draattrmust = qw(Rad1h); # Werte die im Attr forecastProperties des Radiation-DWD_Opendata Devices mindestens gesetzt sein müssen my $whistrepeat = 900; # Wiederholungsintervall Schreiben historische Daten -my $cldampdef = 45; # Dämpfung (%) des Korrekturfaktors bzgl. effektiver Bewölkung, siehe: https://www.energie-experten.org/erneuerbare-energien/photovoltaik/planung/sonnenstunden +my $cldampdef = 35; # Dämpfung (%) des Korrekturfaktors bzgl. effektiver Bewölkung, siehe: https://www.energie-experten.org/erneuerbare-energien/photovoltaik/planung/sonnenstunden my $cloud_base = 0; # Fußpunktverschiebung bzgl. effektiver Bewölkung -my $rdampdef = 20; # Dämpfung (%) des Korrekturfaktors bzgl. Niederschlag (R101) +my $rdampdef = 10; # Dämpfung (%) des Korrekturfaktors bzgl. Niederschlag (R101) my $rain_base = 0; # Fußpunktverschiebung bzgl. effektiver Bewölkung # Information zu verwendeten internen Datenhashes @@ -1778,6 +1779,7 @@ sub _transferWeatherValues { my $wid = ReadingsNum($fcname, "fc${fd}_${fh2}_ww", -1); my $neff = ReadingsNum($fcname, "fc${fd}_${fh2}_Neff", 0); # Effektive Wolkendecke my $r101 = ReadingsNum($fcname, "fc${fd}_${fh2}_R101", 0); # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde + my $temp = ReadingsNum($fcname, "fc${fd}_${fh2}_TTT", 0); # Außentemperatur my $fhstr = sprintf "%02d", $fh; # hier kann Tag/Nacht-Grenze verstellt werden @@ -1790,21 +1792,27 @@ sub _transferWeatherValues { my $txt = ReadingsVal($fcname, "fc${fd}_${fh2}_wwd", ''); - Log3($name, 5, "$name - collect Weather data: device=$fcname, wid=fc${fd}_${fh1}_ww, val=$wid, txt=$txt, cc=$neff, rp=$r101"); + Log3($name, 5, "$name - collect Weather data: device=$fcname, wid=fc${fd}_${fh1}_ww, val=$wid, txt=$txt, cc=$neff, rp=$r101, t=$temp"); $time_str = "NextHour".sprintf "%02d", $num; $data{$type}{$name}{nexthours}{$time_str}{weatherid} = $wid; $data{$type}{$name}{nexthours}{$time_str}{cloudcover} = $neff; $data{$type}{$name}{nexthours}{$time_str}{rainprob} = $r101; + $data{$type}{$name}{nexthours}{$time_str}{temp} = $temp; if($num < 23 && $fh < 24) { # Ringspeicher Weather Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251 $data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{weatherid} = $wid; $data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{weathertxt} = $txt; $data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{wcc} = $neff; $data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{wrp} = $r101; + $data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{temp} = $temp; + + if($num == 0) { # aktuelle Außentemperatur + $data{$type}{$name}{current}{temp} = $temp; + } } - if($fd == 0 && $fh1) { # WeatherId in pvhistory speichern + if($fd == 0 && $fh1) { # Weather in pvhistory speichern $paref->{wid} = $wid; $paref->{histname} = "weatherid"; $paref->{nhour} = sprintf("%02d",$fh1); @@ -1818,6 +1826,10 @@ sub _transferWeatherValues { $paref->{histname} = "weatherrainprob"; setPVhistory ($paref); + $paref->{temp} = $temp; + $paref->{histname} = "temperature"; + setPVhistory ($paref); + delete $paref->{histname}; } } @@ -2266,12 +2278,12 @@ sub _calcSummaries { $next4HoursSum->{PV} += $pvfc / 60 * $minute if($h == 4); } - $restOfDaySum->{PV} += $pvfc if($h <= $rdh); - $tomorrowSum->{PV} += $pvfc if($h > $rdh); + $restOfDaySum->{PV} += $pvfc if($h <= $rdh); + $tomorrowSum->{PV} += $pvfc if($h > $rdh); } for my $th (1..24) { - $todaySum->{PV} += ReadingsNum($name, "Today_Hour".sprintf("%02d",$th)."_PVforecast", 0); + $todaySum->{PV} += ReadingsNum($name, "Today_Hour".sprintf("%02d",$th)."_PVforecast", 0); } push @{$data{$type}{$name}{current}{h4fcslidereg}}, int $next4HoursSum->{PV}; # Schieberegister 4h Summe Forecast @@ -2360,18 +2372,19 @@ sub estConsumptionForecast { return if(!$medev || !$defs{$medev}); my $type = $hash->{TYPE}; + my $hhist = $data{$type}{$name}{pvhist}; ## Verbrauchsvorhersage für den nächsten Tag ############################################## - my $tomorrow = strftime "%a", localtime($t+86400); # Wochentagsname morgen + my $tomorrow = strftime "%a", localtime($t+86400); # Wochentagsname kommender Tag my $totcon = 0; my $dnum = 0; - for my $n (1..31) { - my $hdn = HistoryVal ($hash, sprintf("%02d",$n), 99, "dayname", undef); + for my $n (sort{$a<=>$b} keys %{$data{$type}{$name}{pvhist}}) { + my $hdn = HistoryVal ($hash, $n, 99, "dayname", undef); next if(!$hdn || $hdn ne $tomorrow); - $totcon += HistoryVal ($hash, sprintf("%02d",$n), 99, "con", 0); + $totcon += HistoryVal ($hash, $n, 99, "con", 0); $dnum++; } @@ -2382,6 +2395,38 @@ sub estConsumptionForecast { $data{$type}{$name}{current}{tomorrowconsumption} = "Wait for more days with a consumption figure"; } + ## Verbrauchsvorhersage für die nächsten Stunden + ################################################## + my $conh = { "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, + }; + + for my $k (sort keys %{$data{$type}{$name}{nexthours}}) { + my $nhts = NexthoursVal ($hash, $k, "starttime", undef); + next if(!$nhts); + + $dnum = 0; + my $utime = timestringToTimestamp ($nhts); + 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) + + for my $m (sort{$a<=>$b} keys %{$data{$type}{$name}{pvhist}}) { + my $hdn = HistoryVal ($hash, $m, 99, "dayname", undef); + next if(!$hdn || $hdn ne $nhday); + + $conh->{$nhhr} += HistoryVal ($hash, $m, $nhhr, "con", 0); + $dnum++; + Log3($name, 1, "$name - hdn: $hdn, $dnum, nhhr: $nhhr, ".$conh->{$nhhr}); + } + if ($dnum) { + $data{$type}{$name}{nexthours}{$k}{confc} = $conh->{$nhhr}/$dnum; # Durchschnittsverbrauch aller gleicher Wochentage pro Stunde + } + } + return; } @@ -3504,13 +3549,14 @@ sub calcPVforecast { my $raindamp = AttrVal($name, "rainFactorDamping", $rdampdef); # prozentuale Berücksichtigung des Regenkorrekturfaktors my @strings = sort keys %{$stch}; - my $cloudcover = NexthoursVal ($hash, "NextHour".sprintf("%02d",$num), "cloudcover", 0); # effektive Wolkendecke nächste Stunde X - my $ccf = 1 - ((($cloudcover - $cloud_base)/100) * $clouddamp/100); # Cloud Correction Faktor mit Steilheit und Fußpunkt - my $range = int ($cloudcover/10); # Range errechnen - my $rainprob = NexthoursVal ($hash, "NextHour".sprintf("%02d",$num), "rainprob", 0); # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde my $rcf = 1 - ((($rainprob - $rain_base)/100) * $raindamp/100); # Rain Correction Faktor mit Steilheit + my $cloudcover = NexthoursVal ($hash, "NextHour".sprintf("%02d",$num), "cloudcover", 0); # effektive Wolkendecke nächste Stunde X + my $ccf = 1 - ((($cloudcover - $cloud_base)/100) * $clouddamp/100); # Cloud Correction Faktor mit Steilheit und Fußpunkt + + my $range = int ($cloudcover/10); # Range errechnen + ## Ermitteln des relevanten Autokorrekturfaktors if ($uac eq "on") { # Autokorrektur soll genutzt werden $hcfound = "yes"; # Status ob Autokorrekturfaktor im Wertevorrat gefunden wurde @@ -3596,7 +3642,7 @@ sub calcVariance { my $idts = ReadingsTimestamp($name, "currentInverterDev", ""); # Definitionstimestamp des Inverterdevice return if(!$idts); - $idts = timestringToTimestamp ($hash, $idts); + $idts = timestringToTimestamp ($idts); if($t - $idts < 86400) { my $rmh = sprintf "%.1f", ((86400 - ($t - $idts)) / 3600); @@ -3621,7 +3667,7 @@ sub calcVariance { my $cdone = ReadingsVal ($name, "pvCorrectionFactor_".sprintf("%02d",$h)."_autocalc", ""); if($cdone eq "done") { - Log3($name, 5, "$name - pvCorrectionFactor Hour: ".sprintf("%02d",$h). " already calculated"); + Log3($name, 5, "$name - pvCorrectionFactor Hour: ".sprintf("%02d",$h)." already calculated"); next; } @@ -3786,6 +3832,7 @@ sub setPVhistory { my $wcc = $paref->{wcc} // 0; # Wolkenbedeckung my $wrp = $paref->{wrp} // 0; # Wahrscheinlichkeit von Niederschlag my $pvcorrf = $paref->{pvcorrf} // 1; # pvCorrectionFactor + my $temp = $paref->{temp}; # Außentemperatur my $type = $hash->{TYPE}; my $val = q{}; @@ -3854,26 +3901,32 @@ sub setPVhistory { if($histname eq "weatherid") { # Wetter ID $val = $wid; - $data{$type}{$name}{pvhist}{$day}{$nhour}{weatherid} = $wid; - $data{$type}{$name}{pvhist}{$day}{99}{weatherid} = q{}; + $data{$type}{$name}{pvhist}{$day}{$nhour}{weatherid} = $wid; + $data{$type}{$name}{pvhist}{$day}{99}{weatherid} = q{}; } if($histname eq "weathercloudcover") { # Wolkenbedeckung $val = $wcc; - $data{$type}{$name}{pvhist}{$day}{$nhour}{wcc} = $wcc; + $data{$type}{$name}{pvhist}{$day}{$nhour}{wcc} = $wcc; $data{$type}{$name}{pvhist}{$day}{99}{wcc} = q{}; } if($histname eq "weatherrainprob") { # Niederschlagswahrscheinlichkeit $val = $wrp; - $data{$type}{$name}{pvhist}{$day}{$nhour}{wrp} = $wrp; + $data{$type}{$name}{pvhist}{$day}{$nhour}{wrp} = $wrp; $data{$type}{$name}{pvhist}{$day}{99}{wrp} = q{}; } if($histname eq "pvcorrfactor") { # pvCorrectionFactor $val = $pvcorrf; - $data{$type}{$name}{pvhist}{$day}{$nhour}{pvcorrf} = $pvcorrf; - $data{$type}{$name}{pvhist}{$day}{99}{pvcorrf} = q{}; + $data{$type}{$name}{pvhist}{$day}{$nhour}{pvcorrf} = $pvcorrf; + $data{$type}{$name}{pvhist}{$day}{99}{pvcorrf} = q{}; + } + + if($histname eq "temperature") { # Außentemperatur + $val = $temp; + $data{$type}{$name}{pvhist}{$day}{$nhour}{temp} = $temp; + $data{$type}{$name}{pvhist}{$day}{99}{temp} = q{}; } Log3 ($name, 5, "$name - set PV History hour: $nhour, hash: $histname, val: $val"); @@ -3906,6 +3959,7 @@ sub listDataPool { my $wid = HistoryVal ($hash, $day, $key, "weatherid", "-"); my $wcc = HistoryVal ($hash, $day, $key, "wcc", "-"); my $wrp = HistoryVal ($hash, $day, $key, "wrp", "-"); + my $temp = HistoryVal ($hash, $day, $key, "temp", undef); my $pvcorrf = HistoryVal ($hash, $day, $key, "pvcorrf", "-"); my $dayname = HistoryVal ($hash, $day, $key, "dayname", undef); $ret .= "\n " if($ret); @@ -3913,6 +3967,7 @@ sub listDataPool { $ret .= ", wid: $wid" if($wid); $ret .= ", wcc: $wcc" if($wcc); $ret .= ", wrp: $wrp" if($wrp); + $ret .= ", temp: $temp" if($temp); $ret .= ", pvcorrf: $pvcorrf" if($pvcorrf); $ret .= ", dayname: $dayname" if($dayname); } @@ -3943,6 +3998,7 @@ sub listDataPool { my $wtxt = CircularVal ($hash, $idx, "weathertxt", "-"); my $wccv = CircularVal ($hash, $idx, "wcc", "-"); my $wrprb = CircularVal ($hash, $idx, "wrp", "-"); + my $temp = CircularVal ($hash, $idx, "temp", "-"); my $pvcorrf = CircularVal ($hash, $idx, "pvcorrf", "-"); my $quality = CircularVal ($hash, $idx, "quality", "-"); @@ -3969,7 +4025,7 @@ sub listDataPool { } $sq .= "\n" if($sq); - $sq .= $idx." => pvfc: $pvfc, pvrl: $pvrl, gcon: $gcons, gfeedin: $gfeedin, wcc: $wccv, wrp: $wrprb, wid: $wid, wtxt: $wtxt\n"; + $sq .= $idx." => pvfc: $pvfc, pvrl: $pvrl, gcon: $gcons, gfeedin: $gfeedin, wcc: $wccv, wrp: $wrprb, temp=$temp, wid: $wid, wtxt: $wtxt\n"; $sq .= " corr: $pvcf\n"; $sq .= " quality:$cfq"; } @@ -3988,8 +4044,10 @@ sub listDataPool { my $r101 = NexthoursVal ($hash, $idx, "rainprob", "-"); my $rad1h = NexthoursVal ($hash, $idx, "Rad1h", "-"); my $pvcorrf = NexthoursVal ($hash, $idx, "pvcorrf", "-"); + my $temp = NexthoursVal ($hash, $idx, "temp", "-"); + my $confc = NexthoursVal ($hash, $idx, "confc", "-"); $sq .= "\n" if($sq); - $sq .= $idx." => starttime: $nhts, pvfc: $nhfc, wid: $wid, wcc: $neff, correff: $pvcorrf, wrp: $r101, Rad1h: $rad1h"; + $sq .= $idx." => starttime: $nhts, pvfc: $nhfc, confc: $confc, wid: $wid, wcc: $neff, wrp: $r101, correff: $pvcorrf, Rad1h: $rad1h, temp=$temp"; } } @@ -3999,6 +4057,8 @@ sub listDataPool { return qq{NextHours cache is empty.}; } for my $idx (sort keys %{$h}) { + my $nhfc = NexthoursVal ($hash, $idx, "pvforecast", undef); + next if(!$nhfc); my $nhts = NexthoursVal ($hash, $idx, "starttime", undef); my $pvcorrf = NexthoursVal ($hash, $idx, "pvcorrf", undef); $pvcorrf //= "-/-"; @@ -4011,7 +4071,7 @@ sub listDataPool { if ($htol eq "current") { $h = $data{$type}{$name}{current}; if (!keys %{$h}) { - return qq{current values cache is empty.}; + return qq{Current values cache is empty.}; } for my $idx (sort keys %{$h}) { if (ref $h->{$idx} ne "ARRAY") { @@ -4097,9 +4157,7 @@ return; # Timestamp umwandeln ################################################################ sub timestringToTimestamp { - my $hash = shift; my $tstring = shift; - my $name = $hash->{NAME}; my($y, $mo, $d, $h, $m, $s) = $tstring =~ /([0-9]{4})-([0-9]{2})-([0-9]{2})\s([0-9]{2}):([0-9]{2}):([0-9]{2})/xs; return if(!$mo || !$y); @@ -4212,6 +4270,7 @@ return; # gfeedin - reale Netzeinspeisung # weatherid - Wetter ID # wcc - Grad der Bewölkung +# temp - Außentemperatur # wrp - Niederschlagswahrscheinlichkeit # pvcorrf - PV Autokorrekturfaktor f. Stunde des Tages # dayname - Tagesname (Kürzel) @@ -4255,6 +4314,7 @@ return $def; # weathertxt - DWD Wetter Text # wcc - DWD Wolkendichte # wrp - DWD Regenwahrscheinlichkeit +# temp - Außentemperatur # pvcorrf - PV Autokorrekturfaktoren (HASH) # $def: Defaultwert # @@ -4359,12 +4419,14 @@ return $def; # Usage: # CurrentVal ($hash, $key, $def) # -# $key: generation - aktuelle PV Erzeugung -# genslidereg - Schieberegister PV Erzeugung (Array) -# h4fcslidereg - Schieberegister 4h PV Forecast (Array) -# gridconsumption - aktueller Netzbezug -# powerbatin - Batterie Ladeleistung -# powerbatout - Batterie Entladeleistung +# $key: generation - aktuelle PV Erzeugung +# genslidereg - Schieberegister PV Erzeugung (Array) +# h4fcslidereg - Schieberegister 4h PV Forecast (Array) +# gridconsumption - aktueller Netzbezug +# powerbatin - Batterie Ladeleistung +# powerbatout - Batterie Entladeleistung +# temp - aktuelle Außentemperatur +# tomorrowconsumption - Verbrauch des kommenden Tages # $def: Defaultwert # ################################################################ @@ -4829,6 +4891,7 @@ verfügbare Globalstrahlung ganz spezifisch in elektrische Energie umgewandelt. /1...X - Korrekturfaktor aus Store genutzt (höhere Zahl = bessere Qualität) wrp vorhergesagter Grad der Regenwahrscheinlichkeit Rad1h vorhergesagte Globalstrahlung + temp vorhergesagte Außentemperatur @@ -4876,6 +4939,7 @@ verfügbare Globalstrahlung ganz spezifisch in elektrische Energie umgewandelt. gfeedin reale Leistungseinspeisung in das Stromnetz wcc Grad der Wolkenüberdeckung wrp Grad der Regenwahrscheinlichkeit + temp Außentemperatur wid ID des vorhergesagten Wetters wtxt Beschreibung des vorhergesagten Wetters corr Autokorrekturfaktoren für die Stunde des Tages und der Bewölkungsrange (0..10) @@ -4994,7 +5058,7 @@ verfügbare Globalstrahlung ganz spezifisch in elektrische Energie umgewandelt.
  • cloudFactorDamping
    Prozentuale Berücksichtigung (Dämpfung) des Bewölkungprognosefaktors bei der solaren Vorhersage.
    Größere Werte vermindern, kleinere Werte erhöhen tendenziell den prognostizierten PV Ertrag.
    - (default: 45) + (default: 35)

  • @@ -5126,7 +5190,7 @@ verfügbare Globalstrahlung ganz spezifisch in elektrische Energie umgewandelt.
  • rainFactorDamping
    Prozentuale Berücksichtigung (Dämpfung) des Regenprognosefaktors bei der solaren Vorhersage.
    Größere Werte vermindern, kleinere Werte erhöhen tendenziell den prognostizierten PV Ertrag.
    - (default: 20) + (default: 10)