2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-04 05:16:45 +00:00

76_SolarForecast: contrib 1.17.2

git-svn-id: https://svn.fhem.de/fhem/trunk@28718 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2024-03-28 21:24:55 +00:00
parent da750fb7aa
commit abb44d8939

View File

@ -158,6 +158,8 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.17.2" => "28.03.2024 aiTrain: better status info, limit ctrlWeatherDev2/3 to can only use DWD Devices ".
"integrate OpenMeteoWorld-API with the 'Best match' Weather model ",
"1.17.1" => "27.03.2024 add AI to OpenMeteoDWD-API, changed AI train debuglog, new attr ctrlAIshiftTrainStart ". "1.17.1" => "27.03.2024 add AI to OpenMeteoDWD-API, changed AI train debuglog, new attr ctrlAIshiftTrainStart ".
"_specialActivities: split tasks to several time slots, bugfixes ". "_specialActivities: split tasks to several time slots, bugfixes ".
"AI: modify aiAddInstance, Customize pattern training data ". "AI: modify aiAddInstance, Customize pattern training data ".
@ -1340,6 +1342,7 @@ sub Set {
my $resets = join ",",@re; my $resets = join ",",@re;
my @fcdevs = qw( OpenMeteoDWD-API my @fcdevs = qw( OpenMeteoDWD-API
OpenMeteoWorld-API
SolCast-API SolCast-API
ForecastSolar-API ForecastSolar-API
VictronKI-API VictronKI-API
@ -1554,12 +1557,15 @@ sub _setcurrentRadiationAPI { ## no critic "not used"
return qq{The device "$prop" doesn't exist or has no TYPE "DWD_OpenData"}; return qq{The device "$prop" doesn't exist or has no TYPE "DWD_OpenData"};
} }
if ($prop ne 'OpenMeteoDWD-API' && AttrVal ($name, 'ctrlWeatherDev1', '') eq 'OpenMeteoDWD-API') { my $awdev1 = AttrVal ($name, 'ctrlWeatherDev1', '');
return "The attribute 'ctrlWeatherDev1' is set to 'OpenMeteoDWD-API'. \n".
if (($awdev1 eq 'OpenMeteoDWD-API' && $prop ne 'OpenMeteoDWD-API') ||
($awdev1 eq 'OpenMeteoWorld-API' && $prop ne 'OpenMeteoWorld-API')) {
return "The attribute 'ctrlWeatherDev1' is set to '$awdev1'. \n".
"Change that attribute to another weather device first if you want use an other API."; "Change that attribute to another weather device first if you want use an other API.";
} }
if ($prop =~ /(SolCast|OpenMeteoDWD)-API/xs) { if ($prop =~ /(SolCast|OpenMeteoDWD|OpenMeteoWorld)-API/xs) {
return "The library FHEM::Utility::CTZ is missing. Please update FHEM completely." if($ctzAbsent); return "The library FHEM::Utility::CTZ is missing. Please update FHEM completely." if($ctzAbsent);
my $rmf = reqModFail(); my $rmf = reqModFail();
@ -1574,7 +1580,7 @@ sub _setcurrentRadiationAPI { ## no critic "not used"
return if(_checkSetupNotComplete ($hash)); # keine Stringkonfiguration wenn Setup noch nicht komplett return if(_checkSetupNotComplete ($hash)); # keine Stringkonfiguration wenn Setup noch nicht komplett
if ($prop =~ /(ForecastSolar|OpenMeteoDWD)-API/xs) { if ($prop =~ /(ForecastSolar|OpenMeteoDWD|OpenMeteoWorld)-API/xs) {
my ($set, $lat, $lon, $elev) = locCoordinates(); my ($set, $lat, $lon, $elev) = locCoordinates();
return qq{set attributes 'latitude' and 'longitude' in global device first} if(!$set); return qq{set attributes 'latitude' and 'longitude' in global device first} if(!$set);
@ -2690,8 +2696,8 @@ sub _getRoofTopData {
my $ret = __getVictronSolarData ($paref); my $ret = __getVictronSolarData ($paref);
return $ret; return $ret;
} }
elsif ($hash->{MODEL} eq 'OpenMeteoDWDAPI') { elsif ($hash->{MODEL} =~ /^OpenMeteo/xs) {
my $ret = __getopenMeteoDWDdata ($paref); my $ret = __getopenMeteoData ($paref);
return $ret; return $ret;
} }
@ -4022,9 +4028,9 @@ return;
} }
################################################################################################ ################################################################################################
# Abruf Open-Meteo DWD ICON API data # Abruf Open-Meteo API Daten
################################################################################################ ################################################################################################
sub __getopenMeteoDWDdata { sub __getopenMeteoData {
my $paref = shift; my $paref = shift;
my $hash = $paref->{hash}; my $hash = $paref->{hash};
my $name = $paref->{name}; my $name = $paref->{name};
@ -4041,8 +4047,14 @@ sub __getopenMeteoDWDdata {
} }
} }
my $submodel = InternalVal ($hash->{NAME}, 'MODEL', '');
$paref->{allstrings} = ReadingsVal ($name, 'inverterStrings', ''); $paref->{allstrings} = ReadingsVal ($name, 'inverterStrings', '');
$paref->{submodel} = $paref->{arg} ? $paref->{arg} : 'DWD ICON Seamless'; $paref->{submodel} = $submodel eq 'OpenMeteoDWDAPI' ? 'DWD ICON Seamless' :
$submodel eq 'OpenMeteoWorldAPI' ? 'World Best Match' :
'unknown';
return "The Weather Model '$submodel' is not a valid Open-Meteo Weather Model" if($paref->{submodel} eq 'unknown');
$paref->{begin} = 1; $paref->{begin} = 1;
__openMeteoDWD_ApiRequest ($paref); __openMeteoDWD_ApiRequest ($paref);
@ -4085,7 +4097,7 @@ sub __openMeteoDWD_ApiRequest {
my $submodel = $paref->{submodel}; # abzufragendes Wettermodell my $submodel = $paref->{submodel}; # abzufragendes Wettermodell
if (!$allstrings) { # alle Strings wurden abgerufen if (!$allstrings) { # alle Strings wurden abgerufen
writeCacheToFile ($hash, 'solcastapi', $scpicache.$name); # Cache File API Werte schreiben writeCacheToFile ($hash, 'solcastapi', $scpicache.$name);
readingsSingleUpdate ($hash, 'nextRadiationAPICall', $hqtxt{after}{$lang}.' '.(timestampToTimestring ($t + $ometeorepdef, $lang))[0], 1); readingsSingleUpdate ($hash, 'nextRadiationAPICall', $hqtxt{after}{$lang}.' '.(timestampToTimestring ($t + $ometeorepdef, $lang))[0], 1);
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIcalls} += 1; $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIcalls} += 1;
return; return;
@ -4093,7 +4105,6 @@ sub __openMeteoDWD_ApiRequest {
my $string; my $string;
($string, $allstrings) = split ",", $allstrings, 2; ($string, $allstrings) = split ",", $allstrings, 2;
my ($set, $lat, $lon, $elev) = locCoordinates(); my ($set, $lat, $lon, $elev) = locCoordinates();
if (!$set) { if (!$set) {
@ -4105,11 +4116,9 @@ sub __openMeteoDWD_ApiRequest {
my $tilt = StringVal ($hash, $string, 'tilt', '<unknown>'); my $tilt = StringVal ($hash, $string, 'tilt', '<unknown>');
my $az = StringVal ($hash, $string, 'azimut', '<unknown>'); my $az = StringVal ($hash, $string, 'azimut', '<unknown>');
#my $url = "https://api.open-meteo.com/v1/dwd-icon?".
my $url = "https://api.open-meteo.com/v1/forecast?"; my $url = "https://api.open-meteo.com/v1/forecast?";
$url .= "models=icon_seamless" if($submodel eq 'DWD ICON Seamless'); $url .= "models=icon_seamless" if($submodel eq 'DWD ICON Seamless');
$url .= "models=best_match" if($submodel eq 'Best Match'); $url .= "models=best_match" if($submodel eq 'World Best Match');
$url .= "&latitude=".$lat. $url .= "&latitude=".$lat.
"&longitude=".$lon. "&longitude=".$lon.
"&hourly=temperature_2m,rain,weather_code,cloud_cover,is_day,global_tilted_irradiance_instant". "&hourly=temperature_2m,rain,weather_code,cloud_cover,is_day,global_tilted_irradiance_instant".
@ -4121,7 +4130,7 @@ sub __openMeteoDWD_ApiRequest {
"&tilt=".$tilt. "&tilt=".$tilt.
"&azimuth=".$az; "&azimuth=".$az;
debugLog ($paref, 'apiCall', qq{Open-Meteo DWD ICON API Call - Request for PV-String "$string" with weather model >$submodel<:\n$url}); debugLog ($paref, 'apiCall', qq{Open-Meteo API Call - Request for PV-String "$string" with Weather Model >$submodel<:\n$url});
my $caller = (caller(0))[3]; # Rücksprungmarke my $caller = (caller(0))[3]; # Rücksprungmarke
@ -4226,7 +4235,7 @@ sub __openMeteoDWD_ApiResponse {
my $rt = (timestampToTimestring ($t, $lang))[3]; my $rt = (timestampToTimestring ($t, $lang))[3];
my $jdata = decode_json ($myjson); my $jdata = decode_json ($myjson);
# debugLog ($paref, 'apiProcess', qq{Open-Meteo DWD ICON API Call - response for string "$string":\n}. Dumper $jdata); # debugLog ($paref, 'apiProcess', qq{Open-Meteo API Call - response for string "$string":\n}. Dumper $jdata);
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{lastretrieval_time} = $rt; # letzte Abrufzeit $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{lastretrieval_time} = $rt; # letzte Abrufzeit
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{lastretrieval_timestamp} = $t; # letzter Abrufzeitstempel $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{lastretrieval_timestamp} = $t; # letzter Abrufzeitstempel
@ -4254,9 +4263,9 @@ sub __openMeteoDWD_ApiResponse {
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{response_message} = 'success'; $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{response_message} = 'success';
if ($debug =~ /apiCall/xs) { if ($debug =~ /apiCall/xs) {
Log3 ($name, 1, qq{$name DEBUG> Open-Meteo DWD ICON API Call - server response for PV string "$string"}); Log3 ($name, 1, qq{$name DEBUG> Open-Meteo API Call - server response for PV string "$string"});
Log3 ($name, 1, "$name DEBUG> Open-Meteo DWD ICON API Call - request time: ".$rt." ($t)"); Log3 ($name, 1, "$name DEBUG> Open-Meteo API Call - request time: ".$rt." ($t)");
Log3 ($name, 1, "$name DEBUG> Open-Meteo DWD ICON API Call - status: success"); Log3 ($name, 1, "$name DEBUG> Open-Meteo API Call - status: success");
} }
my $date = strftime "%Y-%m-%d", localtime(time); my $date = strftime "%Y-%m-%d", localtime(time);
@ -5493,16 +5502,17 @@ sub _attrWeatherDev { ## no critic "not used"
return if(!$init_done); return if(!$init_done);
if ($paref->{cmd} eq 'set' ) { if ($paref->{cmd} eq 'set' ) {
if ($aVal ne 'OpenMeteoDWD-API' && (!$defs{$aVal} || $defs{$aVal}{TYPE} ne "DWD_OpenData")) { if ($aVal !~ /^OpenMeteo/xs && (!$defs{$aVal} || $defs{$aVal}{TYPE} ne "DWD_OpenData")) {
return qq{The device "$aVal" doesn't exist or has no TYPE 'DWD_OpenData'}; return qq{The device "$aVal" doesn't exist or has no TYPE 'DWD_OpenData'};
} }
if ($aVal eq 'OpenMeteoDWD-API') { if ($aVal =~ /^OpenMeteo/xs) {
if ($aName ne 'ctrlWeatherDev1') { if ($aName ne 'ctrlWeatherDev1') {
return qq{Only the leading attribute 'ctrlWeatherDev1' can set to 'OpenMeteoDWD-API'}; return qq{Only the leading attribute 'ctrlWeatherDev1' can set to '$aVal'};
} }
CommandSet (undef,"$name currentRadiationAPI $aVal"); # automatisch currentRadiationAPI setzen #CommandSet (undef, "$name currentRadiationAPI $aVal"); # automatisch currentRadiationAPI setzen wenn ctrlWeatherDev1
InternalTimer (gettimeofday()+1, 'FHEM::SolarForecast::__setRadAPIdelayed', $hash, 0); # automatisch currentRadiationAPI setzen wenn ctrlWeatherDev1
return; return;
} }
@ -5515,6 +5525,20 @@ sub _attrWeatherDev { ## no critic "not used"
return; return;
} }
################################################################
# currentRadiationAPI verzögert aus Attr setzen
################################################################
sub __setRadAPIdelayed {
my $hash = shift;
my $name = $hash->{NAME};
my $awdev1 = AttrVal ($name, 'ctrlWeatherDev1', '');
CommandSet (undef, "$name currentRadiationAPI $awdev1"); # automatisch currentRadiationAPI setzen
return;
}
################################################################################### ###################################################################################
# Eventverarbeitung # Eventverarbeitung
# - Aktualisierung Consumerstatus bei asynchronen Consumern # - Aktualisierung Consumerstatus bei asynchronen Consumern
@ -6081,10 +6105,12 @@ sub _addDynAttr {
my $atd = 'ctrlWeatherDev'; my $atd = 'ctrlWeatherDev';
@deva = grep {!/$atd/} @deva; @deva = grep {!/$atd/} @deva;
#push @deva, ($adwds ? "ctrlWeatherDev1:$adwds " : "ctrlWeatherDev1:noArg");
for my $step (1..$weatherDevMax) { for my $step (1..$weatherDevMax) {
push @deva, ($adwds ? "ctrlWeatherDev".$step.":OpenMeteoDWD-API,$adwds " : "ctrlWeatherDev1:OpenMeteoDWD-API"); if ($step == 1) {
push @deva, ($adwds ? "ctrlWeatherDev".$step.":OpenMeteoDWD-API,OpenMeteoWorld-API,$adwds" : "ctrlWeatherDev1:OpenMeteoDWD-API,OpenMeteoWorld-API");
next;
}
push @deva, ($adwds ? "ctrlWeatherDev".$step.":$adwds" : "ctrlWeatherDev1");
} }
$hash->{".AttrList"} = join " ", @deva; $hash->{".AttrList"} = join " ", @deva;
@ -6602,7 +6628,7 @@ sub _specialActivities {
## Task 4 ## Task 4
########### ###########
if ($chour == 1 && $minute >= 9) { if ($chour == 0 && $minute >= 9) {
if (!defined $hash->{HELPER}{T4RUN}) { if (!defined $hash->{HELPER}{T4RUN}) {
$hash->{HELPER}{T4RUN} = 1; $hash->{HELPER}{T4RUN} = 1;
@ -13579,6 +13605,7 @@ sub finishTrain {
$data{$type}{$name}{current}{aiAddedToTrain} = 0; $data{$type}{$name}{current}{aiAddedToTrain} = 0;
$data{$type}{$name}{current}{aicanuse} = $aicanuse if(defined $aicanuse); $data{$type}{$name}{current}{aicanuse} = $aicanuse if(defined $aicanuse);
$data{$type}{$name}{current}{aiinitstate} = $aiinitstate if(defined $aiinitstate); $data{$type}{$name}{current}{aiinitstate} = $aiinitstate if(defined $aiinitstate);
$data{$type}{$name}{current}{aitrainstate} = $aitrainstate if(defined $aitrainstate);
$data{$type}{$name}{circular}{99}{runTimeTrainAI} = $runTimeTrainAI if(defined $runTimeTrainAI); # !! in Circular speichern um zu persistieren, setTimeTracking speichert zunächst in Current !! $data{$type}{$name}{circular}{99}{runTimeTrainAI} = $runTimeTrainAI if(defined $runTimeTrainAI); # !! in Circular speichern um zu persistieren, setTimeTracking speichert zunächst in Current !!
if ($aitrainstate eq 'ok') { if ($aitrainstate eq 'ok') {
@ -13593,6 +13620,7 @@ sub finishTrain {
} }
$paref->{debug} = getDebug ($hash); $paref->{debug} = getDebug ($hash);
if (defined $hash->{HELPER}{AIBLOCKRUNNING}) { if (defined $hash->{HELPER}{AIBLOCKRUNNING}) {
debugLog ($paref, 'aiProcess', qq{AI Training BlockingCall PID "$hash->{HELPER}{AIBLOCKRUNNING}{pid}" finished}); debugLog ($paref, 'aiProcess', qq{AI Training BlockingCall PID "$hash->{HELPER}{AIBLOCKRUNNING}{pid}" finished});
delete($hash->{HELPER}{AIBLOCKRUNNING}); delete($hash->{HELPER}{AIBLOCKRUNNING});
@ -13711,7 +13739,11 @@ sub aiTrain { ## no critic "not used"
my $dtree = AiDetreeVal ($hash, 'object', undef); my $dtree = AiDetreeVal ($hash, 'object', undef);
if (!$dtree) { if (!$dtree) {
$serial = encode_base64 (Serialize ( {name => $name, aiinitstate => 'no AI::DecisionTree object present'} ), ""); $serial = encode_base64 (Serialize ( {name => $name,
aitrainstate => "Train: not performed (see 'get $name valCurrent' -> aiinitstate for further info)",
aiinitstate => 'Init: no AI::DecisionTree object present'
}
), "");
$block ? return ($serial) : return \&finishTrain ($serial); $block ? return ($serial) : return \&finishTrain ($serial);
} }
@ -13719,8 +13751,12 @@ sub aiTrain { ## no critic "not used"
1; 1;
} }
or do { Log3 ($name, 1, "$name - aiTrain ERROR: $@"); or do { Log3 ($name, 1, "$name - aiTrain ERROR: $@");
$data{$type}{$name}{current}{aitrainstate} = $@; #$data{$type}{$name}{current}{aitrainstate} = $@;
$serial = encode_base64 (Serialize ( {name => $name, aitrainstate => $@} ), ""); $err = (split / at/, $@)[0];
$serial = encode_base64 (Serialize ( {name => $name,
aitrainstate => "Train: $err"
}
), "");
$block ? return ($serial) : return \&finishTrain ($serial); $block ? return ($serial) : return \&finishTrain ($serial);
}; };
@ -15647,6 +15683,9 @@ sub setModel {
elsif ($api =~ /OpenMeteoDWD/xs) { elsif ($api =~ /OpenMeteoDWD/xs) {
$hash->{MODEL} = 'OpenMeteoDWDAPI'; $hash->{MODEL} = 'OpenMeteoDWDAPI';
} }
elsif ($api =~ /OpenMeteoWorld/xs) {
$hash->{MODEL} = 'OpenMeteoWorldAPI';
}
else { else {
$hash->{MODEL} = 'DWD'; $hash->{MODEL} = 'DWD';
} }
@ -16119,7 +16158,7 @@ sub isDWDUsed {
my $ret = 0; my $ret = 0;
if ($hash->{MODEL} && $hash->{MODEL} eq 'DWD') { if (InternalVal ($hash->{NAME}, 'MODEL', '') eq 'DWD') {
$ret = 1; $ret = 1;
} }
@ -16134,7 +16173,7 @@ sub isSolCastUsed {
my $ret = 0; my $ret = 0;
if ($hash->{MODEL} && $hash->{MODEL} eq 'SolCastAPI') { if (InternalVal ($hash->{NAME}, 'MODEL', '') eq 'SolCastAPI') {
$ret = 1; $ret = 1;
} }
@ -16149,7 +16188,7 @@ sub isForecastSolarUsed {
my $ret = 0; my $ret = 0;
if ($hash->{MODEL} && $hash->{MODEL} eq 'ForecastSolarAPI') { if (InternalVal ($hash->{NAME}, 'MODEL', '') eq 'ForecastSolarAPI') {
$ret = 1; $ret = 1;
} }
@ -16164,7 +16203,7 @@ sub isVictronKiUsed {
my $ret = 0; my $ret = 0;
if ($hash->{MODEL} && $hash->{MODEL} eq 'VictronKiAPI') { if (InternalVal ($hash->{NAME}, 'MODEL', '') eq 'VictronKiAPI') {
$ret = 1; $ret = 1;
} }
@ -16179,7 +16218,7 @@ sub isOpenMeteoUsed {
my $ret = 0; my $ret = 0;
if ($hash->{MODEL} && $hash->{MODEL} eq 'OpenMeteoDWDAPI') { if (InternalVal ($hash->{NAME}, 'MODEL', '') =~ /^OpenMeteo/xs) {
$ret = 1; $ret = 1;
} }
@ -16254,9 +16293,9 @@ sub isWeatherDevValid {
if ($fcname) { $valid = 1 } if ($fcname) { $valid = 1 }
if (!$defs{$fcname} || $defs{$fcname}{TYPE} ne "DWD_OpenData") { $valid = '' } if (!$defs{$fcname} || $defs{$fcname}{TYPE} ne "DWD_OpenData") { $valid = '' }
if (isOpenMeteoUsed($hash) && $fcname =~ /OpenMeteoDWD-API/xs) { if (isOpenMeteoUsed($hash) && $fcname =~ /^OpenMeteo/xs) {
$valid = 1; $valid = 1;
$apiu = 'OpenMeteoDWD-API'; $apiu = $fcname;
} }
return ($valid, $fcname, $apiu); return ($valid, $fcname, $apiu);
@ -17735,12 +17774,22 @@ to ensure that the system configuration is correct.
This API provides access to the renowned ICON weather models of the German Weather Service (DWD), which provide This API provides access to the renowned ICON weather models of the German Weather Service (DWD), which provide
15-minute data for short-term forecasts in Central Europe and global forecasts with a resolution of 11 km. 15-minute data for short-term forecasts in Central Europe and global forecasts with a resolution of 11 km.
The ICON model is a preferred choice for general weather forecast APIs when no other high-resolution weather The ICON model is a preferred choice for general weather forecast APIs when no other high-resolution weather
models are available. models are available. The models DWD Icon D2, DWD Icon EU and DWD Icon Global models are merged into a
seamless forecast.
The comprehensive and clearly laid out The comprehensive and clearly laid out
<a href='https://open-meteo.com/en/docs/dwd-api' target='_blank'>API Documentation</a> is available on <a href='https://open-meteo.com/en/docs/dwd-api' target='_blank'>API Documentation</a> is available on
the service's website. the service's website.
<br><br> <br><br>
<b>OpenMeteoWorld-API</b> <br>
As a variant of the Open Meteo service, the OpenMeteoWorld API provides the optimum forecast for a specific location worldwide.
The OpenMeteoWorld API seamlessly combines ensemble models from well-known organizations such as NOAA (National Oceanic and Atmospheric
Administration), DWD (German Weather Service), CMCC (Canadian) and ECMWF (European Centre for Medium-Range Weather Forecasts).
The best models are combined for each location worldwide to produce the best possible forecast.
The weather models are selected automatically based on the location coordinates contained in the API call.
<br><br>
<b>SolCast-API</b> <br> <b>SolCast-API</b> <br>
API usage requires one or more API-keys (accounts) and one or more Rooftop-ID's in advance API usage requires one or more API-keys (accounts) and one or more Rooftop-ID's in advance
@ -19106,7 +19155,7 @@ to ensure that the system configuration is correct.
Specifies the device or API that provides the required weather data (cloud cover, precipitation, etc.).<br> Specifies the device or API that provides the required weather data (cloud cover, precipitation, etc.).<br>
The attribute 'ctrlWeatherDev1' specifies the leading weather service and is mandatory.<br> The attribute 'ctrlWeatherDev1' specifies the leading weather service and is mandatory.<br>
If 'OpenMeteoDWD-API' is selected in the 'ctrlWeatherDev1' attribute, the Open-Meteo service is automatically set as the If an Open-Mete API is selected in the 'ctrlWeatherDev1' attribute, the Open-Meteo service is automatically set as the
source of the radiation data (setter currentRadiationAPI). <br> source of the radiation data (setter currentRadiationAPI). <br>
If an FHEM device is to be used to supply the weather data, it must be of type 'DWD_OpenData'.<br> If an FHEM device is to be used to supply the weather data, it must be of type 'DWD_OpenData'.<br>
If no device of this type exists, at least one DWD_OpenData device must first be defined. If no device of this type exists, at least one DWD_OpenData device must first be defined.
@ -19888,8 +19937,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Legt die Quelle zur Lieferung der solaren Strahlungsdaten fest. Es kann ein Device vom Typ DWD_OpenData oder Legt die Quelle zur Lieferung der solaren Strahlungsdaten fest. Es kann ein Device vom Typ DWD_OpenData oder
eine implementierte API eines Dienstes ausgewählt werden. <br> eine implementierte API eines Dienstes ausgewählt werden. <br>
<b>Hinweis:</b> Ist OpenMeteoDWD-API im Attribut 'ctrlWeatherDev1' gesetzt, kann kein anderer Strahlungsdatendienst als <b>Hinweis:</b> Ist eine OpenMeteo API im Attribut 'ctrlWeatherDev1' gesetzt, kann kein anderer Strahlungsdatendienst als
OpenMeteoDWD-API ausgewählt werden. <br><br> diese OpenMeteo API ausgewählt werden. <br><br>
<b>OpenMeteoDWD-API</b> <br> <b>OpenMeteoDWD-API</b> <br>
@ -19900,11 +19949,21 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Diese API bietet Zugang zu den renommierten ICON-Wettermodellen des Deutschen Wetterdienstes (DWD), die Diese API bietet Zugang zu den renommierten ICON-Wettermodellen des Deutschen Wetterdienstes (DWD), die
15-minütige Daten für kurzfristige Vorhersagen in Mitteleuropa und globale Vorhersagen mit einer Auflösung 15-minütige Daten für kurzfristige Vorhersagen in Mitteleuropa und globale Vorhersagen mit einer Auflösung
von 11 km liefern. Das ICON-Modell ist eine bevorzugte Wahl für allgemeine Wettervorhersage-APIs, wenn keine von 11 km liefern. Das ICON-Modell ist eine bevorzugte Wahl für allgemeine Wettervorhersage-APIs, wenn keine
anderen hochauflösenden Wettermodelle verfügbar sind. anderen hochauflösenden Wettermodelle verfügbar sind. Es werden die Modelle DWD Icon D2, DWD Icon EU
und DWD Icon Global zu einer nahtlosen Vorhersage zusammengeführt.
Auf der Webseite des Dienstes ist die umfangreiche und übersichtliche Auf der Webseite des Dienstes ist die umfangreiche und übersichtliche
<a href='https://open-meteo.com/en/docs/dwd-api' target='_blank'>API Dokumentation</a> verfügbar. <a href='https://open-meteo.com/en/docs/dwd-api' target='_blank'>API Dokumentation</a> verfügbar.
<br><br> <br><br>
<b>OpenMeteoWorld-API</b> <br>
Als Variante des Open-Meteo Dienstes liefert die OpenMeteoWorld-API die optimale Vorhersage für einen bestimmten Ort weltweit.
Die OpenMeteoWorld-API vereint nahtlos Ensemblemodelle bekannter Organisationen wie NOAA (National Oceanic and Atmospheric
Administration), DWD (Deutscher Wetterdienst), CMCC (Canadian) und ECMWF (Europäisches Zentrum für mittelfristige Wettervorhersage).
Für jeden Ort weltweit werden die besten Modelle kombiniert, um die bestmögliche Vorhersage zu erstellen.
Die Auswahl der Wettermodelle erfolgt automatisch anhand der im API Aufruf enthalteten Standortkoordinaten.
<br><br>
<b>SolCast-API</b> <br> <b>SolCast-API</b> <br>
Die API-Nutzung benötigt vorab ein oder mehrere API-keys (Accounts) sowie ein oder mehrere Rooftop-ID's Die API-Nutzung benötigt vorab ein oder mehrere API-keys (Accounts) sowie ein oder mehrere Rooftop-ID's
@ -21282,7 +21341,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Gibt das Gerät oder die API an, das/die die erforderlichen Wetterdaten (Wolkendecke, Niederschlag usw.) liefert.<br> Gibt das Gerät oder die API an, das/die die erforderlichen Wetterdaten (Wolkendecke, Niederschlag usw.) liefert.<br>
Das Attribut 'ctrlWeatherDev1' gibt den führenden Wetterdienst an und ist zwingend erforderlich.<br> Das Attribut 'ctrlWeatherDev1' gibt den führenden Wetterdienst an und ist zwingend erforderlich.<br>
Wird 'OpenMeteoDWD-API' im Attribut 'ctrlWeatherDev1' ausgewählt, wird der Dienst Open-Meteo automatisch auch als Quelle Wird eine Open-Mete API im Attribut 'ctrlWeatherDev1' ausgewählt, wird der Dienst Open-Meteo automatisch auch als Quelle
der Strahlungsdaten (Setter currentRadiationAPI) eingestellt. <br> der Strahlungsdaten (Setter currentRadiationAPI) eingestellt. <br>
Soll ein FHEM Gerät zur Lieferung der Wetterdaten dienen, muß es vom Typ 'DWD_OpenData' sein.<br> Soll ein FHEM Gerät zur Lieferung der Wetterdaten dienen, muß es vom Typ 'DWD_OpenData' sein.<br>
Ist noch kein Gerät dieses Typs vorhanden, muß zunächst mindestens ein DWD_OpenData-Gerät Ist noch kein Gerät dieses Typs vorhanden, muß zunächst mindestens ein DWD_OpenData-Gerät