diff --git a/fhem/CHANGED b/fhem/CHANGED index 15620f5b0..37de900f5 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -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: check age of Rad1h data, use RR1c instead of R101 - feature: 70_PylonLowVoltage: print out faulty response with verbose 5 - bugfix: 88_HMCCU: fixed device detection bug - feature: 93_DbRep: sqlCmd executing ckey:latest possible diff --git a/fhem/FHEM/76_SolarForecast.pm b/fhem/FHEM/76_SolarForecast.pm index c216f8bd5..9f659cd7d 100644 --- a/fhem/FHEM/76_SolarForecast.pm +++ b/fhem/FHEM/76_SolarForecast.pm @@ -158,6 +158,10 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "1.16.2" => "22.02.2024 minor changes, R101 -> RR1c, totalrain instead of weatherrainprob, delete wrp r101 ". + "delete wrp from circular & airaw, remove rain2bin, __getDWDSolarData: change \$runh, ". + "fix Illegal division by zero Forum: https://forum.fhem.de/index.php?msg=1304009 ". + "DWD API: check age of Rad1h data, store pvcorrf of sunalt with value 200+x in pvCircular ", "1.16.1" => "14.02.2024 ___isCatFiltered: add eval for regex evaluation, add sunaz to AI raw and get, fillup AI hash ", "1.16.0" => "12.02.2024 new command get dwdCatalog ", "1.15.5" => "11.02.2024 change forecastQualities output, new limits for 'accurate' and 'spreaded' results from AI ". @@ -341,7 +345,7 @@ my $aiAccUpLim = 170; my $aiAccLowLim = 30; # untere Abweichungsgrenze (%) AI 'Accurate' von API Prognose my $calcmaxd = 30; # Anzahl Tage die zur Berechnung Vorhersagekorrektur verwendet werden -my @dweattrmust = qw(TTT Neff R101 ww SunUp SunRise SunSet); # Werte die im Attr forecastProperties des Weather-DWD_Opendata Devices mindestens gesetzt sein müssen +my @dweattrmust = qw(TTT Neff RR1c ww SunUp SunRise SunSet); # Werte die im Attr forecastProperties des Weather-DWD_Opendata Devices mindestens gesetzt sein müssen my @draattrmust = qw(Rad1h); # Werte die im Attr forecastProperties des Radiation-DWD_Opendata Devices mindestens gesetzt sein müssen my $whistrepeat = 900; # Wiederholungsintervall Cache File Daten schreiben @@ -690,6 +694,8 @@ my %htitles = ( DE => qq{Ein -> kein off-Kommando definiert!} }, natc => { EN => qq{automatic cycle:}, DE => qq{automatischer Zyklus:} }, + predtime => { EN => qq{Prediction time Weather data:}, + DE => qq{Vorhersagezeitpunkt Wetterdaten:} }, upd => { EN => qq{Click for update}, DE => qq{Klick für Update} }, on => { EN => qq{switched on}, @@ -742,6 +748,8 @@ my %htitles = ( DE => qq{Planungsstatus: \nInfo: \n\nEin: \nAus: \nverbleibende Sperrzeit:  Sekunden} }, ainuse => { EN => qq{AI Perl module is installed, but the AI support is not used.\nRun 'set plantConfiguration check' for hints.}, DE => qq{KI Perl Modul ist installiert, aber die KI Unterstützung wird nicht verwendet.\nPrüfen sie 'set plantConfiguration check' für Hinweise.} }, + arsrad2o => { EN => qq{API query successful but the radiation values are outdated.\nCheck the plant with 'set plantConfiguration check'.}, + DE => qq{API Abfrage erfolgreich aber die Strahlungswerte sind veraltet.\nPrüfen sie die Anlage mit 'set plantConfiguration check'.} }, ); my %weather_ids = ( @@ -959,7 +967,6 @@ sub Initialize { "affectConsForecastIdentWeekdays:1,0 ". "affectConsForecastInPlanning:1,0 ". "affectMaxDayVariance ". - "affectNumHistDays:obsolete ". "affectSolCastPercentile:select,10,50,90 ". "consumerLegend:none,icon_top,icon_bottom,text_top,text_bottom ". "consumerAdviceIcon ". @@ -2528,7 +2535,11 @@ return $getlist; sub _getRoofTopData { my $paref = shift; my $hash = $paref->{hash}; - my $name = $hash->{NAME}; + my $name = $paref->{name}; + my $type = $paref->{type}; + + delete $data{$type}{$name}{current}{dwdRad1hAge}; + delete $data{$type}{$name}{current}{dwdRad1hAgeTS}; if($hash->{MODEL} eq 'SolCastAPI') { __getSolCastData ($paref); @@ -3368,21 +3379,24 @@ sub __getDWDSolarData { $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{lastretrieval_time} = (timestampToTimestring ($t, $lang))[3]; # letzte Abrufzeit $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{lastretrieval_timestamp} = $t; $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIrequests} += 1; + + my $fctime = ReadingsVal ($raname, 'fc_time', '-'); + $data{$type}{$name}{current}{dwdRad1hAge} = $fctime; + $data{$type}{$name}{current}{dwdRad1hAgeTS} = timestringToTimestamp ($fctime); debugLog ($paref, "apiCall", "DWD API - collect DWD Radiation data with start >$stime<- device: $raname =>"); for my $num (0..47) { my $dateTime = strftime "%Y-%m-%d %H:%M:00", localtime($sts + (3600 * $num)); # laufendes Datum ' ' Zeit - my $runh = int strftime "%H", localtime($sts + (3600 * $num) + 3600); # laufende Stunde in 24h format (00-23), DWD liefert Rad1h zum Ende der Stunde - Modul benutzt die Startzeit + my $runh = int strftime "%H", localtime($sts + (3600 * $num) + 3600); # laufende Stunde in 24h format (00-23), Rad1h = Absolute Globalstrahlung letzte 1 Stunde my ($fd,$fh) = _calcDayHourMove (0, $num); next if($fh == 24); - my $stime = ReadingsVal ($raname, "fc${fd}_${runh}_time", 0); my $rad = ReadingsVal ($raname, "fc${fd}_${runh}_Rad1h", undef); if (!defined $rad) { - $ret = "The reading 'fc${fd}_${runh}_Rad1h' doesn't exist. Check the device $raname!"; + $ret = "The reading 'fc${fd}_${runh}_Rad1h' doesn't exist.\nRun 'set $name plantConfiguration check' for further information."; $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{response_message} = $ret; debugLog ($paref, "apiCall", "DWD API - ERROR - got no data of starttime: $dateTime. ".$ret); @@ -4605,17 +4619,16 @@ sub Attr { my ($do,$val, $err); ### nicht mehr benötigte Daten löschen - Bereich kann später wieder raus !! - ########################################################################################## - if ($cmd eq 'set' && $aName eq 'affectNumHistDays') { # 30.01.2024 - if (!$init_done) { - return qq{Device "$name" -> The attribute '$aName' is obsolete and will be deleted soon. Please press "save config" when restart is finished.}; - } - else { - return qq{The attribute '$aName' is obsolete and will be deleted soon.}; - } - } - - ########################################################################################## + ###################################################################################################################### + #if ($cmd eq 'set' && $aName eq 'affectNumHistDays') { + # if (!$init_done) { + # return qq{Device "$name" -> The attribute '$aName' is obsolete and will be deleted soon. Please press "save config" when restart is finished.}; + # } + # else { + # return qq{The attribute '$aName' is obsolete and will be deleted soon.}; + # } + #} + ###################################################################################################################### if ($aName eq 'disable') { if($cmd eq 'set') { @@ -5586,12 +5599,11 @@ sub centralTask { RemoveInternalTimer ($hash, 'FHEM::SolarForecast::singleUpdateState'); ### nicht mehr benötigte Daten löschen - Bereich kann später wieder raus !! - ########################################################################################## - ## AI Raw Daten formatieren # 09.02.2024 + ########################################################################################################################## + ## AI Raw Daten formatieren # 09.02.2024 if (defined $data{$type}{$name}{aidectree}{airaw}) { for my $idx (sort keys %{$data{$type}{$name}{aidectree}{airaw}}) { - $data{$type}{$name}{aidectree}{airaw}{$idx}{wrp} = 0 if(AiRawdataVal ($hash, $idx, 'wrp', 0) eq '00'); - $data{$type}{$name}{aidectree}{airaw}{$idx}{wrp} = 5 if(AiRawdataVal ($hash, $idx, 'wrp', 0) eq '05'); + delete $data{$type}{$name}{aidectree}{airaw}{$idx}{wrp}; $data{$type}{$name}{aidectree}{airaw}{$idx}{temp} = 0 if(AiRawdataVal ($hash, $idx, 'temp', 0) eq '00'); $data{$type}{$name}{aidectree}{airaw}{$idx}{temp} = 5 if(AiRawdataVal ($hash, $idx, 'temp', 0) eq '05'); $data{$type}{$name}{aidectree}{airaw}{$idx}{temp} = -5 if(AiRawdataVal ($hash, $idx, 'temp', 0) eq '-05'); @@ -5617,8 +5629,7 @@ sub centralTask { else { my $sabin = sunalt2bin ($alt); $data{$type}{$name}{aidectree}{airaw}{$idx}{sunalt} = $sabin; - } - + } } my $sunaz = AiRawdataVal ($hash, $idx, 'sunaz', ''); @@ -5636,7 +5647,6 @@ sub centralTask { }; if ($@) { - Log3 ($name, 1, "$name - add sunaz - idx: $idx, hod: $h, err: $@"); delete $data{$type}{$name}{aidectree}{airaw}{$idx}; } else { @@ -5670,8 +5680,8 @@ sub centralTask { } } - ## nicht-Bin Werte löschen - my $ra = '0|00|05|5|10|15|20|25|30|35|40|45|50|55|60|65|70|75|80|85|90|95|100|percentile|simple'; + ## nicht-Bin Werte löschen / wrp löschen + my $ra = '0|00|05|5|10|15|20|25|30|35|40|45|50|55|60|65|70|75|80|85|90|95|100|2.{2}|percentile|simple'; for my $hod (keys %{$data{$type}{$name}{circular}}) { # 30.01.2024 for my $range (keys %{$data{$type}{$name}{circular}{$hod}{pvcorrf}}) { @@ -5681,6 +5691,11 @@ sub centralTask { for my $range (keys %{$data{$type}{$name}{circular}{$hod}{quality}}) { delete $data{$type}{$name}{circular}{$hod}{quality}{$range} if($range !~ /^($ra)$/xs); } + + for my $wp (keys %{$data{$type}{$name}{circular}{$hod}}) { # 19.02.204 + next if($wp ne 'wrp'); + delete $data{$type}{$name}{circular}{$hod}{$wp}; + } } ## currentWeatherDev in Attr umsetzen my $cwd = ReadingsVal ($name, 'currentWeatherDev', ''); # 30.01.2024 @@ -5701,8 +5716,8 @@ sub centralTask { readingsSingleUpdate ($hash, 'moduleDeclination', $mta, 0); readingsDelete ($hash, 'moduleTiltAngle'); } - - ############################################################################################ + + ####################################################################################################################### return if(!$init_done); @@ -6215,81 +6230,70 @@ sub _transferWeatherValues { delete $data{$type}{$name}{weatherdata}; # Wetterdaten Hash löschen $paref->{fcname} = $fcname; - my ($fc0_sr_mm, $fc0_ss_mm, $fc1_sr_mm, $fc1_ss_mm) = __sunRS ($paref); # Sonnenauf- und untergang + __sunRS ($paref); # Sonnenauf- und untergang delete $paref->{fcname}; - - $paref->{fc0_sr_mm} = $fc0_sr_mm; - $paref->{fc0_ss_mm} = $fc0_ss_mm; - $paref->{fc1_sr_mm} = $fc1_sr_mm; - $paref->{fc1_ss_mm} = $fc1_ss_mm; - + for my $step (1..$weatherDevMax) { - $paref->{step} = $step; + $paref->{step} = $step; __readDataWeather ($paref); # Wetterdaten in einen Hash einlesen delete $paref->{step}; } - delete $paref->{fc0_sr_mm}; - delete $paref->{fc0_ss_mm}; - delete $paref->{fc1_sr_mm}; - delete $paref->{fc1_ss_mm}; - __mergeDataWeather ($paref); # Wetterdaten zusammenfügen - my $cat = 'merge'; - for my $num (0..46) { my ($fd, $fh) = _calcDayHourMove ($chour, $num); last if($fd > 1); - - my $fh1 = $fh + 1; - my $wid = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$cat}{ww}; # signifikantes Wetter - my $wwd = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$cat}{wwd}; # Wetter Beschreibung - my $neff = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$cat}{neff}; # Effektive Wolkendecke - my $r101 = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$cat}{r101}; # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde - my $temp = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$cat}{ttt}; # Außentemperatur - my $don = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$cat}{don}; # Tag/Nacht-Grenze + my $wid = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{merge}{ww}; # signifikantes Wetter + my $wwd = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{merge}{wwd}; # Wetter Beschreibung + my $neff = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{merge}{neff}; # Effektive Wolkendecke + my $rr1c = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{merge}{rr1c}; # Gesamtniederschlag (1-stündig) letzte 1 Stunde + my $temp = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{merge}{ttt}; # Außentemperatur + my $don = $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{merge}{don}; # Tag/Nacht-Grenze my $nhtstr = "NextHour".sprintf "%02d", $num; $data{$type}{$name}{nexthours}{$nhtstr}{weatherid} = $wid; $data{$type}{$name}{nexthours}{$nhtstr}{cloudcover} = $neff; - $data{$type}{$name}{nexthours}{$nhtstr}{rainprob} = $r101; - $data{$type}{$name}{nexthours}{$nhtstr}{rainrange} = rain2bin ($r101); + $data{$type}{$name}{nexthours}{$nhtstr}{totalrain} = $rr1c; + $data{$type}{$name}{nexthours}{$nhtstr}{rainrange} = $rr1c; $data{$type}{$name}{nexthours}{$nhtstr}{temp} = $temp; $data{$type}{$name}{nexthours}{$nhtstr}{DoN} = $don; + my $fh1 = $fh + 1; # = hod + 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} = $wwd; $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)}{rr1c} = $rr1c; $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) { # Weather in pvHistory speichern - $paref->{wid} = $wid; - $paref->{histname} = "weatherid"; - $paref->{nhour} = sprintf "%02d",$fh1; + $paref->{val} = $wid // -1; + $paref->{histname} = 'weatherid'; + $paref->{nhour} = sprintf "%02d", $fh1; setPVhistory ($paref); - $paref->{wcc} = $neff; - $paref->{histname} = "weathercloudcover"; + $paref->{val} = $neff // 0; + $paref->{histname} = 'weathercloudcover'; setPVhistory ($paref); - $paref->{wrp} = $r101; - $paref->{histname} = "weatherrainprob"; + $paref->{val} = $rr1c; + $paref->{histname} = 'totalrain'; setPVhistory ($paref); - $paref->{temp} = $temp; - $paref->{histname} = "temperature"; + $paref->{val} = $temp; + $paref->{histname} = 'temperature'; setPVhistory ($paref); delete $paref->{histname}; + delete $paref->{val}; } } @@ -6308,11 +6312,6 @@ sub __readDataWeather { my $type = $paref->{type}; my $step = $paref->{step}; - my $fc0_sr_mm = $paref->{fc0_sr_mm}; - my $fc0_ss_mm = $paref->{fc0_ss_mm}; - my $fc1_sr_mm = $paref->{fc1_sr_mm}; - my $fc1_ss_mm = $paref->{fc1_ss_mm}; - my $fcname = AttrVal ($name, 'ctrlWeatherDev'.$step, ''); # Weather Forecast Device return if(!$fcname || !$defs{$fcname}); @@ -6325,34 +6324,36 @@ sub __readDataWeather { my ($fd, $fh) = _calcDayHourMove ($chour, $n); last if($fd > 1); - my $wid = ReadingsNum ($fcname, "fc${fd}_${fh}_ww", -1); # signifikantes Wetter - my $wwd = ReadingsVal ($fcname, "fc${fd}_${fh}_wwd", ''); # Wetter Beschreibung - my $neff = ReadingsNum ($fcname, "fc${fd}_${fh}_Neff", 0); # Effektive Wolkendecke - my $temp = ReadingsNum ($fcname, "fc${fd}_${fh}_TTT", 0); # Außentemperatur - my $r101 = int ReadingsNum ($fcname, "fc${fd}_${fh}_R101", 0); # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde - - my $don = 1; # es ist default "Tag" - my $fhstr = sprintf "%02d", $fh; # hier kann Tag/Nacht-Grenze verstellt werden - - if ($fd == 0 && ($fhstr lt $fc0_sr_mm || $fhstr gt $fc0_ss_mm)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang heute - $wid += 100; # "1" der WeatherID voranstellen wenn Nacht - $don = 0; + my $wid = ReadingsNum ($fcname, "fc${fd}_${fh}_ww", -1); # Signifikantes Wetter zum Vorhersagezeitpunkt + my $wwd = ReadingsVal ($fcname, "fc${fd}_${fh}_wwd", ''); # Wetter Beschreibung + my $neff = ReadingsNum ($fcname, "fc${fd}_${fh}_Neff", 0); # Effektiver Bedeckungsgrad zum Vorhersagezeitpunkt + my $temp = ReadingsNum ($fcname, "fc${fd}_${fh}_TTT", 0); # 2m-Temperatur zum Vorhersagezeitpunkt + my $sunup = ReadingsNum ($fcname, "fc${fd}_${fh}_SunUp", 0); # 1 - Tag + + my $fh1 = $fh + 1; + my $fd1 = $fd; + + if ($fh1 == 24) { + $fh1 = 0; + $fd1++; } - elsif ($fd == 1 && ($fhstr lt $fc1_sr_mm || $fhstr gt $fc1_ss_mm)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang morgen - $wid += 100; # "1" der WeatherID voranstellen wenn Nacht - $don = 0; - } - my $fh1 = $fh + 1; + last if($fd1 > 1); - debugLog ($paref, 'collectData', "Weather $step: fc${fd}_${fh1}, don: $don, ww: $wid, R101: $r101, TTT: $temp, Neff: $neff, wwd: $wwd"); + my $rr1c = ReadingsNum ($fcname, "fc${fd1}_${fh1}_RR1c", 0); # Gesamtniederschlag (1-stündig) letzte 1 Stunde - $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$step}{ww} = $wid; - $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$step}{wwd} = $wwd; - $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$step}{neff} = $neff; - $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$step}{r101} = $r101; - $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$step}{ttt} = $temp; - $data{$type}{$name}{weatherdata}{"fc${fd}_${fh1}"}{$step}{don} = $don; + if (!$sunup) { + $wid += 100; + } + + debugLog ($paref, 'collectData', "Weather $step: fc${fd}_${fh}, don: $sunup, ww: $wid, RR1c: $rr1c, TTT: $temp, Neff: $neff, wwd: $wwd"); + + $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{$step}{ww} = $wid; + $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{$step}{wwd} = $wwd; + $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{$step}{neff} = $neff; + $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{$step}{rr1c} = $rr1c; + $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{$step}{ttt} = $temp; + $data{$type}{$name}{weatherdata}{"fc${fd}_${fh}"}{$step}{don} = $sunup; } return; @@ -6378,26 +6379,26 @@ sub __mergeDataWeather { my ($q, $m) = (0,0); for my $key (sort keys %{$data{$type}{$name}{weatherdata}}) { - my ($z, $neff, $r101, $temp) = (0,0,0,0); + my ($z, $neff, $rr1c, $temp) = (0,0,0,0); $data{$type}{$name}{weatherdata}{$key}{merge}{don} = $data{$type}{$name}{weatherdata}{$key}{1}{don}; $data{$type}{$name}{weatherdata}{$key}{merge}{ww} = $data{$type}{$name}{weatherdata}{$key}{1}{ww}; $data{$type}{$name}{weatherdata}{$key}{merge}{wwd} = $data{$type}{$name}{weatherdata}{$key}{1}{wwd}; $data{$type}{$name}{weatherdata}{$key}{merge}{neff} = $data{$type}{$name}{weatherdata}{$key}{1}{neff}; - $data{$type}{$name}{weatherdata}{$key}{merge}{r101} = $data{$type}{$name}{weatherdata}{$key}{1}{r101}; + $data{$type}{$name}{weatherdata}{$key}{merge}{rr1c} = $data{$type}{$name}{weatherdata}{$key}{1}{rr1c}; $data{$type}{$name}{weatherdata}{$key}{merge}{ttt} = $data{$type}{$name}{weatherdata}{$key}{1}{ttt}; for my $step (1..$ds) { $q++; my $n = $data{$type}{$name}{weatherdata}{$key}{$step}{neff}; - my $r = $data{$type}{$name}{weatherdata}{$key}{$step}{r101}; + my $r = $data{$type}{$name}{weatherdata}{$key}{$step}{rr1c}; my $t = $data{$type}{$name}{weatherdata}{$key}{$step}{ttt}; next if(!isNumeric ($n) || !isNumeric ($r) || !isNumeric ($t)); $neff += $n; - $r101 += $r; + $rr1c += $r; $temp += $t; $z++; $m++; @@ -6406,19 +6407,19 @@ sub __mergeDataWeather { next if(!$z); $data{$type}{$name}{weatherdata}{$key}{merge}{neff} = sprintf "%.0f", ($neff / $z); - $data{$type}{$name}{weatherdata}{$key}{merge}{r101} = sprintf "%.0f", ($r101 / $z); + $data{$type}{$name}{weatherdata}{$key}{merge}{rr1c} = sprintf "%.2f", ($rr1c / $z); $data{$type}{$name}{weatherdata}{$key}{merge}{ttt} = sprintf "%.2f", ($temp / $z); debugLog ($paref, 'collectData', "Weather merged: $key, ". "don: $data{$type}{$name}{weatherdata}{$key}{merge}{don}, ". "ww: $data{$type}{$name}{weatherdata}{$key}{1}{ww}, ". - "R101: $data{$type}{$name}{weatherdata}{$key}{merge}{r101}, ". + "RR1c: $data{$type}{$name}{weatherdata}{$key}{merge}{rr1c}, ". "TTT: $data{$type}{$name}{weatherdata}{$key}{merge}{ttt}, ". "Neff: $data{$type}{$name}{weatherdata}{$key}{merge}{neff}, ". "wwd: $data{$type}{$name}{weatherdata}{$key}{merge}{wwd}"); } - debugLog ($paref, 'collectData', "Number of Weather datasets mergers - deliverd: $q, merged: $m, failures: ".($q - $m)); + debugLog ($paref, 'collectData', "Number of Weather datasets mergers - delivered: $q, merged: $m, failures: ".($q - $m)); return; } @@ -6513,7 +6514,6 @@ sub _transferAPIRadiationValues { my $nhtstr = 'NextHour'.sprintf "%02d", $num; my ($hod) = $wantdt =~ /\s(\d{2}):/xs; $hod = sprintf "%02d", int $hod + 1; # Stunde des Tages - my $rad1h = SolCastAPIVal ($hash, '?All', $wantdt, 'Rad1h', undef); my $params = { @@ -6543,14 +6543,15 @@ sub _transferAPIRadiationValues { my $pvfc; if ($msg eq 'accurate' || $msg eq 'spreaded') { - my $aivar = 100 * $pvaifc / $est; + my $aivar = 100; + $aivar = 100 * $pvaifc / $est if($est); if ($msg eq 'accurate' && $aivar >= $aiAccLowLim && $aivar <= $aiAccUpLim) { # KI liefert 'accurate' Treffer -> verwenden $data{$type}{$name}{nexthours}{$nhtstr}{aihit} = 1; $pvfc = $pvaifc; $useai = 1; - debugLog ($paref, 'aiData', qq{AI Hit - accurate result found -> hod: $hod, Rad1h: $rad1h, pvfc: $pvfc Wh}); + debugLog ($paref, 'aiData', qq{AI Hit - accurate result found -> variance $aivar, hod: $hod, Rad1h: $rad1h, pvfc: $pvfc Wh}); } if ($msg eq 'spreaded' && $aivar >= $aiSpreadLowLim && $aivar <= $aiSpreadUpLim) { # Abweichung AI von Standardvorhersage begrenzen @@ -6590,17 +6591,19 @@ sub _transferAPIRadiationValues { } if($fd == 0 && $fh1) { - $paref->{nhour} = sprintf "%02d", $fh1; + $paref->{nhour} = sprintf "%02d", $fh1; - $paref->{calcpv} = $pvfc; + $paref->{val} = $pvfc; $paref->{histname} = 'pvfc'; setPVhistory ($paref); - $paref->{rad1h} = $rad1h; + $paref->{val} = $rad1h; $paref->{histname} = 'radiation'; setPVhistory ($paref); delete $paref->{histname}; + delete $paref->{val}; + delete $paref->{nhour}; } } @@ -6659,7 +6662,7 @@ sub __calcPVestimates { my $reld = $fd == 0 ? "today" : $fd == 1 ? "tomorrow" : "unknown"; - my $rainprob = NexthoursVal ($hash, "NextHour".sprintf ("%02d", $num), "rainprob", 0); # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde + my $totalrain = NexthoursVal ($hash, "NextHour".sprintf ("%02d", $num), "totalrain", 0); # Gesamtniederschlag während der letzten Stunde kg/m2 my $cloudcover = NexthoursVal ($hash, "NextHour".sprintf ("%02d", $num), "cloudcover", 0); # effektive Wolkendecke nächste Stunde X my $temp = NexthoursVal ($hash, "NextHour".sprintf ("%02d",$num), "temp", $tempbasedef); # vorhergesagte Temperatur Stunde X my ($acu, $aln) = isAutoCorrUsed ($name); @@ -6735,14 +6738,14 @@ sub __calcPVestimates { if ($debug =~ /radiationProcess/xs) { $lh = { # Log-Hash zur Ausgabe - "Starttime" => $wantdt, - "Forecasted temperature" => $temp." °C", - "Cloudcover" => $cloudcover, - "Rainprob" => $rainprob, - "PV Correction mode" => ($acu ? $acu : 'no'), - "PV correction factor" => $hc, - "PV correction quality" => $hq, - "PV generation forecast" => $pvsum." Wh ".$logao, + "Starttime" => $wantdt, + "Forecasted temperature" => $temp." °C", + "Cloudcover" => $cloudcover, + "Total Rain last hour" => $totalrain." kg/m2", + "PV Correction mode" => ($acu ? $acu : 'no'), + "PV correction factor" => $hc, + "PV correction quality" => $hq, + "PV generation forecast" => $pvsum." Wh ".$logao, }; $sq = q{}; @@ -6780,24 +6783,27 @@ sub ___readCandQ { my $hq = '-'; # keine Qualität definiert delete $data{$type}{$name}{nexthours}{"NextHour".sprintf("%02d",$num)}{cloudrange}; + + my $sunalt = NexthoursVal ($hash, "NextHour".sprintf("%02d",$num), 'sunalt', ''); # Sun Altitude + my $safac = CircularSunaltkorrVal ($hash, sprintf("%02d",$fh1), $sunalt, 0); # Faktor gespeichert für eine Sun Altitude if ($acu =~ /on_complex/xs) { # Autokorrektur complex soll genutzt werden - my $range = cloud2bin ($cc); # Range errechnen - ($hc, $hq) = CircularAutokorrVal ($hash, sprintf("%02d",$fh1), $range, undef); # Korrekturfaktor/Qualität der Stunde des Tages (complex) + my $crang = cloud2bin ($cc); # Range errechnen + ($hc, $hq) = CircularCloudkorrVal ($hash, sprintf("%02d",$fh1), $crang, undef); # Korrekturfaktor/Qualität der Stunde des Tages (complex) $hq //= '-'; $hc //= 1; # Korrekturfaktor = 1 (keine Korrektur) # keine Qualität definiert $hc = 1 if(1 * $hc == 0); # 0.0-Werte ignorieren (Schleifengefahr) - $data{$type}{$name}{nexthours}{"NextHour".sprintf("%02d",$num)}{cloudrange} = $range; + $data{$type}{$name}{nexthours}{"NextHour".sprintf("%02d",$num)}{cloudrange} = $crang; } elsif ($acu =~ /on_simple/xs) { - ($hc, $hq) = CircularAutokorrVal ($hash, sprintf("%02d",$fh1), 'simple', undef); # Korrekturfaktor/Qualität der Stunde des Tages (simple) + ($hc, $hq) = CircularCloudkorrVal ($hash, sprintf("%02d",$fh1), 'simple', undef); # Korrekturfaktor/Qualität der Stunde des Tages (simple) $hq //= '-'; $hc //= 1; # Korrekturfaktor = 1 $hc = 1 if(1 * $hc == 0); # 0.0-Werte ignorieren (Schleifengefahr) } else { # keine Autokorrektur - ($hc, $hq) = CircularAutokorrVal ($hash, sprintf("%02d",$fh1), 'simple', undef); # Korrekturfaktor/Qualität der Stunde des Tages (simple) + ($hc, $hq) = CircularCloudkorrVal ($hash, sprintf("%02d",$fh1), 'simple', undef); # Korrekturfaktor/Qualität der Stunde des Tages (simple) $hq //= '-'; $hc = 1; } @@ -6807,13 +6813,15 @@ sub ___readCandQ { $data{$type}{$name}{nexthours}{"NextHour".sprintf("%02d",$num)}{pvcorrf} = $hc."/".$hq; if($fd == 0 && $fh1) { - $paref->{pvcorrf} = $hc."/".$hq; + $paref->{val} = $hc.'/'.$hq; $paref->{nhour} = sprintf "%02d", $fh1; $paref->{histname} = 'pvcorrfactor'; setPVhistory ($paref); delete $paref->{histname}; + delete $paref->{val}; + delete $paref->{nhour}; } return ($hc, $hq); @@ -6957,13 +6965,15 @@ sub _transferInverterValues { my $ethishour; if (!$histetot) { # etotal der aktuelle Stunde gesetzt ? - $paref->{etotal} = $etotal; - $paref->{nhour} = sprintf("%02d",$nhour); + $paref->{val} = $etotal; + $paref->{nhour} = sprintf "%02d", $nhour; $paref->{histname} = 'etotal'; setPVhistory ($paref); delete $paref->{histname}; + delete $paref->{nhour}; + delete $paref->{val}; my $etot = CurrentVal ($hash, "etotal", $etotal); $ethishour = int ($etotal - $etot); @@ -9528,25 +9538,29 @@ sub _calcCaQcomplex { return; } - my $chwcc = HistoryVal ($hash, $day, sprintf("%02d",$h), 'wcc', 0); # Wolkenbedeckung Heute & abgefragte Stunde - my $range = cloud2bin ($chwcc); + my $chwcc = HistoryVal ($hash, $day, sprintf("%02d",$h), 'wcc', 0); # Wolkenbedeckung Heute & abgefragte Stunde + my $sunalt = HistoryVal ($hash, $day, sprintf("%02d",$h), 'sunalt', 0); # Sonne Altitude + my $crang = cloud2bin ($chwcc); + my $sabin = sunalt2bin ($sunalt); $paref->{pvrl} = $pvrl; $paref->{pvfc} = $pvfc; - $paref->{range} = $range; + $paref->{crang} = $crang; + $paref->{sabin} = $sabin; $paref->{calc} = 'Complex'; my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref); delete $paref->{pvrl}; delete $paref->{pvfc}; - delete $paref->{range}; + delete $paref->{crang}; + delete $paref->{sabin}; delete $paref->{calc}; storeReading ('.pvCorrectionFactor_'.sprintf("%02d",$h).'_cloudcover', 'done'); if ($acu =~ /on_complex/xs) { - storeReading ('pvCorrectionFactor_'.sprintf("%02d",$h), $factor." (automatic - old factor: $oldfac, cloudiness range: $range, days in range: $dnum)"); + storeReading ('pvCorrectionFactor_'.sprintf("%02d",$h), $factor." (automatic - old factor: $oldfac, cloudiness range: $crang, days in range: $dnum)"); storeReading ('pvCorrectionFactor_'.sprintf("%02d",$h).'_autocalc', 'done'); } @@ -9588,16 +9602,16 @@ sub _calcCaQsimple { return; } - $paref->{pvrl} = $pvrl; - $paref->{pvfc} = $pvfc; - $paref->{range} = 'simple'; - $paref->{calc} = 'Simple'; + $paref->{pvrl} = $pvrl; + $paref->{pvfc} = $pvfc; + $paref->{crang} = 'simple'; + $paref->{calc} = 'Simple'; my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref); delete $paref->{pvrl}; delete $paref->{pvfc}; - delete $paref->{range}; + delete $paref->{crang}; delete $paref->{calc}; storeReading ('.pvCorrectionFactor_'.sprintf("%02d",$h).'_apipercentil', 'done'); @@ -9621,7 +9635,8 @@ sub __calcNewFactor { my $type = $paref->{type}; my $pvrl = $paref->{pvrl}; my $pvfc = $paref->{pvfc}; - my $range = $paref->{range}; + my $crang = $paref->{crang}; + my $sabin = $paref->{sabin}; my $h = $paref->{h}; my $calc = $paref->{calc}; @@ -9629,8 +9644,8 @@ sub __calcNewFactor { my $pvrlsum = $pvrl; my $pvfcsum = $pvfc; - my ($oldfac, $oldq) = CircularAutokorrVal ($hash, sprintf("%02d",$h), $range, 0); # bisher definierter Korrekturfaktor - my ($pvhis, $fchis, $dnum) = CircularSumVal ($hash, sprintf("%02d",$h), $range, 0); + my ($oldfac, $oldq) = CircularCloudkorrVal ($hash, sprintf("%02d",$h), $crang, 0); # bisher definierter Korrekturfaktor + my ($pvhis, $fchis, $dnum) = CircularSumVal ($hash, sprintf("%02d",$h), $crang, 0); $oldfac = 1 if(1 * $oldfac == 0); if ($dnum) { # Werte in History vorhanden -> haben Prio ! @@ -9651,9 +9666,9 @@ sub __calcNewFactor { $factor = sprintf "%.2f", ($pvrl / $pvfc); } - $data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvrlsum}{$range} = $pvrlsum; # PV Erzeugung Summe speichern - $data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvfcsum}{$range} = $pvfcsum; # PV Prognose Summe speichern - $data{$type}{$name}{circular}{sprintf("%02d",$h)}{dnumsum}{$range} = $dnum; # Anzahl aller historischen Tade dieser Range + $data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvrlsum}{$crang} = $pvrlsum; # PV Erzeugung Summe speichern + $data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvfcsum}{$crang} = $pvfcsum; # PV Prognose Summe speichern + $data{$type}{$name}{circular}{sprintf("%02d",$h)}{dnumsum}{$crang} = $dnum; # Anzahl aller historischen Tade dieser Range my $maxvar = AttrVal ($name, 'affectMaxDayVariance', $defmaxvar); # max. Korrekturvarianz $factor = 1.00 if(1 * $factor == 0); # 0.00-Werte ignorieren (Schleifengefahr) @@ -9672,11 +9687,16 @@ sub __calcNewFactor { my $qual = __calcFcQuality ($pvfc, $pvrl); # Qualität der Vorhersage für die vergangene Stunde debugLog ($paref, 'pvCorrection', "$calc Corrf -> start calculation correction factor for hour: $h"); - debugLog ($paref, 'pvCorrection', "$calc Corrf -> determined values - hour: $h, cloudiness range: $range, old corrf: $oldfac, new corrf: $factor, days: $dnum"); - debugLog ($paref, 'pvCorrection|saveData2Cache', "$calc Corrf -> write correction values into Circular - hour: $h, cloudiness range: $range, factor: $factor, quality: $qual"); + debugLog ($paref, 'pvCorrection', "$calc Corrf -> determined values - hour: $h, cloudiness range: $crang, old corrf: $oldfac, new corrf: $factor, days: $dnum"); + debugLog ($paref, 'pvCorrection|saveData2Cache', "$calc Corrf -> write correction values into Circular - hour: $h, cloudiness range: $crang, factor: $factor, quality: $qual"); - $data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvcorrf}{$range} = $factor; # Korrekturfaktor der jeweiligen Stunde als Datenquelle eintragen - $data{$type}{$name}{circular}{sprintf("%02d",$h)}{quality}{$range} = $qual; + $data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvcorrf}{$crang} = $factor; # Korrekturfaktor nach "Cloudcover" oder "Simple" + $data{$type}{$name}{circular}{sprintf("%02d",$h)}{quality}{$crang} = $qual; + + if (defined $sabin) { # Korrekturfaktor für Sonne Altitude + $sabin = 200 + $sabin; # 200 + value für pvcorrf Sonne Altitude + $data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvcorrf}{$sabin} = $factor; + } return ($oldfac, $factor, $dnum); } @@ -10720,9 +10740,16 @@ sub _graphicHeader { elsif ($api =~ /DWD/xs) { $nscc = ReadingsVal ($name, 'nextCycletime', '?'); $api .= ' '.$lrt; - + if ($scrm eq 'success') { - $img = FW_makeImage('10px-kreis-gruen.png', $htitles{scaresps}{$lang}.' '.$htitles{natc}{$lang}.' '.$nscc); + my $ptr = CurrentVal ($hash, 'dwdRad1hAge', '-'); + $img = FW_makeImage('10px-kreis-gruen.png', $htitles{scaresps}{$lang}.' '.$htitles{predtime}{$lang}.' '.$ptr); + + if ($paref->{t} - CurrentVal ($hash, 'dwdRad1hAgeTS', 0) > 7200) { + my $agetit = $htitles{arsrad2o}{$lang}; + $agetit =~ s//$name/xs; + $img = FW_makeImage('10px-kreis-gelb.png', $agetit.' '.$htitles{predtime}{$lang}.' '.$ptr); + } } else { $img = FW_makeImage('10px-kreis-rot.png', $htitles{scarespf}{$lang}.': '. $scrm); @@ -12640,8 +12667,8 @@ sub checkdwdattr { my $dwddev = shift; my $amref = shift; - my @fcprop = map { trim($_) } split ",", AttrVal($dwddev, "forecastProperties", "pattern"); - my $fcr = AttrVal($dwddev, "forecastResolution", 3); + my @fcprop = map { trim($_) } split ",", AttrVal ($dwddev, "forecastProperties", "pattern"); + my $fcr = AttrVal ($dwddev, "forecastResolution", 3); my $err; my @aneeded; @@ -12659,7 +12686,7 @@ sub checkdwdattr { $err .= qq{ERROR - device "$dwddev" -> attribute "forecastResolution" must be set to "1"}; } - Log3 ($name, 1, "$name - $err") if($err); + Log3 ($name, 2, "$name - $err") if($err); return $err; } @@ -12853,13 +12880,13 @@ sub aiAddInstance { ## no critic "not used" my $temp = AiRawdataVal ($hash, $idx, 'temp', 20); my $wcc = AiRawdataVal ($hash, $idx, 'wcc', 0); - my $wrp = AiRawdataVal ($hash, $idx, 'wrp', 0); + my $rr1c = AiRawdataVal ($hash, $idx, 'rr1c', 0); my $sunalt = AiRawdataVal ($hash, $idx, 'sunalt', 0); eval { $dtree->add_instance (attributes => { rad1h => $rad1h, temp => $temp, wcc => $wcc, - wrp => $wrp, + rr1c => $rr1c, sunalt => $sunalt, hod => $hod }, @@ -12871,7 +12898,7 @@ sub aiAddInstance { ## no critic "not used" return; }; - debugLog ($paref, 'aiProcess', qq{AI Instance added - hod: $hod, sunalt: $sunalt, rad1h: $rad1h, pvrl: $pvrl, wcc: $wcc, wrp: $wrp, temp: $temp}); + debugLog ($paref, 'aiProcess', qq{AI Instance added - hod: $hod, sunalt: $sunalt, rad1h: $rad1h, pvrl: $pvrl, wcc: $wcc, rr1c: $rr1c, temp: $temp}); } $data{$type}{$name}{aidectree}{object} = $dtree; @@ -12977,14 +13004,13 @@ sub aiGetResult { debugLog ($paref, 'aiData', "Start AI result check for hod: $hod"); my $wcc = NexthoursVal ($hash, $nhidx, 'cloudcover', 0); - my $wrp = NexthoursVal ($hash, $nhidx, 'rainprob', 0); + my $rr1c = NexthoursVal ($hash, $nhidx, 'totalrain', 0); my $temp = NexthoursVal ($hash, $nhidx, 'temp', 20); my $sunalt = NexthoursVal ($hash, $nhidx, 'sunalt', 0); my $sunaz = NexthoursVal ($hash, $nhidx, 'sunaz', 0); my $tbin = temp2bin ($temp); my $cbin = cloud2bin ($wcc); - my $rbin = rain2bin ($wrp); my $sabin = sunalt2bin ($sunalt); my $pvaifc; @@ -12992,7 +13018,7 @@ sub aiGetResult { eval { $pvaifc = $dtree->get_result (attributes => { rad1h => $rad1h, temp => $tbin, wcc => $cbin, - wrp => $rbin, + rr1c => $rr1c, sunalt => $sabin, sunaz => $sunaz, hod => $hod @@ -13006,7 +13032,7 @@ sub aiGetResult { } if (defined $pvaifc) { - debugLog ($paref, 'aiData', qq{AI accurate result found: pvaifc: $pvaifc (hod: $hod, sunaz: $sunaz, sunalt: $sabin, Rad1h: $rad1h, wcc: $wcc, wrp: $rbin, temp: $tbin)}); + debugLog ($paref, 'aiData', qq{AI accurate result found: pvaifc: $pvaifc (hod: $hod, sunaz: $sunaz, sunalt: $sabin, Rad1h: $rad1h, wcc: $wcc, rr1c: $rr1c, temp: $tbin)}); return ('accurate', $pvaifc); } @@ -13016,7 +13042,7 @@ sub aiGetResult { rad1h => $rad1h, temp => $tbin, wcc => $cbin, - wrp => $rbin, + rr1c => $rr1c, sunalt => $sabin, sunaz => $sunaz, hod => $hod, @@ -13041,7 +13067,7 @@ sub _aiGetSpread { my $rad1h = $paref->{rad1h}; my $temp = $paref->{temp}; my $wcc = $paref->{wcc}; - my $wrp = $paref->{wrp}; + my $rr1c = $paref->{rr1c}; my $sunalt = $paref->{sunalt}; my $sunaz = $paref->{sunaz}; my $hod = $paref->{hod}; @@ -13058,7 +13084,7 @@ sub _aiGetSpread { my $gra = { temp => $temp, wcc => $wcc, - wrp => $wrp, + rr1c => $rr1c, sunalt => $sunalt, sunaz => $sunaz, hod => $hod @@ -13106,7 +13132,7 @@ sub _aiGetSpread { my $pvaifc = $pos && $neg ? sprintf "%.0f", (($pos + $neg) / 2) : undef; if (defined $pvaifc) { - debugLog ($paref, 'aiData', qq{AI determined average result: pvaifc: $pvaifc Wh (hod: $hod, sunaz: $sunaz, sunalt: $sunalt, wcc: $wcc, wrp: $wrp, temp: $temp)}); + debugLog ($paref, 'aiData', qq{AI determined average result: pvaifc: $pvaifc Wh (hod: $hod, sunaz: $sunaz, sunalt: $sunalt, wcc: $wcc, rr1c: $rr1c, temp: $temp)}); return ('spreaded', $pvaifc); } @@ -13186,19 +13212,18 @@ sub aiAddRawData { my $temp = HistoryVal ($hash, $pvd, $hod, 'temp', 20); my $wcc = HistoryVal ($hash, $pvd, $hod, 'wcc', 0); - my $wrp = HistoryVal ($hash, $pvd, $hod, 'wrp', 0); + my $rr1c = HistoryVal ($hash, $pvd, $hod, 'rr1c', 0); my $sunalt = HistoryVal ($hash, $pvd, $hod, 'sunalt', 0); my $sunaz = HistoryVal ($hash, $pvd, $hod, 'sunaz', 0); my $tbin = temp2bin ($temp); my $cbin = cloud2bin ($wcc); - my $rbin = rain2bin ($wrp); my $sabin = sunalt2bin ($sunalt); $data{$type}{$name}{aidectree}{airaw}{$ridx}{rad1h} = $rad1h; $data{$type}{$name}{aidectree}{airaw}{$ridx}{temp} = $tbin; $data{$type}{$name}{aidectree}{airaw}{$ridx}{wcc} = $cbin; - $data{$type}{$name}{aidectree}{airaw}{$ridx}{wrp} = $rbin; + $data{$type}{$name}{aidectree}{airaw}{$ridx}{rr1c} = $rr1c; $data{$type}{$name}{aidectree}{airaw}{$ridx}{hod} = $hod; $data{$type}{$name}{aidectree}{airaw}{$ridx}{pvrl} = $pvrl; $data{$type}{$name}{aidectree}{airaw}{$ridx}{sunalt} = $sabin; @@ -13206,7 +13231,7 @@ sub aiAddRawData { $dosave = 1; - debugLog ($paref, 'aiProcess', "AI raw add - idx: $ridx, day: $pvd, hod: $hod, sunalt: $sabin, sunaz: $sunaz, rad1h: $rad1h, pvrl: $pvrl, wcc: $cbin, wrp: $rbin, temp: $tbin"); + debugLog ($paref, 'aiProcess', "AI raw add - idx: $ridx, day: $pvd, hod: $hod, sunalt: $sabin, sunaz: $sunaz, rad1h: $rad1h, pvrl: $pvrl, wcc: $cbin, rr1c: $rr1c, temp: $tbin"); } } @@ -13295,25 +13320,17 @@ sub setPVhistory { my $dayname = $paref->{dayname}; # aktueller Wochentagsname my $histname = $paref->{histname} // qq{}; my $pvrlvd = $paref->{pvrlvd}; # 1: Eintrag 'pvrl' wird im Lernprozess berücksichtigt - my $ethishour = $paref->{ethishour} // 0; - my $etotal = $paref->{etotal}; + my $ethishour = $paref->{ethishour}; my $batinthishour = $paref->{batinthishour}; # Batterieladung in Stunde my $btotin = $paref->{batintotal}; # totale Batterieladung my $batoutthishour = $paref->{batoutthishour}; # Batterieentladung in Stunde my $btotout = $paref->{batouttotal}; # totale Batterieentladung - my $calcpv = $paref->{calcpv} // 0; my $gcthishour = $paref->{gctotthishour} // 0; # Netzbezug my $fithishour = $paref->{gftotthishour} // 0; # Netzeinspeisung my $con = $paref->{con} // 0; # realer Hausverbrauch Energie my $confc = $paref->{confc} // 0; # Verbrauchsvorhersage my $consumerco = $paref->{consumerco}; # Verbrauch eines Verbrauchers - my $wid = $paref->{wid} // -1; - my $wcc = $paref->{wcc} // 0; # Wolkenbedeckung - my $wrp = $paref->{wrp} // 0; # Wahrscheinlichkeit von Niederschlag - my $pvcorrf = $paref->{pvcorrf} // "1.00/0"; # pvCorrectionFactor - my $temp = $paref->{temp}; # Außentemperatur my $val = $paref->{val}; # Wert zur Speicherung in pvHistory (soll mal generell verwendet werden -> Change) - my $rad1h = $paref->{rad1h}; # Strahlungsdaten speichern my $reorg = $paref->{reorg} // 0; # Neuberechnung von Werten in Stunde "99" nach Löschen von Stunden eines Tages my $reorgday = $paref->{reorgday} // q{}; # Tag der reorganisiert werden soll @@ -13366,13 +13383,12 @@ sub setPVhistory { $data{$type}{$name}{pvhist}{$day}{99}{pvrl} = $pvrlsum; } - if ($histname eq "radiation") { # irradiation - $data{$type}{$name}{pvhist}{$day}{$nhour}{rad1h} = $rad1h; + if ($histname eq 'radiation') { # irradiation + $data{$type}{$name}{pvhist}{$day}{$nhour}{rad1h} = $val; } if ($histname eq 'pvfc') { # prognostizierter Energieertrag - $val = $calcpv; - $data{$type}{$name}{pvhist}{$day}{$nhour}{pvfc} = $calcpv; + $data{$type}{$name}{pvhist}{$day}{$nhour}{pvfc} = $val; my $pvfcsum = 0; for my $k (keys %{$data{$type}{$name}{pvhist}{$day}}) { @@ -13474,9 +13490,8 @@ sub setPVhistory { $data{$type}{$name}{pvhist}{$day}{99}{"hourscsme${num}"} = sprintf "%.2f", ($minutes / 60 ) if($cycles); } - if ($histname eq "etotal") { # etotal des Wechselrichters - $val = $etotal; - $data{$type}{$name}{pvhist}{$day}{$nhour}{etotal} = $etotal; + if ($histname eq 'etotal') { # etotal des Wechselrichters + $data{$type}{$name}{pvhist}{$day}{$nhour}{etotal} = $val; $data{$type}{$name}{pvhist}{$day}{99}{etotal} = q{}; } @@ -13492,33 +13507,28 @@ sub setPVhistory { $data{$type}{$name}{pvhist}{$day}{99}{batouttotal} = q{}; } - if ($histname eq "weatherid") { # Wetter ID - $val = $wid; - $data{$type}{$name}{pvhist}{$day}{$nhour}{weatherid} = $wid; + if ($histname eq 'weatherid') { # Wetter ID + $data{$type}{$name}{pvhist}{$day}{$nhour}{weatherid} = $val; $data{$type}{$name}{pvhist}{$day}{99}{weatherid} = q{}; } - if ($histname eq "weathercloudcover") { # Wolkenbedeckung - $val = $wcc; - $data{$type}{$name}{pvhist}{$day}{$nhour}{wcc} = $wcc; + if ($histname eq 'weathercloudcover') { # Wolkenbedeckung + $data{$type}{$name}{pvhist}{$day}{$nhour}{wcc} = $val; $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}{99}{wrp} = q{}; + if ($histname eq 'totalrain') { # Gesamtniederschlag (1-stündig) letzte 1 Stunde + $data{$type}{$name}{pvhist}{$day}{$nhour}{rr1c} = $val; + $data{$type}{$name}{pvhist}{$day}{99}{rr1c} = q{}; } - if ($histname eq "pvcorrfactor") { # pvCorrectionFactor - $val = $pvcorrf; - $data{$type}{$name}{pvhist}{$day}{$nhour}{pvcorrf} = $pvcorrf; + if ($histname eq 'pvcorrfactor') { # pvCorrectionFactor + $data{$type}{$name}{pvhist}{$day}{$nhour}{pvcorrf} = $val; $data{$type}{$name}{pvhist}{$day}{99}{pvcorrf} = q{}; } - if ($histname eq "temperature") { # Außentemperatur - $val = $temp; - $data{$type}{$name}{pvhist}{$day}{$nhour}{temp} = $temp; + if ($histname eq 'temperature') { # Außentemperatur + $data{$type}{$name}{pvhist}{$day}{$nhour}{temp} = $val; $data{$type}{$name}{pvhist}{$day}{99}{temp} = q{}; } @@ -13589,7 +13599,7 @@ sub listDataPool { my $gfeedin = HistoryVal ($hash, $day, $key, 'gfeedin', '-'); my $wid = HistoryVal ($hash, $day, $key, 'weatherid', '-'); my $wcc = HistoryVal ($hash, $day, $key, 'wcc', '-'); - my $wrp = HistoryVal ($hash, $day, $key, 'wrp', '-'); + my $rr1c = HistoryVal ($hash, $day, $key, 'rr1c', '-'); my $temp = HistoryVal ($hash, $day, $key, 'temp', undef); my $pvcorrf = HistoryVal ($hash, $day, $key, 'pvcorrf', '-'); my $dayname = HistoryVal ($hash, $day, $key, 'dayname', undef); @@ -13618,7 +13628,7 @@ sub listDataPool { $ret .= "\n "; $ret .= "wid: $wid"; $ret .= ", wcc: $wcc"; - $ret .= ", wrp: $wrp"; + $ret .= ", rr1c: $rr1c"; $ret .= ", temp: $temp" if($temp); $ret .= ", pvcorrf: $pvcorrf"; $ret .= ", dayname: $dayname" if($dayname); @@ -13749,7 +13759,7 @@ sub listDataPool { my $wid = CircularVal ($hash, $idx, "weatherid", '-'); my $wtxt = CircularVal ($hash, $idx, "weathertxt", '-'); my $wccv = CircularVal ($hash, $idx, "wcc", '-'); - my $wrprb = CircularVal ($hash, $idx, "wrp", '-'); + my $rr1c = CircularVal ($hash, $idx, "rr1c", '-'); my $temp = CircularVal ($hash, $idx, "temp", '-'); my $pvcorrf = CircularVal ($hash, $idx, "pvcorrf", '-'); my $quality = CircularVal ($hash, $idx, "quality", '-'); @@ -13780,7 +13790,7 @@ sub listDataPool { if ($idx != 99) { $sq .= $idx." => pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit, pvrl: $pvrl\n"; - $sq .= " batin: $batin, batout: $batout, confc: $confc, gcon: $gcons, gfeedin: $gfeedin, wcc: $wccv, wrp: $wrprb\n"; + $sq .= " batin: $batin, batout: $batout, confc: $confc, gcon: $gcons, gfeedin: $gfeedin, wcc: $wccv, rr1c: $rr1c\n"; $sq .= " temp: $temp, wid: $wid, wtxt: $wtxt\n"; $sq .= " pvcorrf: $pvcf\n"; $sq .= " quality: $cfq\n"; @@ -13816,8 +13826,8 @@ sub listDataPool { my $aihit = NexthoursVal ($hash, $idx, 'aihit', '-'); # KI ForeCast Treffer Status my $wid = NexthoursVal ($hash, $idx, 'weatherid', '-'); my $neff = NexthoursVal ($hash, $idx, 'cloudcover', '-'); - my $crange = NexthoursVal ($hash, $idx, 'cloudrange', '-'); - my $r101 = NexthoursVal ($hash, $idx, 'rainprob', '-'); + my $crang = NexthoursVal ($hash, $idx, 'cloudrange', '-'); + my $rr1c = NexthoursVal ($hash, $idx, 'totalrain', '-'); my $rrange = NexthoursVal ($hash, $idx, 'rainrange', '-'); my $rad1h = NexthoursVal ($hash, $idx, 'rad1h', '-'); my $pvcorrf = NexthoursVal ($hash, $idx, 'pvcorrf', '-'); @@ -13834,11 +13844,11 @@ sub listDataPool { $sq .= "\n "; $sq .= "pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit, confc: $confc"; $sq .= "\n "; - $sq .= "confcEx: $confcex, DoN: $don, wid: $wid, wcc: $neff, wrp: $r101, temp=$temp"; + $sq .= "confcEx: $confcex, DoN: $don, wid: $wid, wcc: $neff, rr1c: $rr1c, temp=$temp"; $sq .= "\n "; $sq .= "rad1h: $rad1h, sunaz: $sunaz, sunalt: $sunalt"; $sq .= "\n "; - $sq .= "rrange: $rrange, crange: $crange, correff: $pvcorrf"; + $sq .= "rrange: $rrange, crange: $crang, correff: $pvcorrf"; } } @@ -13941,11 +13951,11 @@ sub listDataPool { my $sunaz = AiRawdataVal ($hash, $idx, 'sunaz', '-'); my $rad1h = AiRawdataVal ($hash, $idx, 'rad1h', '-'); my $wcc = AiRawdataVal ($hash, $idx, 'wcc', '-'); - my $wrp = AiRawdataVal ($hash, $idx, 'wrp', '-'); + my $rr1c = AiRawdataVal ($hash, $idx, 'rr1c', '-'); my $pvrl = AiRawdataVal ($hash, $idx, 'pvrl', '-'); my $temp = AiRawdataVal ($hash, $idx, 'temp', '-'); $sq .= "\n"; - $sq .= "$idx => hod: $hod, sunaz: $sunaz, sunalt: $sunalt, rad1h: $rad1h, wcc: $wcc, wrp: $wrp, pvrl: $pvrl, temp: $temp"; + $sq .= "$idx => hod: $hod, sunaz: $sunaz, sunalt: $sunalt, rad1h: $rad1h, wcc: $wcc, rr1c: $rr1c, pvrl: $pvrl, temp: $temp"; } } @@ -13962,17 +13972,31 @@ sub _ldchash2val { my $key = $paref->{key}; my $cval = $paref->{cval}; - my $ret = qq{}; + my $ret = qq{}; + my $ret2 = qq{}; if (ref $cval eq 'HASH') { no warnings 'numeric'; for my $f (sort {$a<=>$b} keys %{$pool->{$idx}{$key}}) { next if($f eq 'simple'); - $ret .= " " if($ret); - $ret .= "$f=".$pool->{$idx}{$key}{$f}; - my $ct = ($ret =~ tr/=// // 0) / 10; - $ret .= "\n " if($ct =~ /^([1-9])?$/); + if ($f !~ /2.{2}/xs) { + $ret .= " " if($ret); + $ret .= "$f=".$pool->{$idx}{$key}{$f}; + my $ct = ($ret =~ tr/=// // 0) / 10; + $ret .= "\n " if($ct =~ /^([1-9])?$/); + } + elsif ($f =~ /2.{2}/xs) { + $ret2 .= " " if($ret2); + $ret2 .= "$f=".$pool->{$idx}{$key}{$f}; + my $ct2 = ($ret2 =~ tr/=// // 0) / 10; + $ret2 .= "\n " if($ct2 =~ /^([1-9])?$/); + } + } + + if ($ret2) { + $ret .= "\n " if($ret && $ret !~ /\n\s+$/xs); + $ret .= $ret2; } use warnings; @@ -14112,8 +14136,7 @@ sub checkPlantConfig { $result->{'DWD Weather Attributes'}{fault} = 1; } else { - $result->{'DWD Weather Attributes'}{note} .= qq{checked attributes of device "$fcname":
}. join (' ', @dweattrmust).'
'; - $err = checkdwdattr ($name, $fcname, \@dweattrmust); + $err = checkdwdattr ($name, $fcname, \@dweattrmust); if ($err) { $result->{'DWD Weather Attributes'}{state} = $nok; @@ -14123,35 +14146,53 @@ sub checkPlantConfig { else { $result->{'DWD Weather Attributes'}{result} .= $hqtxt{fulfd}{$lang}." ($hqtxt{attrib}{$lang}: ctrlWeatherDev$step)
"; } + + $result->{'DWD Weather Attributes'}{note} .= qq{checked parameters and attributes of device "$fcname":
}; + $result->{'DWD Weather Attributes'}{note} .= 'forecastProperties -> '.join (' ', @dweattrmust).'
'; } } - ## Check Attribute DWD Radiation Device - ######################################### + ## Check DWD Radiation Device + ############################### if (isDWDUsed ($hash)) { - $result->{'DWD Radiation Attributes'}{state} = $ok; - $result->{'DWD Radiation Attributes'}{result} = ''; - $result->{'DWD Radiation Attributes'}{note} = ''; - $result->{'DWD Radiation Attributes'}{fault} = 0; + $result->{'DWD Radiation Properties'}{state} = $ok; + $result->{'DWD Radiation Properties'}{result} = ''; + $result->{'DWD Radiation Properties'}{note} = ''; + $result->{'DWD Radiation Properties'}{fault} = 0; if (!$raname || !$defs{$raname}) { - $result->{'DWD Radiation Attributes'}{state} = $nok; - $result->{'DWD Radiation Attributes'}{result} .= qq{The DWD device "$raname" doesn't exist
}; - $result->{'DWD Radiation Attributes'}{fault} = 1; + $result->{'DWD Radiation Properties'}{state} = $nok; + $result->{'DWD Radiation Properties'}{result} .= qq{The DWD device "$raname" doesn't exist
}; + $result->{'DWD Radiation Properties'}{fault} = 1; } else { - $result->{'DWD Radiation Attributes'}{note} .= qq{checked attributes of device "$raname":
}. join ' ', @draattrmust; - $err = checkdwdattr ($name, $raname, \@draattrmust); + $err = checkdwdattr ($name, $raname, \@draattrmust); if ($err) { - $result->{'DWD Radiation Attributes'}{state} = $nok; - $result->{'DWD Radiation Attributes'}{result} = $err; - $result->{'DWD Radiation Attributes'}{fault} = 1; + $result->{'DWD Radiation Properties'}{state} = $nok; + $result->{'DWD Radiation Properties'}{result} .= $err.'
'; + $result->{'DWD Radiation Properties'}{note} .= qq{
Check the parameters set in device '$raname': attribute 'forecastProperties'
}; + $result->{'DWD Radiation Properties'}{fault} = 1; } - else { - $result->{'DWD Radiation Attributes'}{result} = $hqtxt{fulfd}{$lang}; + + if (time() - CurrentVal ($hash, 'dwdRad1hAgeTS', 0) > 7200) { + $result->{'DWD Radiation Properties'}{state} = $warn; + $result->{'DWD Radiation Properties'}{note} .= qq{The Prediction time of radiation data (Rad1h) is older than 2 hours.
}; + $result->{'DWD Radiation Properties'}{note} .= qq{Check the DWD device '$raname' for proper functioning of the data retrieval.
}; + $result->{'DWD Radiation Properties'}{warn} = 1; + } + + if (!$err) { + $result->{'DWD Radiation Properties'}{result} .= $hqtxt{fulfd}{$lang}.'
'; } } + + if (!$result->{'DWD Radiation Properties'}{fault}) { + $result->{'DWD Radiation Properties'}{result} = $hqtxt{fulfd}{$lang}; + $result->{'DWD Radiation Properties'}{note} .= qq{
checked parameters and attributes device "$raname":
}; + $result->{'DWD Radiation Properties'}{note} .= 'Age of Rad1h data
'; + $result->{'DWD Radiation Properties'}{note} .= 'forecastProperties -> '.join (' ', @draattrmust).'
'; + } } ## Check Rooftop und Roof Ident Pair Settings (SolCast) @@ -14374,7 +14415,7 @@ sub checkPlantConfig { $result->{'API Access'}{state} = $nok; $result->{'API Access'}{result} .= qq{DWD last message:
"$lam"
}; $result->{'API Access'}{note} .= qq{Check the setup of the device "$raname".
}; - $result->{'API Access'}{note} .= qq{It is possible that not all readings are transmitted when "$raname" is newly set up.
}; + $result->{'API Access'}{note} .= qq{It is possible that not all readings are transmitted when "$raname" is newly set up or was changed.
}; $result->{'API Access'}{note} .= qq{In this case, wait until tomorrow and check again.
}; $result->{'API Access'}{fault} = 1; } @@ -15725,57 +15766,6 @@ sub cloud2bin { return $bin; } -################################################################ -# diskrete Rain Prob in "Bins" wandeln -################################################################ -sub rain2bin { - my $val = shift; - - my $bin = $val == 100 ? 100 : - $val > 97 ? 100 : - $val > 95 ? 95 : - $val > 92 ? 95 : - $val > 90 ? 90 : - $val > 87 ? 90 : - $val > 85 ? 85 : - $val > 82 ? 85 : - $val > 80 ? 80 : - $val > 77 ? 80 : - $val > 75 ? 75 : - $val > 72 ? 75 : - $val > 70 ? 70 : - $val > 67 ? 70 : - $val > 65 ? 65 : - $val > 62 ? 65 : - $val > 60 ? 60 : - $val > 57 ? 60 : - $val > 55 ? 55 : - $val > 52 ? 55 : - $val > 50 ? 50 : - $val > 47 ? 50 : - $val > 45 ? 45 : - $val > 42 ? 45 : - $val > 40 ? 40 : - $val > 37 ? 40 : - $val > 35 ? 35 : - $val > 32 ? 35 : - $val > 30 ? 30 : - $val > 27 ? 30 : - $val > 25 ? 25 : - $val > 22 ? 25 : - $val > 20 ? 20 : - $val > 17 ? 20 : - $val > 15 ? 15 : - $val > 12 ? 15 : - $val > 10 ? 10 : - $val > 7 ? 10 : - $val > 5 ? 5 : - $val > 2 ? 5 : - 0; - -return $bin; -} - ################################################################ # diskrete Sonnen Höhe (altitude) in "Bins" wandeln ################################################################ @@ -15981,7 +15971,7 @@ return; # weatherid - Wetter ID # wcc - Grad der Bewölkung # temp - Außentemperatur -# wrp - Niederschlagswahrscheinlichkeit +# rr1c - Gesamtniederschlag (1-stündig) letzte 1 Stunde kg/m2 # pvcorrf - PV Autokorrekturfaktor f. Stunde des Tages # dayname - Tagesname (Kürzel) # csmt${c} - Totalconsumption Consumer $c (1..$maxconsumer) @@ -16033,9 +16023,11 @@ return $def; # weatherid - DWD Wetter id # weathertxt - DWD Wetter Text # wcc - DWD Wolkendichte -# wrp - DWD Regenwahrscheinlichkeit +# rr1c - Gesamtniederschlag (1-stündig) letzte 1 Stunde kg/m2 # temp - Außentemperatur -# pvcorrf - PV Autokorrekturfaktoren (HASH) +# pvcorrf - PV Autokorrekturfaktoren (HASH), +# - ohne Wertesummand: Faktoren bezogen auf Cloudcover +# - 200 + sunalt: Faktoren bezogen auf Sonne Altitude # lastTsMaxSocRchd - Timestamp des letzten Erreichens von SoC >= maxSoC # nextTsMaxSocChge - Timestamp bis zu dem die Batterie mindestens einmal maxSoC erreichen soll # days2care - verbleibende Tage bis der Batterie Pflege-SoC (default $maxSoCdef) erreicht sein soll @@ -16076,64 +16068,103 @@ return $def; # für eine bestimmte Bewölkungs-Range aus dem circular-Hash # zurückliefern # Usage: -# ($f,$q) = CircularAutokorrVal ($hash, $hod, $range, $def) +# ($f,$q) = CircularCloudkorrVal ($hash, $hod, $crang, $def) # # $f: Korrekturfaktor f. Stunde des Tages # $q: Qualität des Korrekturfaktors # # $hod: Stunde des Tages (01,02,...,24) -# $range: Range Bewölkung (1...100) oder "simple" +# $crang: Range Bewölkung (1...100) oder "simple" # $def: Defaultwert # ################################################################ -sub CircularAutokorrVal { +sub CircularCloudkorrVal { my $hash = shift; my $hod = shift; - my $range = shift; + my $crang = shift; my $def = shift; my $name = $hash->{NAME}; my $type = $hash->{TYPE}; - my $pvcorrf = $def; + my $corrf = $def; my $quality = $def; if (defined($data{$type}{$name}{circular}) && defined($data{$type}{$name}{circular}{$hod}) && defined($data{$type}{$name}{circular}{$hod}{pvcorrf}) && - defined($data{$type}{$name}{circular}{$hod}{pvcorrf}{$range})) { - $pvcorrf = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range}; + defined($data{$type}{$name}{circular}{$hod}{pvcorrf}{$crang})) { + $corrf = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$crang}; } if (defined($data{$type}{$name}{circular}) && defined($data{$type}{$name}{circular}{$hod}) && defined($data{$type}{$name}{circular}{$hod}{quality}) && - defined($data{$type}{$name}{circular}{$hod}{quality}{$range})) { - $quality = $data{$type}{$name}{circular}{$hod}{quality}{$range}; + defined($data{$type}{$name}{circular}{$hod}{quality}{$crang})) { + $quality = $data{$type}{$name}{circular}{$hod}{quality}{$crang}; } -return ($pvcorrf, $quality); +return ($corrf, $quality); +} + +################################################################ +# Wert des Autokorrekturfaktors +# für eine bestimmte Sun Altitude-Range aus dem Circular-Hash +# zurückliefern +# Usage: +# $f = CircularSunaltkorrVal ($hash, $hod, $crang, $def) +# +# $f: Korrekturfaktor f. Stunde des Tages +# +# $hod: Stunde des Tages (01,02,...,24) +# $sabin: Range Sun Altitude (0..90) +# $def: Defaultwert +# +################################################################ +sub CircularSunaltkorrVal { + my $hash = shift; + my $hod = shift; + my $sunalt = shift; + my $def = shift; + + my $name = $hash->{NAME}; + my $type = $hash->{TYPE}; + my $corrf = $def; + + return $def if(!$sunalt); + + my $sabin = sunalt2bin ($sunalt); + $sabin = 200 + $sabin; + + if (defined($data{$type}{$name}{circular}) && + defined($data{$type}{$name}{circular}{$hod}) && + defined($data{$type}{$name}{circular}{$hod}{pvcorrf}) && + defined($data{$type}{$name}{circular}{$hod}{pvcorrf}{$sabin})) { + $corrf = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$sabin}; + } + +return ($corrf); } ######################################################################################################## # Die durchschnittliche reale PV Erzeugung, PV Prognose und Tage # einer bestimmten Bewölkungs-Range aus dem circular-Hash zurückliefern # Usage: -# ($pvrlsum, $pvfcsum, $dnumsum) = CircularSumVal ($hash, $hod, $range, $def) +# ($pvrlsum, $pvfcsum, $dnumsum) = CircularSumVal ($hash, $hod, $crang, $def) # # $pvrlsum: Summe reale PV Erzeugung pro Bewölkungsbereich über die gesamte Laufzeit # $pvfcsum: Summe PV Prognose pro Bewölkungsbereich über die gesamte Laufzeit # $dnumsum: Anzahl Tage pro Bewölkungsbereich über die gesamte Laufzeit # # $hod: Stunde des Tages (01,02,...,24) -# $range: Range Bewölkung (1...100) oder "simple" +# $crang: Range Bewölkung (1...100) oder "simple" # $def: Defaultwert # ####################################################################################################### sub CircularSumVal { my $hash = shift; my $hod = shift; - my $range = shift; + my $crang = shift; my $def = shift; my $name = $hash->{NAME}; @@ -16146,22 +16177,22 @@ sub CircularSumVal { if (defined($data{$type}{$name}{circular}) && defined($data{$type}{$name}{circular}{$hod}) && defined($data{$type}{$name}{circular}{$hod}{pvrlsum}) && - defined($data{$type}{$name}{circular}{$hod}{pvrlsum}{$range})) { - $pvrlsum = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range}; + defined($data{$type}{$name}{circular}{$hod}{pvrlsum}{$crang})) { + $pvrlsum = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$crang}; } if (defined($data{$type}{$name}{circular}) && defined($data{$type}{$name}{circular}{$hod}) && defined($data{$type}{$name}{circular}{$hod}{pvfcsum}) && - defined($data{$type}{$name}{circular}{$hod}{pvfcsum}{$range})) { - $pvfcsum = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range}; + defined($data{$type}{$name}{circular}{$hod}{pvfcsum}{$crang})) { + $pvfcsum = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$crang}; } if (defined($data{$type}{$name}{circular}) && defined($data{$type}{$name}{circular}{$hod}) && defined($data{$type}{$name}{circular}{$hod}{dnumsum}) && - defined($data{$type}{$name}{circular}{$hod}{dnumsum}{$range})) { - $dnumsum = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range}; + defined($data{$type}{$name}{circular}{$hod}{dnumsum}{$crang})) { + $dnumsum = $data{$type}{$name}{circular}{$hod}{dnumsum}{$crang}; } return ($pvrlsum, $pvfcsum, $dnumsum); @@ -16181,7 +16212,7 @@ return ($pvrlsum, $pvfcsum, $dnumsum); # weatherid - DWD Wetter id # cloudcover - DWD Wolkendichte # cloudrange - berechnete Bewölkungsrange -# rainprob - DWD Regenwahrscheinlichkeit +# totalrain - Gesamtniederschlag während der letzten Stunde kg/m2 # rad1h - Globalstrahlung (kJ/m2) # confc - prognostizierter Hausverbrauch (Wh) # confcEx - prognostizierter Hausverbrauch ohne registrierte Consumer (Wh) @@ -16221,6 +16252,8 @@ return $def; # batcharge - Bat SOC in % # batinstcap - installierte Batteriekapazität in Wh # ctrunning - aktueller Ausführungsstatus des Central Task +# dwdRad1hAge - Alter des Rad1h Wertes als Datumstring +# dwdRad1hAgeTS - Alter des Rad1h Wertes als Unix Timestamp # genslidereg - Schieberegister PV Erzeugung (Array) # h4fcslidereg - Schieberegister 4h PV Forecast (Array) # socslidereg - Schieberegister Batterie SOC (Array) @@ -16331,7 +16364,7 @@ return $def; # $key: rad1h - Strahlungsdaten # temp - Temeperatur als Bin # wcc - Bewölkung als Bin -# wrp - Regenwert als Bin +# rr1c - Gesamtniederschlag (1-stündig) letzte 1 Stunde kg/m2 # hod - Stunde des Tages # sunalt - Höhe der Sonne (in Dezimalgrad) # pvrl - reale PV Erzeugung @@ -17297,7 +17330,11 @@ to ensure that the system configuration is correct.
  • dwdCatalog

    - The German Weather Service provides a catalog of MOSMIX stations.
    + The German Weather Service (DWD) provides a catalog of MOSMIX stations.
    + The stations provide data whose meaning is explained in this + Overview. + The DWD distinguishes between MOSMIX_L and MOSMIX_S stations, which differ in terms of update frequency + and data volume.
    This command reads the catalog into SolarForecast and saves it in the file ./FHEM/FhemUtils/DWDcat_SolarForecast.
    The catalog can be extensively filtered and saved in GPS Exchange Format (GPX). @@ -17418,13 +17455,13 @@ to ensure that the system configuration is correct. pvaifc expected PV generation of the AI (Wh) pvfc PV generation forecast used (Wh) rad1h predicted global radiation - rrange calculated range of rain probability starttime start time of the record sunaz Azimuth of the sun (in decimal degrees) sunalt Altitude of the sun (in decimal degrees) temp predicted outdoor temperature today has value '1' if start date on current day - wrp predicted degree of rain probability + rr1c Total precipitation during the last hour kg/m2 + rrange range of total rain wid ID of the predicted weather wcc predicted degree of cloudiness @@ -17471,7 +17508,7 @@ to ensure that the system configuration is correct. sunaz Azimuth of the sun (in decimal degrees) wid Weather identification number wcc effective cloud cover - wrp Probability of precipitation > 0.1 mm during the respective hour + rr1c Total precipitation during the last hour kg/m2
