From 37c33097162655588d70407f2fcfd3e63363f313 Mon Sep 17 00:00:00 2001 From: nasseeder1 Date: Tue, 11 Jun 2024 19:54:23 +0000 Subject: [PATCH] 76_SolarForecast: set currentRadiationAPI to attr setupRadiationAPI git-svn-id: https://svn.fhem.de/fhem/trunk@28963 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 2 + fhem/FHEM/76_SolarForecast.pm | 634 ++++++++++---------- fhem/contrib/DS_Starter/76_SolarForecast.pm | 634 ++++++++++---------- 3 files changed, 652 insertions(+), 618 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 00eeab88d..2e2dcc403 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # 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: set currentRadiationAPI to attr setupRadiationAPI + !NOTE! save FHEM config after restart - feature: 74_AutomowerConnect: new events for errors related to the APIs - bugfix: 76_SolarForecast: Illegal division by zero - bufgix: 32_withings: improved token refresh timing diff --git a/fhem/FHEM/76_SolarForecast.pm b/fhem/FHEM/76_SolarForecast.pm index 21b554907..9d5c939a8 100644 --- a/fhem/FHEM/76_SolarForecast.pm +++ b/fhem/FHEM/76_SolarForecast.pm @@ -157,6 +157,8 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "1.26.0" => "10.06.2024 transformed setter currentRadiationAPI to attr setupRadiationAPI ", + "1.25.2" => "09.06.2024 _specialActivities: change delete readings exec ", "1.25.1" => "08.06.2024 Illegal division by zero Forum:https://forum.fhem.de/index.php?msg=1314730 ", "1.25.0" => "05.06.2024 transformed setter inverterStrings to attr setupInverterStrings, calcTodayPVdeviation: fix continuously calc again ", "1.24.0" => "03.06.2024 transformed setter currentInverterDev to attr setupInverterDev, calcTodayPVdeviation: fix continuously calc ", @@ -496,7 +498,6 @@ my @fs = qw( ftui_forecast.css ); # Anlagenkonfiguration: maßgebliche Readings my @rconfigs = qw( pvCorrectionFactor_Auto - currentRadiationAPI moduleAzimuth modulePeakString moduleDeclination @@ -526,7 +527,7 @@ my @aconfigs = qw( affect70percentRule affectBatteryPreferredCharge affectConsFo graphicHeaderDetail graphicHeaderShow graphicHistoryHour graphicHourCount graphicHourStyle graphicLayoutType graphicSelect graphicShowDiff graphicShowNight graphicShowWeather graphicSpaceSize graphicStartHtml graphicEndHtml graphicWeatherColor graphicWeatherColorNight - setupMeterDev setupBatteryDev setupInverterDev setupInverterStrings + setupMeterDev setupBatteryDev setupInverterDev setupInverterStrings setupRadiationAPI ); for my $cinit (1..$maxconsumer) { @@ -542,8 +543,7 @@ my $allwidgets = 'icon|sortable|uzsu|knob|noArg|time|text|slider|multiple|select my %hset = ( # Hash der Set-Funktion consumerImmediatePlanning => { fn => \&_setconsumerImmediatePlanning }, - consumerNewPlanning => { fn => \&_setconsumerNewPlanning }, - currentRadiationAPI => { fn => \&_setcurrentRadiationAPI }, + consumerNewPlanning => { fn => \&_setconsumerNewPlanning }, modulePeakString => { fn => \&_setmodulePeakString }, clientAction => { fn => \&_setclientAction }, energyH4Trigger => { fn => \&_setTrigger }, @@ -609,6 +609,7 @@ my %hattr = ( # H setupBatteryDev => { fn => \&_attrBatteryDev }, setupInverterDev => { fn => \&_attrInverterDev }, setupInverterStrings => { fn => \&_attrInverterStrings }, + setupRadiationAPI => { fn => \&_attrRadiationAPI }, ); my %htr = ( # Hash even/odd für @@ -653,8 +654,8 @@ my %hqtxt = ( (Die Anzeigesprache kann mit dem Attribut "ctrlLanguage" umgestellt werden.)

} }, cfd => { EN => qq{Please enter at least one weather forecast device with "attr LINK ctrlWeatherDev1"}, DE => qq{Bitte geben sie mindestens ein Wettervorhersage Device mit "attr LINK ctrlWeatherDev1" an} }, - crd => { EN => qq{Please select the radiation forecast service with "set LINK currentRadiationAPI"}, - DE => qq{Bitte geben sie den Strahlungsvorhersage Dienst mit "set LINK currentRadiationAPI" an} }, + crd => { EN => qq{Please select the radiation forecast service with "attr LINK setupRadiationAPI"}, + DE => qq{Bitte geben sie den Strahlungsvorhersage Dienst mit "attr LINK setupRadiationAPI" an} }, cid => { EN => qq{Please specify the Inverter device with "attr LINK setupInverterDev"}, DE => qq{Bitte geben sie das Wechselrichter Device mit "attr LINK setupInverterDev" an} }, mid => { EN => qq{Please specify the device for energy measurement with "attr LINK setupMeterDev"}, @@ -1221,6 +1222,7 @@ sub Initialize { "setupInverterStrings ". "setupMeterDev:textField-long ". "setupBatteryDev:textField-long ". + "setupRadiationAPI ". $consumer. $readingFnAttributes; @@ -1468,7 +1470,6 @@ sub Set { $setlist = "Unknown argument $opt, choose one of ". "consumerImmediatePlanning:$coms ". "consumerNewPlanning:$coms ". - "currentRadiationAPI:$rdd ". "energyH4Trigger:textField-long ". "modulePeakString ". "operatingMemory:backup,save".$rf." ". @@ -1627,60 +1628,6 @@ sub _setconsumerNewPlanning { ## no critic "not used" return; } -################################################################ -# Setter currentRadiationAPI -################################################################ -sub _setcurrentRadiationAPI { ## no critic "not used" - my $paref = shift; - my $hash = $paref->{hash}; - my $name = $paref->{name}; - my $prop = $paref->{prop} // return qq{no radiation device specified}; - - if ($prop !~ /-API$/x && (!$defs{$prop} || $defs{$prop}{TYPE} ne "DWD_OpenData")) { - return qq{The device "$prop" doesn't exist or has no TYPE "DWD_OpenData"}; - } - - my $awdev1 = AttrVal ($name, 'ctrlWeatherDev1', ''); - - if (($awdev1 eq 'OpenMeteoDWD-API' && $prop ne 'OpenMeteoDWD-API') || - ($awdev1 eq 'OpenMeteoDWDEnsemble-API' && $prop ne 'OpenMeteoDWDEnsemble-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."; - } - - if ($prop =~ /(SolCast|OpenMeteoDWD|OpenMeteoDWDEnsemble|OpenMeteoWorld)-API/xs) { - return "The library FHEM::Utility::CTZ is missing. Please update FHEM completely." if($ctzAbsent); - - my $rmf = reqModFail(); - return "You have to install the required perl module: ".$rmf if($rmf); - } - - readingsSingleUpdate ($hash, "currentRadiationAPI", $prop, 1); - createAssociatedWith ($hash); - writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); # Anlagenkonfiguration File schreiben - setModel ($hash); # Model setzen - deleteReadingspec ($hash, 'nextRadiationAPICall'); - - return if(_checkSetupNotComplete ($hash)); # keine Stringkonfiguration wenn Setup noch nicht komplett - - if ($prop =~ /(ForecastSolar|OpenMeteoDWD|OpenMeteoDWDEnsemble|OpenMeteoWorld)-API/xs) { - my ($set, $lat, $lon, $elev) = locCoordinates(); - return qq{set attributes 'latitude' and 'longitude' in global device first} if(!$set); - - my $tilt = ReadingsVal ($name, 'moduleDeclination', ''); # Modul Neigungswinkel für jeden Stringbezeichner - return qq{Please complete command "set $name moduleDeclination".} if(!$tilt); - - my $dir = ReadingsVal ($name, 'moduleAzimuth', ''); # Modul Ausrichtung für jeden Stringbezeichner - return qq{Please complete command "set $name moduleAzimuth".} if(!$dir); - } - - my $type = $hash->{TYPE}; - $data{$type}{$name}{current}{allStringsFullfilled} = 0; # Stringkonfiguration neu prüfen lassen - -return; -} - ################################################################ # Setter roofIdentPair ################################################################ @@ -2049,7 +1996,7 @@ sub _setpvCorrectionFactor { ## no critic "not used" my $opt = $paref->{opt}; my $prop = $paref->{prop} // return qq{no correction value specified}; - if($prop !~ /[0-9,.]/x) { + if ($prop !~ /[0-9,.]/x) { return qq{The correction value must be specified by numbers and optionally with decimal places}; } @@ -2058,7 +2005,7 @@ sub _setpvCorrectionFactor { ## no critic "not used" readingsSingleUpdate($hash, $opt, $prop." (manual)", 1); my $cfnum = (split "_", $opt)[1]; - deleteReadingspec ($hash, "pvCorrectionFactor_${cfnum}_autocalc"); + readingsDelete ($hash, "pvCorrectionFactor_${cfnum}_autocalc"); centralTask ($hash, 0); @@ -2265,8 +2212,8 @@ sub _setreset { ## no critic "not used" } if ($prop eq 'moduleRoofTopSet') { - deleteReadingspec ($hash, "moduleRoofTops"); - writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); + readingsDelete ($hash, "moduleRoofTops"); + writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); return; } @@ -3411,7 +3358,7 @@ sub __getDWDSolarData { my $type = $hash->{TYPE}; - my $raname = ReadingsVal ($name, "currentRadiationAPI", ""); # Radiation Forecast API + my $raname = AttrVal ($name, 'setupRadiationAPI', ''); # Radiation Forecast API return if(!$raname || !$defs{$raname}); my $stime = $date.' 00:00:00'; # Startzeit Soll Übernahmedaten @@ -5204,7 +5151,7 @@ sub Attr { if ($aName eq 'ctrlGenPVdeviation' && $aVal eq 'daily') { my $type = $hash->{TYPE}; - deleteReadingspec ($hash, 'Today_PVdeviation'); + readingsDelete ($hash, 'Today_PVdeviation'); delete $data{$type}{$name}{circular}{99}{tdayDvtn}; } @@ -5681,8 +5628,7 @@ sub _attrWeatherDev { ## no critic "not used" return qq{Only the leading attribute 'ctrlWeatherDev1' can set to '$aVal'}; } - #CommandSet (undef, "$name currentRadiationAPI $aVal"); # automatisch currentRadiationAPI setzen wenn ctrlWeatherDev1 - InternalTimer (gettimeofday()+1, 'FHEM::SolarForecast::__setRadAPIdelayed', $hash, 0); # automatisch currentRadiationAPI setzen wenn ctrlWeatherDev1 + InternalTimer (gettimeofday()+1, 'FHEM::SolarForecast::__setRadAPIdelayed', $hash, 0); # automatisch setupRadiationAPI setzen wenn ctrlWeatherDev1 return; } @@ -5695,6 +5641,65 @@ sub _attrWeatherDev { ## no critic "not used" return; } +################################################################ +# Attr setupRadiationAPI +################################################################ +sub _attrRadiationAPI { ## no critic "not used" + my $paref = shift; + my $hash = $paref->{hash}; + my $name = $paref->{name}; + my $aVal = $paref->{aVal}; + my $aName = $paref->{aName}; + my $type = $paref->{type}; + + return if(!$init_done); + + if ($paref->{cmd} eq 'set') { + if ($aVal !~ /-API$/x && (!$defs{$aVal} || $defs{$aVal}{TYPE} ne "DWD_OpenData")) { + return qq{The device "$aVal" doesn't exist or has no TYPE "DWD_OpenData"}; + } + + my $awdev1 = AttrVal ($name, 'ctrlWeatherDev1', ''); + + if (($awdev1 eq 'OpenMeteoDWD-API' && $aVal ne 'OpenMeteoDWD-API') || + ($awdev1 eq 'OpenMeteoDWDEnsemble-API' && $aVal ne 'OpenMeteoDWDEnsemble-API') || + ($awdev1 eq 'OpenMeteoWorld-API' && $aVal 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."; + } + + if ($aVal =~ /(SolCast|OpenMeteoDWD|OpenMeteoDWDEnsemble|OpenMeteoWorld)-API/xs) { + return "The library FHEM::Utility::CTZ is missing. Please update FHEM completely." if($ctzAbsent); + + my $rmf = reqModFail(); + return "You have to install the required perl module: ".$rmf if($rmf); + } + + return if(_checkSetupNotComplete ($hash)); # keine Stringkonfiguration wenn Setup noch nicht komplett + + if ($aVal =~ /(ForecastSolar|OpenMeteoDWD|OpenMeteoDWDEnsemble|OpenMeteoWorld)-API/xs) { + my ($set, $lat, $lon, $elev) = locCoordinates(); + return qq{set attributes 'latitude' and 'longitude' in global device first} if(!$set); + + my $tilt = ReadingsVal ($name, 'moduleDeclination', ''); # Modul Neigungswinkel für jeden Stringbezeichner + return qq{Please complete command "set $name moduleDeclination".} if(!$tilt); + + my $dir = ReadingsVal ($name, 'moduleAzimuth', ''); # Modul Ausrichtung für jeden Stringbezeichner + return qq{Please complete command "set $name moduleAzimuth".} if(!$dir); + } + + $data{$type}{$name}{current}{allStringsFullfilled} = 0; # Stringkonfiguration neu prüfen lassen + } + + readingsDelete ($hash, 'nextRadiationAPICall'); + + InternalTimer (gettimeofday() + 1, 'FHEM::SolarForecast::setModel', $hash, 0); # Model setzen + InternalTimer (gettimeofday() + 2, 'FHEM::SolarForecast::createAssociatedWith', $hash, 0); + InternalTimer (gettimeofday() + 3, 'FHEM::SolarForecast::writeCacheToFile', [$name, 'plantconfig', $plantcfg.$name], 0); # Anlagenkonfiguration File schreiben + +return; +} + ################################################################ # Attr graphicBeamXContent ################################################################ @@ -5723,7 +5728,7 @@ return; } ################################################################ -# currentRadiationAPI verzögert aus Attr setzen +# setupRadiationAPI verzögert aus Attr setzen ################################################################ sub __setRadAPIdelayed { my $hash = shift; @@ -5731,7 +5736,7 @@ sub __setRadAPIdelayed { my $name = $hash->{NAME}; my $awdev1 = AttrVal ($name, 'ctrlWeatherDev1', ''); - CommandSet (undef, "$name currentRadiationAPI $awdev1"); # automatisch currentRadiationAPI setzen + CommandAttr (undef, "$name setupRadiationAPI $awdev1"); # automatisch setupRadiationAPI setzen return; } @@ -6331,9 +6336,19 @@ sub _addDynAttr { my $adwds = ''; my @alldwd = devspec2array ("TYPE=DWD_OpenData"); $adwds = join ",", @alldwd if(@alldwd); + my @fcdevs = qw( OpenMeteoDWD-API + OpenMeteoDWDEnsemble-API + OpenMeteoWorld-API + SolCast-API + ForecastSolar-API + VictronKI-API + ); + push @fcdevs, @alldwd if(@alldwd); + my $rdd = join ",", @fcdevs; + my @deva = split " ", $modules{$type}{AttrList}; - my $atd = 'ctrlWeatherDev'; + my $atd = 'ctrlWeatherDev|setupRadiationAPI'; @deva = grep {!/$atd/} @deva; for my $step (1..$weatherDevMax) { @@ -6344,6 +6359,8 @@ sub _addDynAttr { push @deva, ($adwds ? "ctrlWeatherDev".$step.":$adwds" : ""); } + + push @deva, "setupRadiationAPI:$rdd "; $hash->{".AttrList"} = join " ", @deva; @@ -6411,6 +6428,12 @@ sub centralTask { CommandAttr (undef, "$name setupInverterStrings $val3"); readingsDelete ($hash, 'inverterStrings'); } + + my $val4 = ReadingsVal ($name, 'currentRadiationAPI', ''); # 10.06.2024 + if ($val4) { + CommandAttr (undef, "$name setupRadiationAPI $val4"); + readingsDelete ($hash, 'currentRadiationAPI'); + } ########################################################################################################################## setModel ($hash); # Model setzen @@ -7005,17 +7028,14 @@ sub _specialActivities { $gcon = ReadingsNum ($name, "Today_Hour24_GridConsumption", 0); storeReading ('LastHourGridconsumptionReal', "$gcon Wh", $ts); - - deleteReadingspec ($hash, "Today_Hour.*_Grid.*"); - deleteReadingspec ($hash, "Today_Hour.*_PV.*"); - deleteReadingspec ($hash, "Today_Hour.*_Bat.*"); - deleteReadingspec ($hash, "powerTrigger_.*"); - deleteReadingspec ($hash, "Today_MaxPVforecast.*"); - deleteReadingspec ($hash, "Today_PVdeviation"); - deleteReadingspec ($hash, "Today_PVreal"); + + deleteReadingspec ($hash, '(Today_Hour(.*_Grid.*|.*_PV.*|.*_Bat.*)|powerTrigger_.*|Today_MaxPVforecast.*)'); + + readingsDelete ($hash, 'Today_PVdeviation'); + readingsDelete ($hash, 'Today_PVreal'); for my $wdr (@widgetreadings) { # Array der Hilfsreadings (Attributspeicher) löschen - deleteReadingspec ($hash, $wdr); + readingsDelete ($hash, $wdr); } delete $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIrequests}; @@ -7146,9 +7166,9 @@ sub __deleteHiddenReadings { for my $n (1..24) { $n = sprintf "%02d", $n; - deleteReadingspec ($hash, ".pvCorrectionFactor_${n}_cloudcover"); - deleteReadingspec ($hash, ".pvCorrectionFactor_${n}_apipercentil"); - deleteReadingspec ($hash, ".signaldone_${n}"); + readingsDelete ($hash, ".pvCorrectionFactor_${n}_cloudcover"); + readingsDelete ($hash, ".pvCorrectionFactor_${n}_apipercentil"); + readingsDelete ($hash, ".signaldone_${n}"); if (ReadingsVal ($name, "pvCorrectionFactor_Auto", "off") =~ /on/xs) { deleteReadingspec ($hash, "pvCorrectionFactor_${n}.*"); @@ -8879,7 +8899,7 @@ sub _manageConsumerData { delete $paref->{val}; } - deleteReadingspec ($hash, "consumer${c}_currentPower") if(!$etotread && !$paread); + readingsDelete ($hash, "consumer${c}_currentPower") if(!$etotread && !$paread); __getAutomaticState ($paref); # Automatic Status des Consumers abfragen __calcEnergyPieces ($paref); # Energieverbrauch auf einzelne Stunden für Planungsgrundlage aufteilen @@ -10995,7 +11015,7 @@ sub genStatisticReadings { for my $item (@srd) { next if(grep /^$item$/, @csr); - deleteReadingspec ($hash, 'statistic_'.$item); + readingsDelete ($hash, 'statistic_'.$item); deleteReadingspec ($hash, 'statistic_'.$item.'_.*') if($item eq 'todayConsumptionForecast'); } @@ -11121,7 +11141,7 @@ sub genStatisticReadings { my $c = (split "_", $kpi)[1]; # Consumer Nummer extrahieren if (!AttrVal ($name, 'consumer'.$c, '')) { - deleteReadingspec ($hash, 'statistic_currentRunMtsConsumer_'.$c); + readingsDelete ($hash, 'statistic_currentRunMtsConsumer_'.$c); return; } @@ -11134,7 +11154,7 @@ sub genStatisticReadings { my $c = (split "_", $kpi)[1]; # Consumer Nummer extrahieren if (!AttrVal ($name, 'consumer'.$c, '')) { - deleteReadingspec ($hash, 'statistic_runTimeAvgDayConsumer_'.$c); + readingsDelete ($hash, 'statistic_runTimeAvgDayConsumer_'.$c); return; } @@ -11524,7 +11544,7 @@ sub _checkSetupNotComplete { my $is = AttrVal ($name, 'setupInverterStrings', undef); # String Konfig my $wedev = AttrVal ($name, 'ctrlWeatherDev1', undef); # Device Vorhersage Wetterdaten (Bewölkung etc.) - my $radev = ReadingsVal ($name, 'currentRadiationAPI', undef); # Device Strahlungsdaten Vorhersage + my $radev = AttrVal ($name, 'setupRadiationAPI', undef); # Device Strahlungsdaten Vorhersage my $indev = AttrVal ($name, 'setupInverterDev', undef); # Inverter Device my $medev = AttrVal ($name, 'setupMeterDev', undef); # Meter Device my $peaks = ReadingsVal ($name, 'modulePeakString', undef); # String Peak @@ -15355,7 +15375,7 @@ sub checkPlantConfig { my $lang = AttrVal ($name, 'ctrlLanguage', AttrVal ('global', 'language', $deflang)); my $pcf = ReadingsVal ($name, 'pvCorrectionFactor_Auto', 'off'); - my $raname = ReadingsVal ($name, 'currentRadiationAPI', ''); + my $raname = AttrVal ($name, 'setupRadiationAPI', ''); my ($acu, $aln) = isAutoCorrUsed ($name); my $ok = FW_makeImage ('10px-kreis-gruen.png', ''); @@ -16191,7 +16211,7 @@ sub createAssociatedWith { ($afc,$h) = parseParams ($fcdev3); $fcdev3 = $afc->[0] // ""; - my $radev = ReadingsVal ($name, 'currentRadiationAPI', ''); # Radiation forecast Device + my $radev = AttrVal ($name, 'setupRadiationAPI', ''); # Radiation forecast Device ($ara,$h) = parseParams ($radev); $radev = $ara->[0] // ""; @@ -16284,7 +16304,7 @@ return; sub setModel { my $hash = shift; - my $api = ReadingsVal ($hash->{NAME}, 'currentRadiationAPI', 'DWD'); + my $api = AttrVal ($hash->{NAME}, 'setupRadiationAPI', 'DWD'); if ($api =~ /SolCast-/xs) { $hash->{MODEL} = 'SolCastAPI'; @@ -17079,7 +17099,7 @@ sub isRad1hAgeExceeded { if (!$fcname || !$defs{$fcname}) { if (!$fcname) { - return (qq{No DWD device is defined in "currentRadiationAPI"}, $resh); + return (qq{No DWD device is defined in "setupRadiationAPI"}, $resh); } else { return (qq{The DWD device "$fcname" doesn't exist}, $resh); @@ -18178,7 +18198,7 @@ to ensure that the system configuration is correct. - + @@ -18312,110 +18332,6 @@ to ensure that the system configuration is correct.
-
ctrlWeatherDevX DWD_OpenData Device which provides meteorological data (e.g. cloud cover)
currentRadiationAPI DWD_OpenData Device or API for the delivery of radiation data.
setupRadiationAPI DWD_OpenData Device or API for the delivery of radiation data.
setupInverterDev Device which provides PV performance data
setupMeterDev Device which supplies network I/O data
setupBatteryDev Device which provides battery performance data (if available)
- - - - - - - -
forecastDays 1
forecastProperties Rad1h
forecastResolution 1
forecastStation <Station code of the evaluated DWD station>
Note: The selected DWD station must provide radiation values (Rad1h Readings).
Not all stations provide this data!
- - - -
- @@ -20441,7 +20459,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. - + @@ -20575,112 +20593,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
-
ctrlWeatherDevX DWD_OpenData Device welches meteorologische Daten (z.B. Bewölkung) liefert
currentRadiationAPI DWD_OpenData Device bzw. API zur Lieferung von Strahlungsdaten
setupRadiationAPI DWD_OpenData Device bzw. API zur Lieferung von Strahlungsdaten
setupInverterDev Device welches PV Leistungsdaten liefert
setupMeterDev Device welches Netz I/O-Daten liefert
setupBatteryDev Device welches Batterie Leistungsdaten liefert (sofern vorhanden)
- - - - - - - -
forecastDays 1
forecastProperties Rad1h
forecastResolution 1
forecastStation <Stationscode der ausgewerteten DWD Station>
Hinweis: Die ausgewählte DWD Station muß Strahlungswerte (Rad1h Readings) liefern.
Nicht alle Stationen liefern diese Daten!
- - - -
- diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm index 21b554907..9d5c939a8 100644 --- a/fhem/contrib/DS_Starter/76_SolarForecast.pm +++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm @@ -157,6 +157,8 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "1.26.0" => "10.06.2024 transformed setter currentRadiationAPI to attr setupRadiationAPI ", + "1.25.2" => "09.06.2024 _specialActivities: change delete readings exec ", "1.25.1" => "08.06.2024 Illegal division by zero Forum:https://forum.fhem.de/index.php?msg=1314730 ", "1.25.0" => "05.06.2024 transformed setter inverterStrings to attr setupInverterStrings, calcTodayPVdeviation: fix continuously calc again ", "1.24.0" => "03.06.2024 transformed setter currentInverterDev to attr setupInverterDev, calcTodayPVdeviation: fix continuously calc ", @@ -496,7 +498,6 @@ my @fs = qw( ftui_forecast.css ); # Anlagenkonfiguration: maßgebliche Readings my @rconfigs = qw( pvCorrectionFactor_Auto - currentRadiationAPI moduleAzimuth modulePeakString moduleDeclination @@ -526,7 +527,7 @@ my @aconfigs = qw( affect70percentRule affectBatteryPreferredCharge affectConsFo graphicHeaderDetail graphicHeaderShow graphicHistoryHour graphicHourCount graphicHourStyle graphicLayoutType graphicSelect graphicShowDiff graphicShowNight graphicShowWeather graphicSpaceSize graphicStartHtml graphicEndHtml graphicWeatherColor graphicWeatherColorNight - setupMeterDev setupBatteryDev setupInverterDev setupInverterStrings + setupMeterDev setupBatteryDev setupInverterDev setupInverterStrings setupRadiationAPI ); for my $cinit (1..$maxconsumer) { @@ -542,8 +543,7 @@ my $allwidgets = 'icon|sortable|uzsu|knob|noArg|time|text|slider|multiple|select my %hset = ( # Hash der Set-Funktion consumerImmediatePlanning => { fn => \&_setconsumerImmediatePlanning }, - consumerNewPlanning => { fn => \&_setconsumerNewPlanning }, - currentRadiationAPI => { fn => \&_setcurrentRadiationAPI }, + consumerNewPlanning => { fn => \&_setconsumerNewPlanning }, modulePeakString => { fn => \&_setmodulePeakString }, clientAction => { fn => \&_setclientAction }, energyH4Trigger => { fn => \&_setTrigger }, @@ -609,6 +609,7 @@ my %hattr = ( # H setupBatteryDev => { fn => \&_attrBatteryDev }, setupInverterDev => { fn => \&_attrInverterDev }, setupInverterStrings => { fn => \&_attrInverterStrings }, + setupRadiationAPI => { fn => \&_attrRadiationAPI }, ); my %htr = ( # Hash even/odd für @@ -653,8 +654,8 @@ my %hqtxt = ( (Die Anzeigesprache kann mit dem Attribut "ctrlLanguage" umgestellt werden.)

} }, cfd => { EN => qq{Please enter at least one weather forecast device with "attr LINK ctrlWeatherDev1"}, DE => qq{Bitte geben sie mindestens ein Wettervorhersage Device mit "attr LINK ctrlWeatherDev1" an} }, - crd => { EN => qq{Please select the radiation forecast service with "set LINK currentRadiationAPI"}, - DE => qq{Bitte geben sie den Strahlungsvorhersage Dienst mit "set LINK currentRadiationAPI" an} }, + crd => { EN => qq{Please select the radiation forecast service with "attr LINK setupRadiationAPI"}, + DE => qq{Bitte geben sie den Strahlungsvorhersage Dienst mit "attr LINK setupRadiationAPI" an} }, cid => { EN => qq{Please specify the Inverter device with "attr LINK setupInverterDev"}, DE => qq{Bitte geben sie das Wechselrichter Device mit "attr LINK setupInverterDev" an} }, mid => { EN => qq{Please specify the device for energy measurement with "attr LINK setupMeterDev"}, @@ -1221,6 +1222,7 @@ sub Initialize { "setupInverterStrings ". "setupMeterDev:textField-long ". "setupBatteryDev:textField-long ". + "setupRadiationAPI ". $consumer. $readingFnAttributes; @@ -1468,7 +1470,6 @@ sub Set { $setlist = "Unknown argument $opt, choose one of ". "consumerImmediatePlanning:$coms ". "consumerNewPlanning:$coms ". - "currentRadiationAPI:$rdd ". "energyH4Trigger:textField-long ". "modulePeakString ". "operatingMemory:backup,save".$rf." ". @@ -1627,60 +1628,6 @@ sub _setconsumerNewPlanning { ## no critic "not used" return; } -################################################################ -# Setter currentRadiationAPI -################################################################ -sub _setcurrentRadiationAPI { ## no critic "not used" - my $paref = shift; - my $hash = $paref->{hash}; - my $name = $paref->{name}; - my $prop = $paref->{prop} // return qq{no radiation device specified}; - - if ($prop !~ /-API$/x && (!$defs{$prop} || $defs{$prop}{TYPE} ne "DWD_OpenData")) { - return qq{The device "$prop" doesn't exist or has no TYPE "DWD_OpenData"}; - } - - my $awdev1 = AttrVal ($name, 'ctrlWeatherDev1', ''); - - if (($awdev1 eq 'OpenMeteoDWD-API' && $prop ne 'OpenMeteoDWD-API') || - ($awdev1 eq 'OpenMeteoDWDEnsemble-API' && $prop ne 'OpenMeteoDWDEnsemble-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."; - } - - if ($prop =~ /(SolCast|OpenMeteoDWD|OpenMeteoDWDEnsemble|OpenMeteoWorld)-API/xs) { - return "The library FHEM::Utility::CTZ is missing. Please update FHEM completely." if($ctzAbsent); - - my $rmf = reqModFail(); - return "You have to install the required perl module: ".$rmf if($rmf); - } - - readingsSingleUpdate ($hash, "currentRadiationAPI", $prop, 1); - createAssociatedWith ($hash); - writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); # Anlagenkonfiguration File schreiben - setModel ($hash); # Model setzen - deleteReadingspec ($hash, 'nextRadiationAPICall'); - - return if(_checkSetupNotComplete ($hash)); # keine Stringkonfiguration wenn Setup noch nicht komplett - - if ($prop =~ /(ForecastSolar|OpenMeteoDWD|OpenMeteoDWDEnsemble|OpenMeteoWorld)-API/xs) { - my ($set, $lat, $lon, $elev) = locCoordinates(); - return qq{set attributes 'latitude' and 'longitude' in global device first} if(!$set); - - my $tilt = ReadingsVal ($name, 'moduleDeclination', ''); # Modul Neigungswinkel für jeden Stringbezeichner - return qq{Please complete command "set $name moduleDeclination".} if(!$tilt); - - my $dir = ReadingsVal ($name, 'moduleAzimuth', ''); # Modul Ausrichtung für jeden Stringbezeichner - return qq{Please complete command "set $name moduleAzimuth".} if(!$dir); - } - - my $type = $hash->{TYPE}; - $data{$type}{$name}{current}{allStringsFullfilled} = 0; # Stringkonfiguration neu prüfen lassen - -return; -} - ################################################################ # Setter roofIdentPair ################################################################ @@ -2049,7 +1996,7 @@ sub _setpvCorrectionFactor { ## no critic "not used" my $opt = $paref->{opt}; my $prop = $paref->{prop} // return qq{no correction value specified}; - if($prop !~ /[0-9,.]/x) { + if ($prop !~ /[0-9,.]/x) { return qq{The correction value must be specified by numbers and optionally with decimal places}; } @@ -2058,7 +2005,7 @@ sub _setpvCorrectionFactor { ## no critic "not used" readingsSingleUpdate($hash, $opt, $prop." (manual)", 1); my $cfnum = (split "_", $opt)[1]; - deleteReadingspec ($hash, "pvCorrectionFactor_${cfnum}_autocalc"); + readingsDelete ($hash, "pvCorrectionFactor_${cfnum}_autocalc"); centralTask ($hash, 0); @@ -2265,8 +2212,8 @@ sub _setreset { ## no critic "not used" } if ($prop eq 'moduleRoofTopSet') { - deleteReadingspec ($hash, "moduleRoofTops"); - writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); + readingsDelete ($hash, "moduleRoofTops"); + writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); return; } @@ -3411,7 +3358,7 @@ sub __getDWDSolarData { my $type = $hash->{TYPE}; - my $raname = ReadingsVal ($name, "currentRadiationAPI", ""); # Radiation Forecast API + my $raname = AttrVal ($name, 'setupRadiationAPI', ''); # Radiation Forecast API return if(!$raname || !$defs{$raname}); my $stime = $date.' 00:00:00'; # Startzeit Soll Übernahmedaten @@ -5204,7 +5151,7 @@ sub Attr { if ($aName eq 'ctrlGenPVdeviation' && $aVal eq 'daily') { my $type = $hash->{TYPE}; - deleteReadingspec ($hash, 'Today_PVdeviation'); + readingsDelete ($hash, 'Today_PVdeviation'); delete $data{$type}{$name}{circular}{99}{tdayDvtn}; } @@ -5681,8 +5628,7 @@ sub _attrWeatherDev { ## no critic "not used" return qq{Only the leading attribute 'ctrlWeatherDev1' can set to '$aVal'}; } - #CommandSet (undef, "$name currentRadiationAPI $aVal"); # automatisch currentRadiationAPI setzen wenn ctrlWeatherDev1 - InternalTimer (gettimeofday()+1, 'FHEM::SolarForecast::__setRadAPIdelayed', $hash, 0); # automatisch currentRadiationAPI setzen wenn ctrlWeatherDev1 + InternalTimer (gettimeofday()+1, 'FHEM::SolarForecast::__setRadAPIdelayed', $hash, 0); # automatisch setupRadiationAPI setzen wenn ctrlWeatherDev1 return; } @@ -5695,6 +5641,65 @@ sub _attrWeatherDev { ## no critic "not used" return; } +################################################################ +# Attr setupRadiationAPI +################################################################ +sub _attrRadiationAPI { ## no critic "not used" + my $paref = shift; + my $hash = $paref->{hash}; + my $name = $paref->{name}; + my $aVal = $paref->{aVal}; + my $aName = $paref->{aName}; + my $type = $paref->{type}; + + return if(!$init_done); + + if ($paref->{cmd} eq 'set') { + if ($aVal !~ /-API$/x && (!$defs{$aVal} || $defs{$aVal}{TYPE} ne "DWD_OpenData")) { + return qq{The device "$aVal" doesn't exist or has no TYPE "DWD_OpenData"}; + } + + my $awdev1 = AttrVal ($name, 'ctrlWeatherDev1', ''); + + if (($awdev1 eq 'OpenMeteoDWD-API' && $aVal ne 'OpenMeteoDWD-API') || + ($awdev1 eq 'OpenMeteoDWDEnsemble-API' && $aVal ne 'OpenMeteoDWDEnsemble-API') || + ($awdev1 eq 'OpenMeteoWorld-API' && $aVal 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."; + } + + if ($aVal =~ /(SolCast|OpenMeteoDWD|OpenMeteoDWDEnsemble|OpenMeteoWorld)-API/xs) { + return "The library FHEM::Utility::CTZ is missing. Please update FHEM completely." if($ctzAbsent); + + my $rmf = reqModFail(); + return "You have to install the required perl module: ".$rmf if($rmf); + } + + return if(_checkSetupNotComplete ($hash)); # keine Stringkonfiguration wenn Setup noch nicht komplett + + if ($aVal =~ /(ForecastSolar|OpenMeteoDWD|OpenMeteoDWDEnsemble|OpenMeteoWorld)-API/xs) { + my ($set, $lat, $lon, $elev) = locCoordinates(); + return qq{set attributes 'latitude' and 'longitude' in global device first} if(!$set); + + my $tilt = ReadingsVal ($name, 'moduleDeclination', ''); # Modul Neigungswinkel für jeden Stringbezeichner + return qq{Please complete command "set $name moduleDeclination".} if(!$tilt); + + my $dir = ReadingsVal ($name, 'moduleAzimuth', ''); # Modul Ausrichtung für jeden Stringbezeichner + return qq{Please complete command "set $name moduleAzimuth".} if(!$dir); + } + + $data{$type}{$name}{current}{allStringsFullfilled} = 0; # Stringkonfiguration neu prüfen lassen + } + + readingsDelete ($hash, 'nextRadiationAPICall'); + + InternalTimer (gettimeofday() + 1, 'FHEM::SolarForecast::setModel', $hash, 0); # Model setzen + InternalTimer (gettimeofday() + 2, 'FHEM::SolarForecast::createAssociatedWith', $hash, 0); + InternalTimer (gettimeofday() + 3, 'FHEM::SolarForecast::writeCacheToFile', [$name, 'plantconfig', $plantcfg.$name], 0); # Anlagenkonfiguration File schreiben + +return; +} + ################################################################ # Attr graphicBeamXContent ################################################################ @@ -5723,7 +5728,7 @@ return; } ################################################################ -# currentRadiationAPI verzögert aus Attr setzen +# setupRadiationAPI verzögert aus Attr setzen ################################################################ sub __setRadAPIdelayed { my $hash = shift; @@ -5731,7 +5736,7 @@ sub __setRadAPIdelayed { my $name = $hash->{NAME}; my $awdev1 = AttrVal ($name, 'ctrlWeatherDev1', ''); - CommandSet (undef, "$name currentRadiationAPI $awdev1"); # automatisch currentRadiationAPI setzen + CommandAttr (undef, "$name setupRadiationAPI $awdev1"); # automatisch setupRadiationAPI setzen return; } @@ -6331,9 +6336,19 @@ sub _addDynAttr { my $adwds = ''; my @alldwd = devspec2array ("TYPE=DWD_OpenData"); $adwds = join ",", @alldwd if(@alldwd); + my @fcdevs = qw( OpenMeteoDWD-API + OpenMeteoDWDEnsemble-API + OpenMeteoWorld-API + SolCast-API + ForecastSolar-API + VictronKI-API + ); + push @fcdevs, @alldwd if(@alldwd); + my $rdd = join ",", @fcdevs; + my @deva = split " ", $modules{$type}{AttrList}; - my $atd = 'ctrlWeatherDev'; + my $atd = 'ctrlWeatherDev|setupRadiationAPI'; @deva = grep {!/$atd/} @deva; for my $step (1..$weatherDevMax) { @@ -6344,6 +6359,8 @@ sub _addDynAttr { push @deva, ($adwds ? "ctrlWeatherDev".$step.":$adwds" : ""); } + + push @deva, "setupRadiationAPI:$rdd "; $hash->{".AttrList"} = join " ", @deva; @@ -6411,6 +6428,12 @@ sub centralTask { CommandAttr (undef, "$name setupInverterStrings $val3"); readingsDelete ($hash, 'inverterStrings'); } + + my $val4 = ReadingsVal ($name, 'currentRadiationAPI', ''); # 10.06.2024 + if ($val4) { + CommandAttr (undef, "$name setupRadiationAPI $val4"); + readingsDelete ($hash, 'currentRadiationAPI'); + } ########################################################################################################################## setModel ($hash); # Model setzen @@ -7005,17 +7028,14 @@ sub _specialActivities { $gcon = ReadingsNum ($name, "Today_Hour24_GridConsumption", 0); storeReading ('LastHourGridconsumptionReal', "$gcon Wh", $ts); - - deleteReadingspec ($hash, "Today_Hour.*_Grid.*"); - deleteReadingspec ($hash, "Today_Hour.*_PV.*"); - deleteReadingspec ($hash, "Today_Hour.*_Bat.*"); - deleteReadingspec ($hash, "powerTrigger_.*"); - deleteReadingspec ($hash, "Today_MaxPVforecast.*"); - deleteReadingspec ($hash, "Today_PVdeviation"); - deleteReadingspec ($hash, "Today_PVreal"); + + deleteReadingspec ($hash, '(Today_Hour(.*_Grid.*|.*_PV.*|.*_Bat.*)|powerTrigger_.*|Today_MaxPVforecast.*)'); + + readingsDelete ($hash, 'Today_PVdeviation'); + readingsDelete ($hash, 'Today_PVreal'); for my $wdr (@widgetreadings) { # Array der Hilfsreadings (Attributspeicher) löschen - deleteReadingspec ($hash, $wdr); + readingsDelete ($hash, $wdr); } delete $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIrequests}; @@ -7146,9 +7166,9 @@ sub __deleteHiddenReadings { for my $n (1..24) { $n = sprintf "%02d", $n; - deleteReadingspec ($hash, ".pvCorrectionFactor_${n}_cloudcover"); - deleteReadingspec ($hash, ".pvCorrectionFactor_${n}_apipercentil"); - deleteReadingspec ($hash, ".signaldone_${n}"); + readingsDelete ($hash, ".pvCorrectionFactor_${n}_cloudcover"); + readingsDelete ($hash, ".pvCorrectionFactor_${n}_apipercentil"); + readingsDelete ($hash, ".signaldone_${n}"); if (ReadingsVal ($name, "pvCorrectionFactor_Auto", "off") =~ /on/xs) { deleteReadingspec ($hash, "pvCorrectionFactor_${n}.*"); @@ -8879,7 +8899,7 @@ sub _manageConsumerData { delete $paref->{val}; } - deleteReadingspec ($hash, "consumer${c}_currentPower") if(!$etotread && !$paread); + readingsDelete ($hash, "consumer${c}_currentPower") if(!$etotread && !$paread); __getAutomaticState ($paref); # Automatic Status des Consumers abfragen __calcEnergyPieces ($paref); # Energieverbrauch auf einzelne Stunden für Planungsgrundlage aufteilen @@ -10995,7 +11015,7 @@ sub genStatisticReadings { for my $item (@srd) { next if(grep /^$item$/, @csr); - deleteReadingspec ($hash, 'statistic_'.$item); + readingsDelete ($hash, 'statistic_'.$item); deleteReadingspec ($hash, 'statistic_'.$item.'_.*') if($item eq 'todayConsumptionForecast'); } @@ -11121,7 +11141,7 @@ sub genStatisticReadings { my $c = (split "_", $kpi)[1]; # Consumer Nummer extrahieren if (!AttrVal ($name, 'consumer'.$c, '')) { - deleteReadingspec ($hash, 'statistic_currentRunMtsConsumer_'.$c); + readingsDelete ($hash, 'statistic_currentRunMtsConsumer_'.$c); return; } @@ -11134,7 +11154,7 @@ sub genStatisticReadings { my $c = (split "_", $kpi)[1]; # Consumer Nummer extrahieren if (!AttrVal ($name, 'consumer'.$c, '')) { - deleteReadingspec ($hash, 'statistic_runTimeAvgDayConsumer_'.$c); + readingsDelete ($hash, 'statistic_runTimeAvgDayConsumer_'.$c); return; } @@ -11524,7 +11544,7 @@ sub _checkSetupNotComplete { my $is = AttrVal ($name, 'setupInverterStrings', undef); # String Konfig my $wedev = AttrVal ($name, 'ctrlWeatherDev1', undef); # Device Vorhersage Wetterdaten (Bewölkung etc.) - my $radev = ReadingsVal ($name, 'currentRadiationAPI', undef); # Device Strahlungsdaten Vorhersage + my $radev = AttrVal ($name, 'setupRadiationAPI', undef); # Device Strahlungsdaten Vorhersage my $indev = AttrVal ($name, 'setupInverterDev', undef); # Inverter Device my $medev = AttrVal ($name, 'setupMeterDev', undef); # Meter Device my $peaks = ReadingsVal ($name, 'modulePeakString', undef); # String Peak @@ -15355,7 +15375,7 @@ sub checkPlantConfig { my $lang = AttrVal ($name, 'ctrlLanguage', AttrVal ('global', 'language', $deflang)); my $pcf = ReadingsVal ($name, 'pvCorrectionFactor_Auto', 'off'); - my $raname = ReadingsVal ($name, 'currentRadiationAPI', ''); + my $raname = AttrVal ($name, 'setupRadiationAPI', ''); my ($acu, $aln) = isAutoCorrUsed ($name); my $ok = FW_makeImage ('10px-kreis-gruen.png', ''); @@ -16191,7 +16211,7 @@ sub createAssociatedWith { ($afc,$h) = parseParams ($fcdev3); $fcdev3 = $afc->[0] // ""; - my $radev = ReadingsVal ($name, 'currentRadiationAPI', ''); # Radiation forecast Device + my $radev = AttrVal ($name, 'setupRadiationAPI', ''); # Radiation forecast Device ($ara,$h) = parseParams ($radev); $radev = $ara->[0] // ""; @@ -16284,7 +16304,7 @@ return; sub setModel { my $hash = shift; - my $api = ReadingsVal ($hash->{NAME}, 'currentRadiationAPI', 'DWD'); + my $api = AttrVal ($hash->{NAME}, 'setupRadiationAPI', 'DWD'); if ($api =~ /SolCast-/xs) { $hash->{MODEL} = 'SolCastAPI'; @@ -17079,7 +17099,7 @@ sub isRad1hAgeExceeded { if (!$fcname || !$defs{$fcname}) { if (!$fcname) { - return (qq{No DWD device is defined in "currentRadiationAPI"}, $resh); + return (qq{No DWD device is defined in "setupRadiationAPI"}, $resh); } else { return (qq{The DWD device "$fcname" doesn't exist}, $resh); @@ -18178,7 +18198,7 @@ to ensure that the system configuration is correct. - + @@ -18312,110 +18332,6 @@ to ensure that the system configuration is correct.
-
ctrlWeatherDevX DWD_OpenData Device which provides meteorological data (e.g. cloud cover)
currentRadiationAPI DWD_OpenData Device or API for the delivery of radiation data.
setupRadiationAPI DWD_OpenData Device or API for the delivery of radiation data.
setupInverterDev Device which provides PV performance data
setupMeterDev Device which supplies network I/O data
setupBatteryDev Device which provides battery performance data (if available)
- - - - - - - -
forecastDays 1
forecastProperties Rad1h
forecastResolution 1
forecastStation <Station code of the evaluated DWD station>
Note: The selected DWD station must provide radiation values (Rad1h Readings).
Not all stations provide this data!
- - - -
- @@ -20441,7 +20459,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. - + @@ -20575,112 +20593,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
-
ctrlWeatherDevX DWD_OpenData Device welches meteorologische Daten (z.B. Bewölkung) liefert
currentRadiationAPI DWD_OpenData Device bzw. API zur Lieferung von Strahlungsdaten
setupRadiationAPI DWD_OpenData Device bzw. API zur Lieferung von Strahlungsdaten
setupInverterDev Device welches PV Leistungsdaten liefert
setupMeterDev Device welches Netz I/O-Daten liefert
setupBatteryDev Device welches Batterie Leistungsdaten liefert (sofern vorhanden)
- - - - - - - -
forecastDays 1
forecastProperties Rad1h
forecastResolution 1
forecastStation <Stationscode der ausgewerteten DWD Station>
Hinweis: Die ausgewählte DWD Station muß Strahlungswerte (Rad1h Readings) liefern.
Nicht alle Stationen liefern diese Daten!
- - - -
-