2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 09:16:53 +00:00

55_DWD_OpenData.pm: contrib MOSMIX S version with timeout

git-svn-id: https://svn.fhem.de/fhem/trunk@28550 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2024-02-25 08:59:27 +00:00
parent b8b6027256
commit e26b2a5c0c
2 changed files with 619 additions and 419 deletions

View File

@ -920,6 +920,11 @@ sub Attr {
return "invalid value for forecastResolution (possible values are 1, 3 and 6)";
}
}
when ("timeout") {
unless ($value =~ /^[0-9]+$/x) {
return qq{invalid value for timeout. Use only figures 0-9!};
}
}
when ("forecastStation") {
my $oldForecastStation = ::AttrVal($name, 'forecastStation', undef);
if ($::init_done && defined($oldForecastStation) && $oldForecastStation ne $value) {
@ -1599,7 +1604,8 @@ sub GetForecast {
# kill old blocking call
::BlockingKill($hash->{".forecastBlockingCall"});
}
$hash->{".forecastBlockingCall"} = ::BlockingCall("DWD_OpenData::GetForecastStart", $hash, "DWD_OpenData::GetForecastFinish", 30, "DWD_OpenData::GetForecastAbort", $hash);
my $to = ::AttrVal($name, 'timeout', 60);
$hash->{".forecastBlockingCall"} = ::BlockingCall("DWD_OpenData::GetForecastStart", $hash, "DWD_OpenData::GetForecastFinish", $to, "DWD_OpenData::GetForecastAbort", $hash);
$hash->{forecastUpdating} = time();
@ -2250,7 +2256,8 @@ sub GetAlerts {
# kill old blocking call
::BlockingKill($hash->{".alertsBlockingCall".$communeUnion});
}
$hash->{".alertsBlockingCall".$communeUnion} = ::BlockingCall("DWD_OpenData::GetAlertsStart", $hash, "DWD_OpenData::GetAlertsFinish", 60, "DWD_OpenData::GetAlertsAbort", $hash);
my $to = ::AttrVal($name, 'timeout', 60);
$hash->{".alertsBlockingCall".$communeUnion} = ::BlockingCall("DWD_OpenData::GetAlertsStart", $hash, "DWD_OpenData::GetAlertsFinish", $to, "DWD_OpenData::GetAlertsAbort", $hash);
$alertsUpdating[$communeUnion] = time();
@ -2788,7 +2795,7 @@ sub DWD_OpenData_Initialize {
$hash->{AttrList} = 'disable:0,1 '
.'forecastStation forecastDays forecastProperties forecastResolution:1,3,6 forecastWW2Text:0,1 forecastPruning:0,1 '
.'forecastDataPrecision:low,high alertArea alertLanguage:DE,EN alertExcludeEvents '
.'timezone '
.'timezone timeout '
.$readingFnAttributes;
}
@ -3011,6 +3018,9 @@ sub DWD_OpenData_Initialize {
<li>disable {0|1}, default: 0<br>
Disable fetching data.
</li><br>
<li>timeout {Integer}, default: 60<br>
Timeout for getting data from DWD in seconds.
</li><br>
<li>timezone &lt;tz&gt;, default: OS dependent<br>
<a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">IANA TZ string</a> for date and time readings (e.g. "Europe/Berlin"), can be used to assume the perspective of a station that is in a different timezone or if your OS timezone settings do not match your local timezone. Alternatively you may use <code>tzselect</code> on the Linux command line to find a valid timezone string.
</li><br>

View File

@ -158,9 +158,13 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
"1.16.2" => "19.02.2024 minor changes, R101 -> RR1c, totalrain instead of weatherrainprob, delete wrp r101 ".
"1.16.3" => "24.02.2024 store pvcorrf, quality, pvrlsum, pvfcsum, dnumsum with value <sunalt2bin>.<cloud2bin> in pvCircular ".
"get pvcorrf / quality from neff in combination with sun altitude (CircularSunCloudkorrVal) ".
"delete CircularCloudkorrVal, show sun position in beamgrafic weather mouse over ",
"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 ",
"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 ".
@ -338,10 +342,10 @@ my $dwdcatgpx = $root."/FHEM/FhemUtils/DWDcat_SolarForecast.gpx";
my $aitrblto = 7200; # KI Training BlockingCall Timeout
my $aibcthhld = 0.2; # Schwelle der KI Trainigszeit ab der BlockingCall benutzt wird
my $aistdudef = 1095; # default Haltezeit KI Raw Daten (Tage)
my $aiSpreadUpLim = 150; # obere Abweichungsgrenze (%) AI 'Spread' von API Prognose
my $aiSpreadLowLim = 50; # untere Abweichungsgrenze (%) AI 'Spread' von API Prognose
my $aiAccUpLim = 170; # obere Abweichungsgrenze (%) AI 'Accurate' von API Prognose
my $aiAccLowLim = 30; # untere Abweichungsgrenze (%) AI 'Accurate' von API Prognose
my $aiSpreadUpLim = 130; # obere Abweichungsgrenze (%) AI 'Spread' von API Prognose
my $aiSpreadLowLim = 70; # untere Abweichungsgrenze (%) AI 'Spread' von API Prognose
my $aiAccUpLim = 150; # obere Abweichungsgrenze (%) AI 'Accurate' von API Prognose
my $aiAccLowLim = 50; # untere Abweichungsgrenze (%) AI 'Accurate' von API Prognose
my $calcmaxd = 30; # Anzahl Tage die zur Berechnung Vorhersagekorrektur verwendet werden
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
@ -693,6 +697,8 @@ my %htitles = (
DE => qq{Ein -> kein off-Kommando definiert!} },
natc => { EN => qq{automatic cycle:},
DE => qq{automatischer Zyklus:} },
predtime => { EN => qq{Prediction time Radiation data:},
DE => qq{Vorhersagezeitpunkt Strahlungsdaten:} },
upd => { EN => qq{Click for update},
DE => qq{Klick f&#252;r Update} },
on => { EN => qq{switched on},
@ -703,6 +709,12 @@ my %htitles = (
DE => qq{undefiniert} },
dela => { EN => qq{delayed},
DE => qq{verzoegert} },
azimuth => { EN => qq{Azimuth},
DE => qq{Azimut} },
elevatio => { EN => qq{Elevation},
DE => qq{H&#246;he} },
sunpos => { EN => qq{Sun position},
DE => qq{Sonnenstand} },
conrec => { EN => qq{Current time is within the consumption planning},
DE => qq{Aktuelle Zeit liegt innerhalb der Verbrauchsplanung} },
conrecba => { EN => qq{Current time is within the consumption planning, Priority charging Battery is active},
@ -745,6 +757,8 @@ my %htitles = (
DE => qq{Planungsstatus:&nbsp;<pstate>\nInfo:&nbsp;<supplmnt>\n\nEin:&nbsp;<start>\nAus:&nbsp;<stop>\nverbleibende Sperrzeit:&nbsp;<RLT> Sekunden} },
ainuse => { EN => qq{AI Perl module is installed, but the AI support is not used.\nRun 'set <NAME> plantConfiguration check' for hints.},
DE => qq{KI Perl Modul ist installiert, aber die KI Unterst&uuml;tzung wird nicht verwendet.\nPr&uuml;fen sie 'set <NAME> plantConfiguration check' f&uuml;r Hinweise.} },
arsrad2o => { EN => qq{API query successful but the radiation values are outdated.\nCheck the plant with 'set <NAME> plantConfiguration check'.},
DE => qq{API Abfrage erfolgreich aber die Strahlungswerte sind veraltet.\nPr&uuml;fen sie die Anlage mit 'set <NAME> plantConfiguration check'.} },
);
my %weather_ids = (
@ -962,7 +976,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 ".
@ -2531,7 +2544,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);
@ -3372,6 +3389,10 @@ sub __getDWDSolarData {
$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) {
@ -3381,7 +3402,6 @@ sub __getDWDSolarData {
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) {
@ -4608,17 +4628,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') {
@ -4681,7 +4700,7 @@ sub Attr {
if ($cmd eq 'set') {
if ($aName eq 'ctrlInterval' || $aName eq 'ctrlBackupFilesKeep' || $aName eq 'ctrlAIdataStorageDuration') {
unless ($aVal =~ /^[0-9]+$/x) {
return qq{The value for $aName is not valid. Use only figures 0-9 !};
return qq{Invalid value for $aName. Use only figures 0-9!};
}
}
@ -5620,7 +5639,6 @@ sub centralTask {
my $sabin = sunalt2bin ($alt);
$data{$type}{$name}{aidectree}{airaw}{$idx}{sunalt} = $sabin;
}
}
my $sunaz = AiRawdataVal ($hash, $idx, 'sunaz', '');
@ -5638,7 +5656,6 @@ sub centralTask {
};
if ($@) {
Log3 ($name, 1, "$name - add sunaz - idx: $idx, hod: $h, err: $@");
delete $data{$type}{$name}{aidectree}{airaw}{$idx};
}
else {
@ -5673,15 +5690,94 @@ sub centralTask {
}
## 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|percentile|simple';
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|.*\..*|simple';
for my $hod (keys %{$data{$type}{$name}{circular}}) { # 30.01.2024
for my $range (keys %{$data{$type}{$name}{circular}{$hod}{pvcorrf}}) {
delete $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range} if($range !~ /^($ra)$/xs);
if($range !~ /simple|\./xs) { # 24.02.2024
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"5.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"10.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"15.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"20.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"25.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"30.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"35.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"40.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
$data{$type}{$name}{circular}{$hod}{pvcorrf}{"45.$range"} = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
delete $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range};
}
delete $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range} if(!defined $data{$type}{$name}{circular}{$hod}{pvcorrf}{$range});
}
for my $range (keys %{$data{$type}{$name}{circular}{$hod}{quality}}) {
delete $data{$type}{$name}{circular}{$hod}{quality}{$range} if($range !~ /^($ra)$/xs);
if($range !~ /simple|\./xs) { # 24.02.2024
$data{$type}{$name}{circular}{$hod}{quality}{"5.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
$data{$type}{$name}{circular}{$hod}{quality}{"10.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
$data{$type}{$name}{circular}{$hod}{quality}{"15.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
$data{$type}{$name}{circular}{$hod}{quality}{"20.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
$data{$type}{$name}{circular}{$hod}{quality}{"25.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
$data{$type}{$name}{circular}{$hod}{quality}{"30.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
$data{$type}{$name}{circular}{$hod}{quality}{"35.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
$data{$type}{$name}{circular}{$hod}{quality}{"40.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
$data{$type}{$name}{circular}{$hod}{quality}{"45.$range"} = $data{$type}{$name}{circular}{$hod}{quality}{$range};
delete $data{$type}{$name}{circular}{$hod}{quality}{$range};
}
delete $data{$type}{$name}{circular}{$hod}{quality}{$range} if(!defined $data{$type}{$name}{circular}{$hod}{quality}{$range});
}
for my $range (keys %{$data{$type}{$name}{circular}{$hod}{pvrlsum}}) {
delete $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range} if($range !~ /^($ra)$/xs);
if($range !~ /simple|\./xs) { # 24.02.2024
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"5.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"10.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"15.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"20.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"25.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"30.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"35.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"40.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvrlsum}{"45.$range"} = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
delete $data{$type}{$name}{circular}{$hod}{pvrlsum}{$range};
}
}
for my $range (keys %{$data{$type}{$name}{circular}{$hod}{pvfcsum}}) {
delete $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range} if($range !~ /^($ra)$/xs);
if($range !~ /simple|\./xs) { # 24.02.2024
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"5.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"10.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"15.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"20.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"25.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"30.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"35.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"40.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
$data{$type}{$name}{circular}{$hod}{pvfcsum}{"45.$range"} = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
delete $data{$type}{$name}{circular}{$hod}{pvfcsum}{$range};
}
}
for my $range (keys %{$data{$type}{$name}{circular}{$hod}{dnumsum}}) {
delete $data{$type}{$name}{circular}{$hod}{dnumsum}{$range} if($range !~ /^($ra)$/xs);
if($range !~ /simple|\./xs) { # 24.02.2024
$data{$type}{$name}{circular}{$hod}{dnumsum}{"5.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
$data{$type}{$name}{circular}{$hod}{dnumsum}{"10.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
$data{$type}{$name}{circular}{$hod}{dnumsum}{"15.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
$data{$type}{$name}{circular}{$hod}{dnumsum}{"20.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
$data{$type}{$name}{circular}{$hod}{dnumsum}{"25.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
$data{$type}{$name}{circular}{$hod}{dnumsum}{"30.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
$data{$type}{$name}{circular}{$hod}{dnumsum}{"35.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
$data{$type}{$name}{circular}{$hod}{dnumsum}{"40.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
$data{$type}{$name}{circular}{$hod}{dnumsum}{"45.$range"} = $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
delete $data{$type}{$name}{circular}{$hod}{dnumsum}{$range};
}
}
for my $wp (keys %{$data{$type}{$name}{circular}{$hod}}) { # 19.02.204
@ -5689,6 +5785,7 @@ sub centralTask {
delete $data{$type}{$name}{circular}{$hod}{$wp};
}
}
## currentWeatherDev in Attr umsetzen
my $cwd = ReadingsVal ($name, 'currentWeatherDev', ''); # 30.01.2024
if ($cwd) {
@ -6583,17 +6680,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};
}
}
@ -6769,44 +6868,51 @@ sub ___readCandQ {
my $cc = $paref->{cloudcover};
my ($acu, $aln) = isAutoCorrUsed ($name); # Autokorrekturmodus
my $hc = ReadingsNum ($name, 'pvCorrectionFactor_'.sprintf("%02d",$fh1), 1.00); # Voreinstellung RAW-Korrekturfaktor
my $sunalt = NexthoursVal ($hash, "NextHour".sprintf("%02d",$num), 'sunalt', ''); # Sun Altitude
my $sabin = sunalt2bin ($sunalt);
my $hc = ReadingsNum ($name, 'pvCorrectionFactor_'.sprintf("%02d",$fh1), 1.00); # Voreinstellung RAW-Korrekturfaktor
my $hq = '-'; # keine Qualität definiert
my $crang = 'simple';
delete $data{$type}{$name}{nexthours}{"NextHour".sprintf("%02d",$num)}{cloudrange};
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)
$crang = cloud2bin ($cc); # Range errechnen
($hc, $hq) = CircularSunCloudkorrVal ($hash, sprintf("%02d",$fh1), $sabin, $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) = CircularSunCloudkorrVal ($hash, sprintf("%02d",$fh1), $sabin, '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) = CircularSunCloudkorrVal ($hash, sprintf("%02d",$fh1), $sabin, 'simple', undef); # Korrekturfaktor/Qualität der Stunde des Tages (simple)
$hq //= '-';
$hc = 1;
}
$hc = sprintf "%.2f", $hc;
debugLog ($paref, 'pvCorrection', "___readCandQ - fd: $fd, hod: ".sprintf("%02d",$fh1).", Sun Altitude Bin: $sabin, Cloud range: $crang, corrf: $hc, quality: $hq");
$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);
@ -6950,13 +7056,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);
@ -9521,25 +9629,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, Sun Alt range: $sabin, Cloud range: $crang, days in range: $dnum)");
storeReading ('pvCorrectionFactor_'.sprintf("%02d",$h).'_autocalc', 'done');
}
@ -9581,16 +9693,21 @@ sub _calcCaQsimple {
return;
}
$paref->{pvrl} = $pvrl;
$paref->{pvfc} = $pvfc;
$paref->{range} = 'simple';
$paref->{calc} = 'Simple';
my $sunalt = HistoryVal ($hash, $day, sprintf("%02d",$h), 'sunalt', 0); # Sonne Altitude
my $sabin = sunalt2bin ($sunalt);
$paref->{pvrl} = $pvrl;
$paref->{pvfc} = $pvfc;
$paref->{sabin} = $sabin;
$paref->{crang} = 'simple';
$paref->{calc} = 'Simple';
my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref);
delete $paref->{pvrl};
delete $paref->{pvfc};
delete $paref->{range};
delete $paref->{sabin};
delete $paref->{crang};
delete $paref->{calc};
storeReading ('.pvCorrectionFactor_'.sprintf("%02d",$h).'_apipercentil', 'done');
@ -9614,7 +9731,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};
@ -9622,8 +9740,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) = CircularSunCloudkorrVal ($hash, sprintf("%02d",$h), $sabin, $crang, 0); # bisher definierter Korrekturfaktor / Qualität
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 !
@ -9644,10 +9762,6 @@ 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
my $maxvar = AttrVal ($name, 'affectMaxDayVariance', $defmaxvar); # max. Korrekturvarianz
$factor = 1.00 if(1 * $factor == 0); # 0.00-Werte ignorieren (Schleifengefahr)
@ -9665,11 +9779,24 @@ 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, Sun Altitude range: $sabin, Cloud range: $crang, old factor: $oldfac, new factor: $factor, days: $dnum");
debugLog ($paref, 'pvCorrection|saveData2Cache', "$calc Corrf -> write correction values into Circular - hour: $h, Sun Altitude range: $sabin, Cloud 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;
if ($crang ne 'simple') {
my $idx = $sabin.'.'.$crang; # value für pvcorrf Sonne Altitude
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvrlsum}{$idx} = $pvrlsum; # PV Erzeugung Summe speichern
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvfcsum}{$idx} = $pvfcsum; # PV Prognose Summe speichern
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{dnumsum}{$idx} = $dnum; # Anzahl aller historischen Tade dieser Range
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvcorrf}{$idx} = $factor;
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{quality}{$idx} = $qual;
}
else {
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvrlsum}{$crang} = $pvrlsum;
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvfcsum}{$crang} = $pvfcsum;
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{dnumsum}{$crang} = $dnum;
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{pvcorrf}{$crang} = $factor;
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{quality}{$crang} = $qual;
}
return ($oldfac, $factor, $dnum);
}
@ -10715,7 +10842,14 @@ sub _graphicHeader {
$api .= '&nbsp;'.$lrt;
if ($scrm eq 'success') {
$img = FW_makeImage('10px-kreis-gruen.png', $htitles{scaresps}{$lang}.'&#10;'.$htitles{natc}{$lang}.' '.$nscc);
my $ptr = CurrentVal ($hash, 'dwdRad1hAge', '-');
$img = FW_makeImage('10px-kreis-gruen.png', $htitles{scaresps}{$lang}.'&#10;'.$htitles{predtime}{$lang}.' '.$ptr);
if ($paref->{t} - CurrentVal ($hash, 'dwdRad1hAgeTS', 0) > 7200) {
my $agetit = $htitles{arsrad2o}{$lang};
$agetit =~ s/<NAME>/$name/xs;
$img = FW_makeImage('10px-kreis-gelb.png', $agetit.'&#10;'.$htitles{predtime}{$lang}.' '.$ptr);
}
}
else {
$img = FW_makeImage('10px-kreis-rot.png', $htitles{scarespf}{$lang}.': '. $scrm);
@ -11651,6 +11785,8 @@ sub _beamGraphicFirstHour {
$hfcg->{0}{weather} = HistoryVal ($hash, $hfcg->{0}{day_str}, $hfcg->{0}{time_str}, 'weatherid', 999);
$hfcg->{0}{wcc} = HistoryVal ($hash, $hfcg->{0}{day_str}, $hfcg->{0}{time_str}, 'wcc', '-');
$hfcg->{0}{sunalt} = HistoryVal ($hash, $hfcg->{0}{day_str}, $hfcg->{0}{time_str}, 'sunalt', '-');
$hfcg->{0}{sunaz} = HistoryVal ($hash, $hfcg->{0}{day_str}, $hfcg->{0}{time_str}, 'sunaz', '-');
}
else {
$val1 = CircularVal ($hash, $hfcg->{0}{time_str}, 'pvfc', 0);
@ -11721,6 +11857,8 @@ sub _beamGraphicRemainingHours {
$hfcg->{$i}{weather} = HistoryVal ($hash, $ds, $hfcg->{$i}{time_str}, 'weatherid', 999);
$hfcg->{$i}{wcc} = HistoryVal ($hash, $ds, $hfcg->{$i}{time_str}, 'wcc', '-');
$hfcg->{$i}{sunalt} = HistoryVal ($hash, $ds, $hfcg->{$i}{time_str}, 'sunalt', '-');
$hfcg->{$i}{sunaz} = HistoryVal ($hash, $ds, $hfcg->{$i}{time_str}, 'sunaz', '-');
}
else {
$nh = sprintf '%02d', $i + $offset;
@ -11735,6 +11873,8 @@ sub _beamGraphicRemainingHours {
$val4 = NexthoursVal ($hash, 'NextHour'.$nh, 'confc', 0);
$hfcg->{$i}{weather} = NexthoursVal ($hash, 'NextHour'.$nh, 'weatherid', 999);
$hfcg->{$i}{wcc} = NexthoursVal ($hash, 'NextHour'.$nh, 'cloudcover', '-');
$hfcg->{$i}{sunalt} = NexthoursVal ($hash, 'NextHour'.$nh, 'sunalt', '-');
$hfcg->{$i}{sunaz} = NexthoursVal ($hash, 'NextHour'.$nh, 'sunaz', '-');
#$val4 = (ReadingsVal($name,"NextHour".$ii."_IsConsumptionRecommended",'no') eq 'yes') ? $icon : undef;
}
@ -12124,6 +12264,12 @@ sub __weatherOnBeam {
$wcc += 0 if(isNumeric ($wcc)); # Javascript Fehler vermeiden: https://forum.fhem.de/index.php/topic,117864.msg1233661.html#msg1233661
$title .= ': '.$wcc;
$title .= '&#10;';
$title .= $htitles{sunpos}{$lang}.':';
$title .= '&#10;';
$title .= $htitles{elevatio}{$lang}.' '.$hfcg->{$i}{sunalt};
$title .= '&#10;';
$title .= $htitles{azimuth}{$lang}.' '.$hfcg->{$i}{sunaz};
if ($icon_name eq 'unknown') {
debugLog ($paref, "graphic", "unknown weather id: ".$hfcg->{$i}{weather}.", please inform the maintainer");
@ -13286,21 +13432,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 $pvcorrf = $paref->{pvcorrf} // "1.00/0"; # pvCorrectionFactor
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
@ -13353,13 +13495,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}}) {
@ -13461,9 +13602,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{};
}
@ -13494,9 +13634,8 @@ sub setPVhistory {
$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{};
}
@ -13799,7 +13938,7 @@ 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 $crang = NexthoursVal ($hash, $idx, 'cloudrange', '-');
my $rr1c = NexthoursVal ($hash, $idx, 'totalrain', '-');
my $rrange = NexthoursVal ($hash, $idx, 'rainrange', '-');
my $rad1h = NexthoursVal ($hash, $idx, 'rad1h', '-');
@ -13821,7 +13960,7 @@ sub listDataPool {
$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";
}
}
@ -13839,10 +13978,11 @@ sub listDataPool {
my $aihit = NexthoursVal ($hash, $idx, 'aihit', '-');
my $pvfc = NexthoursVal ($hash, $idx, 'pvfc', '-');
my $neff = NexthoursVal ($hash, $idx, 'cloudcover', '-');
my $sunalt = NexthoursVal ($hash, $idx, 'sunalt', '-');
my ($f,$q) = split "/", $pvcorrf;
$sq .= "\n" if($sq);
$sq .= "Start: $nhts, Quality: $q, Factor: $f, AI usage: $aihit, PV expect: $pvfc Wh, Cloud: $neff";
$sq .= "Start: $nhts, Quality: $q, Factor: $f, AI usage: $aihit, PV expect: $pvfc Wh, Sun Alt: $sunalt, Cloud: $neff";
}
}
@ -13945,17 +14085,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 !~ /\./xs) {
$ret .= " " if($ret);
$ret .= "$f=".$pool->{$idx}{$key}{$f};
my $ct = ($ret =~ tr/=// // 0) / 10;
$ret .= "\n " if($ct =~ /^[1-9](.{1})?$/);
}
elsif ($f =~ /\./xs) {
$ret2 .= " " if($ret2);
$ret2 .= "$f=".$pool->{$idx}{$key}{$f};
my $ct2 = ($ret2 =~ tr/=// // 0) / 10;
$ret2 .= "\n " if($ct2 =~ /^[1-9](.{1})?$/);
}
}
if ($ret2) {
$ret .= "\n " if($ret && $ret !~ /\n\s+$/xs);
$ret .= $ret2;
}
use warnings;
@ -14095,8 +14249,7 @@ sub checkPlantConfig {
$result->{'DWD Weather Attributes'}{fault} = 1;
}
else {
$result->{'DWD Weather Attributes'}{note} .= qq{checked attributes of device "$fcname": <br>}. join (' ', @dweattrmust).'<br>';
$err = checkdwdattr ($name, $fcname, \@dweattrmust);
$err = checkdwdattr ($name, $fcname, \@dweattrmust);
if ($err) {
$result->{'DWD Weather Attributes'}{state} = $nok;
@ -14106,34 +14259,52 @@ sub checkPlantConfig {
else {
$result->{'DWD Weather Attributes'}{result} .= $hqtxt{fulfd}{$lang}." ($hqtxt{attrib}{$lang}: ctrlWeatherDev$step)<br>";
}
$result->{'DWD Weather Attributes'}{note} .= qq{checked parameters and attributes of device "$fcname": <br>};
$result->{'DWD Weather Attributes'}{note} .= 'forecastProperties -> '.join (' ', @dweattrmust).'<br>';
}
}
## 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 <br>};
$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 <br>};
$result->{'DWD Radiation Properties'}{fault} = 1;
}
else {
$result->{'DWD Radiation Attributes'}{note} .= qq{checked attributes of device "$raname": <br>}. 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.'<br>';
$result->{'DWD Radiation Properties'}{note} .= qq{<br>Check the parameters set in device '$raname': attribute 'forecastProperties' <br>};
$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. <br>};
$result->{'DWD Radiation Properties'}{note} .= qq{Check the DWD device '$raname' for proper functioning of the data retrieval.<br>};
$result->{'DWD Radiation Properties'}{warn} = 1;
}
if (!$err) {
$result->{'DWD Radiation Properties'}{result} .= $hqtxt{fulfd}{$lang}.'<br>';
}
}
if (!$result->{'DWD Radiation Properties'}{fault}) {
$result->{'DWD Radiation Properties'}{result} = $hqtxt{fulfd}{$lang};
$result->{'DWD Radiation Properties'}{note} .= qq{<br>checked parameters and attributes device "$raname": <br>};
$result->{'DWD Radiation Properties'}{note} .= 'Age of Rad1h data <br>';
$result->{'DWD Radiation Properties'}{note} .= 'forecastProperties -> '.join (' ', @draattrmust).'<br>';
}
}
@ -14357,7 +14528,7 @@ sub checkPlantConfig {
$result->{'API Access'}{state} = $nok;
$result->{'API Access'}{result} .= qq{DWD last message:<br>"$lam"<br>};
$result->{'API Access'}{note} .= qq{Check the setup of the device "$raname". <br>};
$result->{'API Access'}{note} .= qq{It is possible that not all readings are transmitted when "$raname" is newly set up. <br>};
$result->{'API Access'}{note} .= qq{It is possible that not all readings are transmitted when "$raname" is newly set up or was changed. <br>};
$result->{'API Access'}{note} .= qq{In this case, wait until tomorrow and check again.<br>};
$result->{'API Access'}{fault} = 1;
}
@ -15967,7 +16138,8 @@ return $def;
# wcc - DWD Wolkendichte
# rr1c - Gesamtniederschlag (1-stündig) letzte 1 Stunde kg/m2
# temp - Außentemperatur
# pvcorrf - PV Autokorrekturfaktoren (HASH)
# pvcorrf - PV Autokorrekturfaktoren (HASH),
# - <Sonne Altitude>.<Cloudcover>
# 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
@ -16003,69 +16175,76 @@ sub CircularVal {
return $def;
}
################################################################
# Wert des Autokorrekturfaktors und dessen Qualität
# für eine bestimmte Bewölkungs-Range aus dem circular-Hash
# zurückliefern
# Usage:
# ($f,$q) = CircularAutokorrVal ($hash, $hod, $range, $def)
###################################################################
# Wert des Autokorrekturfaktors
# für eine bestimmte Sun Altitude-Range aus dem Circular-Hash
# zurückliefern
# Usage:
# $f = CircularSunCloudkorrVal ($hash, $hod, $sabin, $crang, $def)
#
# $f: Korrekturfaktor f. Stunde des Tages
# $q: Qualität des Korrekturfaktors
# $f: Korrekturfaktor f. Stunde des Tages
#
# $hod: Stunde des Tages (01,02,...,24)
# $range: Range Bewölkung (1...100) oder "simple"
# $def: Defaultwert
# $hod: Stunde des Tages (01,02,...,24)
# $sabin: Sun Altitude Bin (0..90)
# $crang: Bewölkung Bin (0..100) oder "simple"
# $def: Defaultwert
#
################################################################
sub CircularAutokorrVal {
###################################################################
sub CircularSunCloudkorrVal {
my $hash = shift;
my $hod = shift;
my $range = shift;
my $sabin = shift;
my $crang = shift;
my $def = shift;
my $name = $hash->{NAME};
my $type = $hash->{TYPE};
my $name = $hash->{NAME};
my $type = $hash->{TYPE};
my $corrf = $def;
my $qual = $def;
my $idx = 'simple';
my $pvcorrf = $def;
my $quality = $def;
if ($crang ne 'simple') {
$idx = $sabin.'.'.$crang;
}
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}{$idx})) {
$corrf = $data{$type}{$name}{circular}{$hod}{pvcorrf}{$idx};
}
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}{$idx})) {
$qual = $data{$type}{$name}{circular}{$hod}{quality}{$idx};
}
return ($pvcorrf, $quality);
return ($corrf, $qual);
}
########################################################################################################
# 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"
# $hod: Stunde des Tages (01,02,..,24)
# $sabin: Sun Altitude Bin (0..90)
# $crang: Bewölkung Bin (1..100) oder "simple"
# $def: Defaultwert
#
#######################################################################################################
sub CircularSumVal {
my $hash = shift;
my $hod = shift;
my $range = shift;
my $sabin = shift;
my $crang = shift;
my $def = shift;
my $name = $hash->{NAME};
@ -16074,26 +16253,31 @@ sub CircularSumVal {
my $pvrlsum = $def;
my $pvfcsum = $def;
my $dnumsum = $def;
my $idx = 'simple';
if ($crang ne 'simple') {
$idx = $sabin.'.'.$crang;
}
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}{$idx})) {
$pvrlsum = $data{$type}{$name}{circular}{$hod}{pvrlsum}{$idx};
}
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}{$idx})) {
$pvfcsum = $data{$type}{$name}{circular}{$hod}{pvfcsum}{$idx};
}
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}{$idx})) {
$dnumsum = $data{$type}{$name}{circular}{$hod}{dnumsum}{$idx};
}
return ($pvrlsum, $pvfcsum, $dnumsum);
@ -16153,6 +16337,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)
@ -17421,6 +17607,8 @@ to ensure that the system configuration is correct.
The hours 01 - 24 refer to the hour of the day, e.g. the hour 09 refers to the time from
08 - 09 o'clock. <br>
Hour 99 has a special function. <br>
The values of the keys pvcorrf, quality, pvrlsum, pvfcsum and dnumsum are coded in the form
&lt;range sun elevation&gt;.&lt;cloud cover range&gt;. <br>
Explanation of the values: <br><br>
<ul>
@ -19552,6 +19740,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Die Stundenangaben 01 - 24 beziehen sich auf die Stunde des Tages, z.B. bezieht sich die Stunde 09 auf die Zeit von
08 - 09 Uhr. <br>
Die Stunde 99 hat eine Sonderfunktion. <br>
Die Werte der Schlüssel pvcorrf, quality, pvrlsum, pvfcsum und dnumsum sind in der Form
&lt;Bereich Sonnenstand Höhe&gt;.&lt;Bewölkungsbreich&gt; kodiert. <br>
Erläuterung der Werte: <br><br>
<ul>