@@ -17520,7 +17557,7 @@ to ensure that the system configuration is correct. tdayDvtn Today's deviation PV forecast/generation in % temp Outdoor temperature wcc Degree of cloud cover - wrp Degree of probability of rain + rr1c Total precipitation during the last hour kg/m2 wid ID of the predicted weather wtxt Description of the predicted weather ydayDvtn Deviation PV forecast/generation in % on the previous day @@ -18168,7 +18205,7 @@ to ensure that the system configuration is correct. - +
forecastDays 1
forecastProperties TTT,Neff,R101,ww,SunUp,SunRise,SunSet
forecastProperties TTT,Neff,RR1c,ww,SunUp,SunRise,SunSet
forecastResolution 1
forecastStation <Station code of the evaluated DWD station>
@@ -19422,7 +19459,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
  • dwdCatalog

    - Der Deutsche Wetterdienst stellt einen Katalog der MOSMIX Stationen zur Verfügung.
    + Der Deutsche Wetterdienst (DWD) stellt einen Katalog der MOSMIX Stationen zur Verfügung.
    + Die Stationen liefern Daten deren Bedeutung in dieser + Übersicht + erläutert ist. Der DWD unterscheidet dabei zwischen MOSMIX_L und MOSMIX_S Stationen die sich durch Aktualisierungfrequenz + und Datenumfang unterscheiden.
    Mit diesem Kommando wird der Katalog in SolarForecast eingelesen und in der Datei ./FHEM/FhemUtils/DWDcat_SolarForecast gespeichert.
    Der Katalog kann umfangreich gefiltert und im GPS Exchange Format (GPX) gespeichert werden. @@ -19544,13 +19585,13 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. pvaifc erwartete PV Erzeugung der KI (Wh) pvfc verwendete PV Erzeugungsprognose (Wh) rad1h vorhergesagte Globalstrahlung - rrange berechneter Bereich der Regenwahrscheinlichkeit starttime Startzeit des Datensatzes sunaz Azimuth der Sonne (in Dezimalgrad) sunalt Höhe der Sonne (in Dezimalgrad) temp vorhergesagte Außentemperatur today hat Wert '1' wenn Startdatum am aktuellen Tag - wrp vorhergesagter Grad der Regenwahrscheinlichkeit + rr1c Gesamtniederschlag in der letzten Stunde kg/m2 + rrange Bereich des Gesamtniederschlags wid ID des vorhergesagten Wetters wcc vorhergesagter Grad der Bewölkung @@ -19597,7 +19638,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. sunaz Azimuth der Sonne (in Dezimalgrad) wid Identifikationsnummer des Wetters wcc effektive Wolkenbedeckung - wrp Wahrscheinlichkeit von Niederschlag > 0,1 mm während der jeweiligen Stunde + rr1c Gesamtniederschlag in der letzten Stunde kg/m2
@@ -19647,7 +19688,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. tdayDvtn heutige Abweichung PV Prognose/Erzeugung in % temp Außentemperatur wcc Grad der Wolkenüberdeckung - wrp Grad der Regenwahrscheinlichkeit + rr1c Gesamtniederschlag in der letzten Stunde kg/m2 wid ID des vorhergesagten Wetters wtxt Beschreibung des vorhergesagten Wetters ydayDvtn Abweichung PV Prognose/Erzeugung in % am Vortag @@ -20297,7 +20338,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. - +
forecastDays 1
forecastProperties TTT,Neff,R101,ww,SunUp,SunRise,SunSet
forecastProperties TTT,Neff,RR1c,ww,SunUp,SunRise,SunSet
forecastResolution 1
forecastStation <Stationscode der ausgewerteten DWD Station>