mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-26 10:34:52 +00:00
76_SolarForecast: first step of multi weather device merger
git-svn-id: https://svn.fhem.de/fhem/trunk@28466 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
8ed0b20a5a
commit
f311d8589e
@ -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: first step of multi weather device merger
|
||||
- change: 76_SolarForecast: language support consumer info
|
||||
- feature: 72_FRITZBOX: set <name> <smartHome>
|
||||
get <name> <luaData> <smartHome>
|
||||
|
@ -157,6 +157,7 @@ BEGIN {
|
||||
|
||||
# Versions History intern
|
||||
my %vNotesIntern = (
|
||||
"1.14.3" => "02.02.2024 _transferWeatherValues: first step of multi weather device merger ",
|
||||
"1.14.2" => "02.02.2024 fix warning, _transferAPIRadiationValues: Consider upper and lower deviation limit AI to API forecast ",
|
||||
"1.14.1" => "01.02.2024 language support for ___setConsumerPlanningState -> supplement, fix setting 'swoncond not met' ",
|
||||
"1.14.0" => "31.01.2024 data maintenance, new sub _addDynAttr for adding attributes at runtime ".
|
||||
@ -924,7 +925,7 @@ sub Initialize {
|
||||
"affectConsForecastIdentWeekdays:1,0 ".
|
||||
"affectConsForecastInPlanning:1,0 ".
|
||||
"affectMaxDayVariance ".
|
||||
"affectNumHistDays:slider,1,1,30 ".
|
||||
"affectNumHistDays:obsolete ".
|
||||
"affectSolCastPercentile:select,10,50,90 ".
|
||||
"consumerLegend:none,icon_top,icon_bottom,text_top,text_bottom ".
|
||||
"consumerAdviceIcon ".
|
||||
@ -4197,6 +4198,15 @@ sub Attr {
|
||||
# $name is device name
|
||||
# aName and aVal are Attribute name and value
|
||||
|
||||
if ($cmd eq 'set' && $aName eq 'affectNumHistDays') {
|
||||
if (!$init_done) {
|
||||
return qq{Device "$name" -> The attribute 'affectNumHistDays' is obsolete and will be deleted soon. Please press "save config" when restart is finished.};
|
||||
}
|
||||
else {
|
||||
return qq{The attribute 'affectNumHistDays' is obsolete and will be deleted soon.};
|
||||
}
|
||||
}
|
||||
|
||||
if ($aName eq 'disable') {
|
||||
if($cmd eq 'set') {
|
||||
$do = $aVal ? 1 : 0;
|
||||
@ -5566,67 +5576,51 @@ sub _transferWeatherValues {
|
||||
my $name = $paref->{name};
|
||||
my $t = $paref->{t}; # Epoche Zeit
|
||||
my $chour = $paref->{chour};
|
||||
my $date = $paref->{date}; # aktuelles Datum
|
||||
|
||||
my $fcname = AttrVal ($name, 'ctrlWeatherDev1', ''); # Weather Forecast Device
|
||||
my $fcname = AttrVal ($name, 'ctrlWeatherDev1', ''); # Standard Weather Forecast Device
|
||||
return if(!$fcname || !$defs{$fcname});
|
||||
|
||||
my $err = checkdwdattr ($name, $fcname, \@dweattrmust);
|
||||
$paref->{state} = $err if($err);
|
||||
|
||||
debugLog ($paref, 'collectData', "collect Weather data - device: $fcname =>");
|
||||
$paref->{fcname} = $fcname;
|
||||
my ($fc0_sr_mm, $fc0_ss_mm, $fc1_sr_mm, $fc1_ss_mm) = __sunRS ($paref); # Sonnenauf- und untergang
|
||||
delete $paref->{fcname};
|
||||
|
||||
for my $step (1..3) {
|
||||
$paref->{step} = $step;
|
||||
$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;
|
||||
|
||||
__readDataWeather ($paref); # Wetterdaten in einen Hash einlesen
|
||||
|
||||
delete $paref->{fc0_sr_mm};
|
||||
delete $paref->{fc0_ss_mm};
|
||||
delete $paref->{fc1_sr_mm};
|
||||
delete $paref->{fc1_ss_mm};
|
||||
delete $paref->{step};
|
||||
}
|
||||
|
||||
my $time_str;
|
||||
my $type = $paref->{type};
|
||||
|
||||
$paref->{fcname} = $fcname;
|
||||
my ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss) = __sunRS ($paref); # Sonnenauf- und untergang
|
||||
delete $paref->{fcname};
|
||||
|
||||
$data{$type}{$name}{current}{sunriseToday} = $date.' '.$fc0_sr.':00';
|
||||
$data{$type}{$name}{current}{sunriseTodayTs} = timestringToTimestamp ($date.' '.$fc0_sr.':00');
|
||||
|
||||
$data{$type}{$name}{current}{sunsetToday} = $date.' '.$fc0_ss.':00';
|
||||
$data{$type}{$name}{current}{sunsetTodayTs} = timestringToTimestamp ($date.' '.$fc0_ss.':00');
|
||||
|
||||
debugLog ($paref, 'collectData', "sunrise/sunset today: $fc0_sr / $fc0_ss, sunrise/sunset tomorrow: $fc1_sr / $fc1_ss");
|
||||
|
||||
storeReading ('Today_SunRise', $fc0_sr);
|
||||
storeReading ('Today_SunSet', $fc0_ss);
|
||||
storeReading ('Tomorrow_SunRise', $fc1_sr);
|
||||
storeReading ('Tomorrow_SunSet', $fc1_ss);
|
||||
|
||||
my $fc0_sr_round = sprintf "%02d", (split ":", $fc0_sr)[0];
|
||||
my $fc0_ss_round = sprintf "%02d", (split ":", $fc0_ss)[0];
|
||||
my $fc1_sr_round = sprintf "%02d", (split ":", $fc1_sr)[0];
|
||||
my $fc1_ss_round = sprintf "%02d", (split ":", $fc1_ss)[0];
|
||||
# Log3 ($name, 1, "$name - Weather data dump:\n". Dumper $data{$type}{$name}{weatherdata});
|
||||
|
||||
for my $num (0..46) {
|
||||
my ($fd, $fh) = _calcDayHourMove ($chour, $num);
|
||||
last if($fd > 1);
|
||||
|
||||
my $fh1 = $fh + 1;
|
||||
my $fh2 = $fh1 == 24 ? 23 : $fh1;
|
||||
my $wid = ReadingsNum ($fcname, "fc${fd}_${fh2}_ww", -1);
|
||||
my $neff = ReadingsNum ($fcname, "fc${fd}_${fh2}_Neff", 0); # Effektive Wolkendecke
|
||||
my $r101 = ReadingsNum ($fcname, "fc${fd}_${fh2}_R101", 0); # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde
|
||||
my $temp = ReadingsNum ($fcname, "fc${fd}_${fh2}_TTT", 0); # Außentemperatur
|
||||
my $cat = 1;
|
||||
|
||||
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_round || $fhstr gt $fc0_ss_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang heute
|
||||
$wid += 100; # "1" der WeatherID voranstellen wenn Nacht
|
||||
$don = 0;
|
||||
}
|
||||
elsif ($fd == 1 && ($fhstr lt $fc1_sr_round || $fhstr gt $fc1_ss_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang morgen
|
||||
$wid += 100; # "1" der WeatherID voranstellen wenn Nacht
|
||||
$don = 0;
|
||||
}
|
||||
|
||||
my $txt = ReadingsVal($fcname, "fc${fd}_${fh2}_wwd", '');
|
||||
|
||||
debugLog ($paref, 'collectData', "wid: fc${fd}_${fh1}_ww, val: $wid, txt: $txt, cc: $neff, rp: $r101, temp: $temp");
|
||||
my $wid = $data{$type}{$name}{weatherdata}{$cat}{"fc${fd}_${fh1}"}{ww}; # signifikantes Wetter
|
||||
my $wwd = $data{$type}{$name}{weatherdata}{$cat}{"fc${fd}_${fh1}"}{wwd}; # Wetter Beschreibung
|
||||
my $neff = $data{$type}{$name}{weatherdata}{$cat}{"fc${fd}_${fh1}"}{neff}; # Effektive Wolkendecke
|
||||
my $r101 = $data{$type}{$name}{weatherdata}{$cat}{"fc${fd}_${fh1}"}{r101}; # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde
|
||||
my $temp = $data{$type}{$name}{weatherdata}{$cat}{"fc${fd}_${fh1}"}{ttt}; # Außentemperatur
|
||||
my $don = $data{$type}{$name}{weatherdata}{$cat}{"fc${fd}_${fh1}"}{don}; # Tag/Nacht-Grenze
|
||||
|
||||
$time_str = "NextHour".sprintf "%02d", $num;
|
||||
$data{$type}{$name}{nexthours}{$time_str}{weatherid} = $wid;
|
||||
@ -5638,7 +5632,7 @@ sub _transferWeatherValues {
|
||||
|
||||
if ($num < 23 && $fh < 24) { # Ringspeicher Weather Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251
|
||||
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{weatherid} = $wid;
|
||||
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{weathertxt} = $txt;
|
||||
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{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)}{temp} = $temp;
|
||||
@ -5648,10 +5642,10 @@ sub _transferWeatherValues {
|
||||
}
|
||||
}
|
||||
|
||||
if($fd == 0 && $fh1) { # Weather in pvhistory speichern
|
||||
if ($fd == 0 && $fh1) { # Weather in pvHistory speichern
|
||||
$paref->{wid} = $wid;
|
||||
$paref->{histname} = "weatherid";
|
||||
$paref->{nhour} = sprintf("%02d",$fh1);
|
||||
$paref->{nhour} = sprintf "%02d",$fh1;
|
||||
setPVhistory ($paref);
|
||||
|
||||
$paref->{wcc} = $neff;
|
||||
@ -5673,6 +5667,70 @@ sub _transferWeatherValues {
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# lese Wetterdaten aus Device im Attribut ctrlWeatherDevX
|
||||
# X = laufende Schleifenvariable $step
|
||||
################################################################
|
||||
sub __readDataWeather {
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
my $chour = $paref->{chour}; # aktuelles Datum
|
||||
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});
|
||||
|
||||
my $err = checkdwdattr ($name, $fcname, \@dweattrmust);
|
||||
$paref->{state} = $err if($err);
|
||||
|
||||
delete $data{$type}{$name}{weatherdata}{$step};
|
||||
|
||||
debugLog ($paref, 'collectData', "collect Weather data step $step - device: $fcname =>");
|
||||
|
||||
for my $n (0..46) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
debugLog ($paref, 'collectData', "Weather storage $step: fc${fd}_${fh1}_x, don: $don, ww: $wid, R101: $r101, TTT: $temp, Neff: $neff, wwd: $wwd");
|
||||
|
||||
$data{$type}{$name}{weatherdata}{$step}{"fc${fd}_${fh1}"}{ww} = $wid;
|
||||
$data{$type}{$name}{weatherdata}{$step}{"fc${fd}_${fh1}"}{wwd} = $wwd;
|
||||
$data{$type}{$name}{weatherdata}{$step}{"fc${fd}_${fh1}"}{neff} = $neff;
|
||||
$data{$type}{$name}{weatherdata}{$step}{"fc${fd}_${fh1}"}{r101} = $r101;
|
||||
$data{$type}{$name}{weatherdata}{$step}{"fc${fd}_${fh1}"}{ttt} = $temp;
|
||||
$data{$type}{$name}{weatherdata}{$step}{"fc${fd}_${fh1}"}{don} = $don;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Sonnenauf- und untergang bei gesetzten global
|
||||
# latitude/longitude Koordinaten berechnen, sonst aus DWD
|
||||
@ -5680,13 +5738,18 @@ return;
|
||||
################################################################
|
||||
sub __sunRS {
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
my $t = $paref->{t}; # aktuelle Zeit
|
||||
my $fcname = $paref->{fcname};
|
||||
my $type = $paref->{type};
|
||||
my $date = $paref->{date}; # aktuelles Datum
|
||||
|
||||
my ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss);
|
||||
|
||||
my ($cset, $lat, $lon) = locCoordinates();
|
||||
|
||||
debugLog ($paref, 'collectData', "collect sunrise/sunset times - device: $fcname =>");
|
||||
|
||||
if ($cset) {
|
||||
my $alt = 'HORIZON=-0.833'; # default from https://metacpan.org/release/JFORGET/DateTime-Event-Sunrise-0.0505/view/lib/DateTime/Event/Sunrise.pm
|
||||
$fc0_sr = substr (sunrise_abs_dat ($t, $alt), 0, 5); # SunRise heute
|
||||
@ -5701,7 +5764,25 @@ sub __sunRS {
|
||||
$fc1_ss = ReadingsVal ($fcname, 'fc1_SunSet', '00:00');
|
||||
}
|
||||
|
||||
return ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss);
|
||||
$data{$type}{$name}{current}{sunriseToday} = $date.' '.$fc0_sr.':00';
|
||||
$data{$type}{$name}{current}{sunriseTodayTs} = timestringToTimestamp ($date.' '.$fc0_sr.':00');
|
||||
|
||||
$data{$type}{$name}{current}{sunsetToday} = $date.' '.$fc0_ss.':00';
|
||||
$data{$type}{$name}{current}{sunsetTodayTs} = timestringToTimestamp ($date.' '.$fc0_ss.':00');
|
||||
|
||||
debugLog ($paref, 'collectData', "sunrise/sunset today: $fc0_sr / $fc0_ss, sunrise/sunset tomorrow: $fc1_sr / $fc1_ss");
|
||||
|
||||
storeReading ('Today_SunRise', $fc0_sr);
|
||||
storeReading ('Today_SunSet', $fc0_ss);
|
||||
storeReading ('Tomorrow_SunRise', $fc1_sr);
|
||||
storeReading ('Tomorrow_SunSet', $fc1_ss);
|
||||
|
||||
my $fc0_sr_mm = sprintf "%02d", (split ":", $fc0_sr)[0];
|
||||
my $fc0_ss_mm = sprintf "%02d", (split ":", $fc0_ss)[0];
|
||||
my $fc1_sr_mm = sprintf "%02d", (split ":", $fc1_sr)[0];
|
||||
my $fc1_ss_mm = sprintf "%02d", (split ":", $fc1_ss)[0];
|
||||
|
||||
return ($fc0_sr_mm, $fc0_ss_mm, $fc1_sr_mm, $fc1_ss_mm);
|
||||
}
|
||||
|
||||
################################################################
|
||||
@ -7516,7 +7597,6 @@ sub ___doPlanning {
|
||||
}
|
||||
|
||||
for my $ts (sort{$a<=>$b} keys %mtimes) {
|
||||
|
||||
if ($mtimes{$ts}{spexp} >= $epiece1) { # die früheste Startzeit sofern Überschuß größer als Bedarf
|
||||
my $starttime = $mtimes{$ts}{starttime};
|
||||
|
||||
@ -7540,7 +7620,7 @@ sub ___doPlanning {
|
||||
last;
|
||||
}
|
||||
else {
|
||||
$paref->{supplement} = encode('utf8', $hqtxt{emsple}{$lang}). $epiece1; # 'erwarteter max Überschuss weniger als'
|
||||
$paref->{supplement} = encode('utf8', $hqtxt{emsple}{$lang}).' '.$epiece1; # 'erwarteter max Überschuss weniger als'
|
||||
$paref->{ps} = 'suspended:';
|
||||
|
||||
___setConsumerPlanningState ($paref);
|
||||
@ -11888,27 +11968,6 @@ sub _addHourAiRawdata {
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Ist Attribut 'affectNumHistDays' gesetzt ?
|
||||
# $usenhd: 1 - ja, 0 - nein
|
||||
# $nhd : Anzahl der zu verwendenden HistDays
|
||||
################################################################
|
||||
sub __useNumHistDays {
|
||||
my $name = shift;
|
||||
|
||||
my $usenhd = 0;
|
||||
my $nhd = AttrVal($name, 'affectNumHistDays', $calcmaxd + 1);
|
||||
|
||||
if ($nhd == $calcmaxd + 1) {
|
||||
$nhd = $calcmaxd;
|
||||
}
|
||||
else {
|
||||
$usenhd = 1;
|
||||
}
|
||||
|
||||
return ($usenhd, $nhd);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Qualität der Vorhersage berechnen
|
||||
################################################################
|
||||
@ -16181,8 +16240,8 @@ to ensure that the system configuration is correct.
|
||||
|
||||
Switches the automatic prediction correction on/off.
|
||||
The mode of operation differs depending on the selected method.
|
||||
The correction behaviour can be influenced with the <a href="#SolarForecast-attr-affectNumHistDays">affectNumHistDays</a>
|
||||
and <a href="#SolarForecast-attr-affectMaxDayVariance">affectMaxDayVariance</a> attributes. <br>
|
||||
The correction behaviour can be influenced with the
|
||||
<a href="#SolarForecast-attr-affectMaxDayVariance">affectMaxDayVariance</a> attribute. <br>
|
||||
(default: off)
|
||||
|
||||
<br><br>
|
||||
@ -16716,14 +16775,6 @@ to ensure that the system configuration is correct.
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<a id="SolarForecast-attr-affectNumHistDays"></a>
|
||||
<li><b>affectNumHistDays </b><br>
|
||||
Number of historical days available in the caches to be used to calculate the PV forecast autocorrection
|
||||
values. <br>
|
||||
(default: all available data in pvHistory and pvCircular)
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<a id="SolarForecast-attr-affectSolCastPercentile"></a>
|
||||
<li><b>affectSolCastPercentile <10 | 50 | 90> </b><br>
|
||||
(only when using Model SolCastAPI) <br><br>
|
||||
@ -18258,7 +18309,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
|
||||
Schaltet die automatische Vorhersagekorrektur ein/aus.
|
||||
Die Wirkungsweise unterscheidet sich je nach gewählter Methode. <br>
|
||||
Das Korrekturverhalten kann mit den Attributen <a href="#SolarForecast-attr-affectNumHistDays">affectNumHistDays</a> und
|
||||
Das Korrekturverhalten kann mit dem Attribut
|
||||
<a href="#SolarForecast-attr-affectMaxDayVariance">affectMaxDayVariance</a> beeinflusst werden. <br>
|
||||
(default: off)
|
||||
|
||||
@ -18801,14 +18852,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<a id="SolarForecast-attr-affectNumHistDays"></a>
|
||||
<li><b>affectNumHistDays </b><br>
|
||||
Anzahl der in den Caches verfügbaren historischen Tage, die zur Berechnung der Autokorrekturwerte der
|
||||
PV Vorhersage verwendet werden sollen. <br>
|
||||
(default: alle verfügbaren Daten in pvHistory und pvCircular)
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<a id="SolarForecast-attr-affectSolCastPercentile"></a>
|
||||
<li><b>affectSolCastPercentile <10 | 50 | 90> </b><br>
|
||||
(nur bei Verwendung Model SolCastAPI) <br><br>
|
||||
|
Loading…
x
Reference in New Issue
Block a user