diff --git a/fhem/CHANGED b/fhem/CHANGED index 072395972..5cd467881 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it + - feature: 76_SolarForecast: version 1.47.5 - feature: 6.4 released - 2025-03-29 (6.3) diff --git a/fhem/FHEM/76_SolarForecast.pm b/fhem/FHEM/76_SolarForecast.pm index 28c9ac2c8..960e5ccc4 100644 --- a/fhem/FHEM/76_SolarForecast.pm +++ b/fhem/FHEM/76_SolarForecast.pm @@ -160,6 +160,12 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "1.49.5" => "29.03.2025 some code changes, Attr affectSolCastPercentile, ctrlSolCastAPIoptimizeReq are obsolete -> SolCast optimze requests is default now ". + "attr affectConsForecastIdentWeekdays replaced by plantControl->consForecastIdentWeekdays ". + "attr affectConsForecastLastDays replaced by plantControl->consForecastLastDays ". + "attr ctrlInterval replaced by plantControl->cycleInterval". + "attr ctrlGenPVdeviation replaced by plantControl->genPVdeviation ". + "setupBatteryDevXX: new keys pinmax, poutmax ", "1.49.4" => "28.03.2025 _batChargeRecmd: revert Loading release changes of V 1.49.0, _transferAPIRadiationValues: fix sunalt for next day ". "Home Node: Mouse over show Autarky Rate, flowGraphicControl: new key strokeconsumerdyncol ", "1.49.3" => "27.03.2025 flowGraphicControl: new key homenodedyncol ", @@ -371,28 +377,6 @@ my %vNotesIntern = ( "1.17.9" => "17.04.2024 _batSocTarget: fix Illegal division by zero, Forum: https://forum.fhem.de/index.php?msg=1310930 ", "1.17.8" => "16.04.2024 _calcTodayPVdeviation: change of calculation ", "1.17.7" => "09.04.2024 export pvHistory to CSV, making attr affectMaxDayVariance obsolete ", - "1.17.6" => "07.04.2024 new sub writeToHistory with many internal changes in pvHistory write process ". - "_transferInverterValues: react on inverter etotal behavior ", - "1.17.5" => "04.04.2024 currentInverterDev: check syntax of key capacity if set, change defmaxvar back from 0.8 to 0.5 ". - "currentMeterDev: [conprice=::] [feedprice=::] ". - "___setOpenMeteoAPIcallKeyData: new sub to calculate the minimum Open-Meteo request intervalls ", - "1.17.4" => "01.04.2024 fix ctrlWeatherDev1 Drop-Down list if no DWD Device exists, edit commandref ", - "1.17.3" => "31.03.2024 edit commandref, valDecTree: more infos in aiRuleStrings output, integrate OpenMeteoDWDEnsemble-API ". - "change Call interval Open-Meteo API to 900s, OpenMeteo-API: fix todayDoneAPIcalls, implement callequivalent". - "aiTrain: change default start to hour 2, change AI acceptable result limits ", - "1.17.2" => "29.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 ". - "_specialActivities: split tasks to several time slots, bugfixes ". - "AI: modify aiAddInstance, Customize pattern training data ". - "add batteryTrigger to save plantconfig, valDecTree: more infos in get aiRuleStrings ", - "1.17.0" => "24.03.2024 new DWD ICON API, change defmaxvar from 0.5 to 0.8, attr ctrlWeatherDev1 can select OpenMeteoDWD-API ", - "1.16.8" => "16.03.2024 plantConfigCheck: adjust pvCorrectionFactor_Auto check, settings of forecastRefresh ". - "rename reading nextSolCastCall to nextRadiationAPICall ". - "currentMeterDev: new optional keys conprice, feedprice ". - "destroy runtime data when delete device ", - "1.16.7" => "12.03.2024 prevent duplicates in NOTIFYDEV, Forum: https://forum.fhem.de/index.php?msg=1306875 ", - "1.16.6" => "11.03.2024 plantConfigCheck: join forecastProperties with ',' ", "0.1.0" => "09.12.2020 initial Version " ); @@ -508,6 +492,8 @@ use constant { CFILE => 'controls_solarforecast.txt', # Controlfile Update FTUI-Files BGHPATH => 'https://raw.githubusercontent.com/nasseeder1/FHEM-SolarForecast/refs/heads/main/', # Basispfad GitHub SolarForecast Files PGHPATH => '', # GitHub Post Pfad + MSGFILETEST => 'controls_solarforecast_messages_test.txt', # TEST Input-File Notification System + MSGFILEPROD => 'controls_solarforecast_messages_prod.txt', # PRODUKTIVES Input-File Notification System }; ## Standardvariablen @@ -536,10 +522,7 @@ my @draattrmust = qw(Rad1h); my @ctypes = qw(dishwasher dryer washingmachine heater charger other noSchedule); # erlaubte Consumer Typen -my $msgfiletest = 'controls_solarforecast_messages_test.txt'; # TEST Input-File Notification System -my $msgfileprod = 'controls_solarforecast_messages_prod.txt'; # PRODUKTIVES Input-File Notification System - -my $messagefile = $msgfileprod; +my $messagefile = MSGFILEPROD; # mögliche Debug-Module my @dd = qw( aiProcess aiData @@ -574,14 +557,12 @@ my @rconfigs = qw( pvCorrectionFactor_Auto energyH4Trigger ); # Anlagenkonfiguration: maßgebliche Attribute -my @aconfigs = qw( affectConsForecastIdentWeekdays affectConsForecastLastDays - affectSolCastPercentile - aiControl +my @aconfigs = qw( aiControl consumerLegend consumerAdviceIcon consumerLink - ctrlConsRecommendReadings ctrlGenPVdeviation ctrlInterval + ctrlConsRecommendReadings ctrlLanguage ctrlNextDayForecastReadings ctrlNextHoursSoCForecastReadings ctrlSolCastAPImaxReq - ctrlSolCastAPIoptimizeReq ctrlSpecialReadings ctrlUserExitFn + ctrlSpecialReadings ctrlUserExitFn disable flowGraphicControl graphicBeamWidth graphicBeamHeightLevel1 graphicBeamHeightLevel2 graphicBeamHeightLevel3 @@ -1535,22 +1516,16 @@ sub Initialize { $hash->{AttrFn} = \&Attr; $hash->{NotifyFn} = \&Notify; $hash->{ReadyFn} = \&runTask; - $hash->{AttrList} = "affectConsForecastIdentWeekdays:1,0 ". - "affectConsForecastLastDays:selectnumbers,1,1,180,0,lin ". - "affectSolCastPercentile:select,10,50,90 ". - "aiControl:textField-long ". + $hash->{AttrList} = "aiControl:textField-long ". "consumerLegend:none,icon_top,icon_bottom,text_top,text_bottom ". "consumerAdviceIcon ". "consumerLink:0,1 ". "ctrlConsRecommendReadings:multiple-strict,$allcs ". "ctrlDebug:multiple-strict,$dm,#10 ". - "ctrlGenPVdeviation:daily,continuously ". - "ctrlInterval ". "ctrlLanguage:DE,EN ". "ctrlNextDayForecastReadings:multiple-strict,$hod ". "ctrlNextHoursSoCForecastReadings ". "ctrlSolCastAPImaxReq:selectnumbers,5,5,60,0,lin ". - "ctrlSolCastAPIoptimizeReq:1,0 ". "ctrlSpecialReadings:multiple-strict,$srd ". "ctrlUserExitFn:textField-long ". "disable:1,0 ". @@ -1598,8 +1573,10 @@ sub Initialize { ### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !! ########################################################################################################################## - my $av = 'obsolete#-#use#attr#plantControl#instead'; - $hash->{AttrList} .= " affectBatteryPreferredCharge:$av affectConsForecastInPlanning:$av ctrlShowLink:$av ctrlBackupFilesKeep:$av"; # 22.03.2025 + my $av = 'obsolete#-#use#attr#plantControl#instead'; + my $av1 = 'obsolete#-#will#be#deleted#soon'; + $hash->{AttrList} .= " affectBatteryPreferredCharge:$av affectConsForecastInPlanning:$av ctrlShowLink:$av ctrlBackupFilesKeep:$av affectConsForecastIdentWeekdays:$av affectConsForecastLastDays:$av ctrlInterval:$av ctrlGenPVdeviation:$av"; # 31.03.2025 + $hash->{AttrList} .= " affectSolCastPercentile:$av1 ctrlSolCastAPIoptimizeReq:$av1"; # 29.03.2025 ########################################################################################################################## $hash->{FW_hideDisplayName} = 1; # Forum 88667 @@ -3011,12 +2988,6 @@ sub __solCast_ApiResponse { } my ($period,$starttmstr); - - my $perc = AttrVal ($name, 'affectSolCastPercentile', 50); # das gewählte zu nutzende Percentil - - debugLog ($paref, "apiProcess", qq{SolCast API used percentile: }. $perc); - - $perc = q{} if($perc == 50); my $k = 0; while ($jdata->{'forecasts'}[$k]) { # vorhandene Startzeiten Schlüssel im SolCast API Hash löschen @@ -3049,7 +3020,7 @@ sub __solCast_ApiResponse { $k = 0; while ($jdata->{'forecasts'}[$k]) { - if (!$jdata->{'forecasts'}[$k]{'pv_estimate'.$perc}) { # keine PV Prognose -> Datensatz überspringen -> Verarbeitungszeit sparen + if (!$jdata->{'forecasts'}[$k]{'pv_estimate'}) { # keine PV Prognose -> Datensatz überspringen -> Verarbeitungszeit sparen $k++; next; } @@ -3057,7 +3028,7 @@ sub __solCast_ApiResponse { my $petstr = $jdata->{'forecasts'}[$k]{'period_end'}; ($err, $starttmstr) = ___convPendToPstart ($name, $lang, $petstr); - my $pvest50 = $jdata->{'forecasts'}[$k]{'pv_estimate'.$perc}; + my $pvest50 = $jdata->{'forecasts'}[$k]{'pv_estimate'}; $period = $jdata->{'forecasts'}[$k]{'period'}; $period =~ s/.*(\d\d).*/$1/; @@ -3180,24 +3151,17 @@ sub ___setSolCastAPIcallKeyData { ## Berechnung des optimalen Request Intervalls ################################################ - if (AttrVal($name, 'ctrlSolCastAPIoptimizeReq', 0)) { - my $date = strftime "%Y-%m-%d", localtime($t); - my $sunset = $date.' '.ReadingsVal ($name, "Today_SunSet", '00:00').':00'; - my $sstime = timestringToTimestamp ($sunset); - my $dart = $sstime - $t; # verbleibende Sekunden bis Sonnenuntergang - $dart = 0 if($dart < 0); - $drc += 1; + my $date = strftime "%Y-%m-%d", localtime($t); + my $sunset = $date.' '.ReadingsVal ($name, "Today_SunSet", '00:00').':00'; + my $sstime = timestringToTimestamp ($sunset); + my $dart = $sstime - $t; # verbleibende Sekunden bis Sonnenuntergang + $dart = 0 if($dart < 0); + $drc += 1; - $data{$name}{statusapi}{SolCast}{'?All'}{currentAPIinterval} = SOLAPIREPDEF; - $data{$name}{statusapi}{SolCast}{'?All'}{currentAPIinterval} = int ($dart / $drc) if($dart && $drc); + $data{$name}{statusapi}{SolCast}{'?All'}{currentAPIinterval} = SOLAPIREPDEF; + $data{$name}{statusapi}{SolCast}{'?All'}{currentAPIinterval} = int ($dart / $drc) if($dart && $drc); - debugLog ($paref, "apiProcess|apiCall", "SolCast API Call - Sunset: $sunset, remain Sec to Sunset: $dart, new interval: ".StatusAPIVal ($hash, 'SolCast', '?All', 'currentAPIinterval', SOLAPIREPDEF)); - } - else { - $data{$name}{statusapi}{SolCast}{'?All'}{currentAPIinterval} = SOLAPIREPDEF; - } - - #### + debugLog ($paref, "apiProcess|apiCall", "SolCast API Call - Sunset: $sunset, remain Sec to Sunset: $dart, new interval: ".StatusAPIVal ($hash, 'SolCast', '?All', 'currentAPIinterval', SOLAPIREPDEF)); my $apiitv = StatusAPIVal ($hash, 'SolCast', '?All', 'currentAPIinterval', SOLAPIREPDEF); @@ -5879,9 +5843,8 @@ sub Attr { ### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !! ###################################################################################################################### - if ($cmd eq 'set' && $aName =~ /^affectBatteryPreferredCharge|affectConsForecastInPlanning|ctrlShowLink|ctrlBackupFilesKeep$/) { # 22.03.2025 - #my $msg = "The attribute $aName is obsolete and will be deleted soon. Please press 'save config' when restart is finished."; - my $msg = "The attribute $aName is replaced by 'plantControl'."; + if ($cmd eq 'set' && $aName =~ /^affectBatteryPreferredCharge|affectConsForecastInPlanning|ctrlShowLink|ctrlBackupFilesKeep|affectConsForecastIdentWeekdays|affectConsForecastLastDays|ctrlInterval|ctrlGenPVdeviation$/) { # 31.03.2025 + my $msg = "The attribute $aName is replaced by 'plantControl'."; if (!$init_done) { Log3 ($name, 1, "$name - $msg"); } @@ -5889,12 +5852,25 @@ sub Attr { return $msg; } } + + if ($cmd eq 'set' && $aName =~ /^affectSolCastPercentile|ctrlSolCastAPIoptimizeReq$/) { # 29.03.2025 + my $msg1 = "The attribute $aName is obsolete and will be deleted soon. Please press 'save config' when restart is finished."; + my $msg2 = "The attribute $aName is obsolete and will be deleted soon."; + if (!$init_done) { + Log3 ($name, 1, "$name - $msg1"); + return $msg1; + } + else { + return $msg2; + } + } ###################################################################################################################### if ($aName eq 'disable') { if($cmd eq 'set') { $do = $aVal ? 1 : 0; } + $do = 0 if($cmd eq 'del'); $val = ($do == 1 ? 'disabled' : 'initialized'); singleUpdateState ( {hash => $hash, state => $val, evt => 1} ); @@ -5931,40 +5907,16 @@ sub Attr { delete $data{$name}{circular}{99}{'nextTsMaxSocChge'.$bn}; } - if ($aName eq 'ctrlGenPVdeviation' && $aVal eq 'daily') { - readingsDelete ($hash, 'Today_PVdeviation'); - delete $data{$name}{circular}{99}{tdayDvtn}; - } - if ($aName eq 'graphicHeaderOwnspecValForm') { $err = isGhoValFormValid ($name, $aVal); return $err if($err); } if ($cmd eq 'set') { - if ($aName eq 'ctrlInterval') { - unless ($aVal =~ /^[0-9]+$/x) { - return qq{Invalid value for $aName. Use only figures 0-9!}; - } - } - - if ($init_done && $aName eq 'ctrlSolCastAPIoptimizeReq') { - if (!isSolCastUsed ($hash)) { - return qq{The attribute $aName is only valid for device model "SolCastAPI".}; - } - } - if ($init_done && $aName eq 'ctrlUserExitFn') { ($err) = checkCode ($name, $aVal, 'cc1'); return $err if($err); } - - if ($init_done && $aName eq 'ctrlInterval') { - _newCycTime ($hash, time, $aVal); - my $nct = CurrentVal ($hash, 'nextCycleTime', 0); # gespeicherte nächste CyleTime - readingsSingleUpdate ($hash, 'nextCycletime', (!$nct ? 'Manual / Event-controlled' : FmtTime($nct)), 0); - return; - } } my $params = { @@ -6311,28 +6263,22 @@ sub _attraiControl { ## no critic "not used" my $name = $paref->{name}; my $aVal = $paref->{aVal}; my $cmd = $paref->{cmd}; + + my $valid = { + aiStorageDuration => { comp => '\d+', act => 0 }, + aiTrainStart => { comp => '(1?[1-9]|10|2[0-3])', act => 0 }, + aiTreesPV => { comp => '(1?[1-9]|10|[2-4][0-9]|50)', act => 0 }, + }; - my $hash = $defs{$name}; - - for my $av ( qw( aiStorageDuration - aiTrainStart - aiTreesPV - ) ) { - + for my $av (keys %{$valid}) { delete $data{$name}{current}{$av}; } + + my ($a, $h) = parseParams ($aVal); if ($cmd eq 'set') { - my $valid = { - aiStorageDuration => '\d+', - aiTrainStart => '(1?[1-9]|10|2[0-3])', - aiTreesPV => '(1?[1-9]|10|[2-4][0-9]|50)', - }; - - my ($a, $h) = parseParams ($aVal); - for my $key (keys %{$h}) { - my $comp = $valid->{$key}; + my $comp = $valid->{$key}{comp}; next if(!$comp); if ($h->{$key} =~ /^$comp$/xs) { @@ -6343,6 +6289,18 @@ sub _attraiControl { ## no critic "not used" } } } + + for my $akey (keys %{$h}) { # von bestimmten Schlüsseln abhängige Aktionen ausführen + next if(!$valid->{$akey}{act}); + + $paref->{akey} = $akey; + $paref->{keyval} = $h->{$akey}; + + __attrKeyAction ($paref); + + delete $paref->{keyval}; + delete $paref->{akey}; + } return; } @@ -6355,30 +6313,28 @@ sub _attrplantControl { ## no critic "not used" my $name = $paref->{name}; my $aVal = $paref->{aVal}; my $cmd = $paref->{cmd}; - - my $hash = $defs{$name}; - - for my $av ( qw( batteryPreferredCharge - consForecastInPlanning - feedinPowerLimit - showLink - ) ) { - + + my $valid = { + backupFilesKeep => { comp => '\d+', act => 0 }, + batteryPreferredCharge => { comp => '([0-9]|[1-9][0-9]|100)', act => 0 }, + consForecastIdentWeekdays => { comp => '(0|1)', act => 0 }, + consForecastLastDays => { comp => '([1-9]|[1-9][0-9]|1[0-7][0-9]|180)', act => 0 }, + consForecastInPlanning => { comp => '(0|1)', act => 0 }, + cycleInterval => { comp => '\d+', act => 1 }, + feedinPowerLimit => { comp => '\d+', act => 0 }, + genPVdeviation => { comp => '(daily|continuously)', act => 1 }, + showLink => { comp => '(0|1)', act => 0 }, + }; + + for my $av (keys %{$valid}) { delete $data{$name}{current}{$av}; } + + my ($a, $h) = parseParams ($aVal); if ($cmd eq 'set') { - my $valid = { - batteryPreferredCharge => '([0-9]|[1-9][0-9]|100)', - consForecastInPlanning => '0|1', - feedinPowerLimit => '\d+', - showLink => '0|1', - }; - - my ($a, $h) = parseParams ($aVal); - for my $key (keys %{$h}) { - my $comp = $valid->{$key}; + my $comp = $valid->{$key}{comp}; next if(!$comp); if ($h->{$key} =~ /^$comp$/xs) { @@ -6389,6 +6345,18 @@ sub _attrplantControl { ## no critic "not used" } } } + + for my $akey (keys %{$h}) { # von bestimmten Schlüsseln abhängige Aktionen ausführen + next if(!$valid->{$akey}{act}); + + $paref->{akey} = $akey; + $paref->{keyval} = $h->{$akey}; + + __attrKeyAction ($paref); + + delete $paref->{keyval}; + delete $paref->{akey}; + } return; } @@ -6723,6 +6691,14 @@ sub _attrBatteryDev { ## no critic "not used" if (!$h->{pin} || !$h->{pout} || !$h->{cap}) { return qq{One or more of the keys 'pin, pout, cap' are missing. Please note the command reference.}; } + + if ($h->{pinmax} && $h->{pinmax} !~ /^\d+$/xs) { + return qq{The key “pinmax” may only be specified by whole numbers}; + } + + if ($h->{poutmax} && $h->{poutmax} !~ /^\d+$/xs) { + return qq{The key “poutmax” may only be specified by whole numbers}; + } if ($h->{show} && $h->{show} =~ /:/xs) { my ($show, $pos) = split ':', $h->{show}; @@ -6832,7 +6808,7 @@ sub _attrRadiationAPI { ## no critic "not used" return if(!$init_done); - my $hash = $defs{$name}; + my $hash = $defs{$name}; if ($paref->{cmd} eq 'set') { if ($aVal !~ /-API$/x && (!$defs{$aVal} || $defs{$aVal}{TYPE} ne "DWD_OpenData")) { @@ -6899,6 +6875,34 @@ sub _attrgraphicBeamXContent { ## no critic "not used" return; } +################################################################ +# von bestimmten Schlüsseln abhängige Aktionen ausführen +################################################################ +sub __attrKeyAction { + my $paref = shift; + my $name = $paref->{name}; + my $akey = $paref->{akey}; + my $keyval = $paref->{keyval}; + my $cmd = $paref->{cmd}; + + my $hash = $defs{$name}; + + if ($cmd eq 'set') { + if ($init_done && $akey eq 'cycleInterval') { + _newCycTime ($hash, time, $keyval); + my $nct = CurrentVal ($name, 'nextCycleTime', 0); # gespeicherte nächste CyleTime + readingsSingleUpdate ($hash, 'nextCycletime', (!$nct ? 'Manual / Event-controlled' : FmtTime($nct)), 0); + } + } + + if ($akey eq 'genPVdeviation' && $keyval eq 'daily') { + readingsDelete ($hash, 'Today_PVdeviation'); + delete $data{$name}{circular}{99}{tdayDvtn}; + } + +return; +} + ################################################################ # Attr setupRadiationAPI und setupWeatherDev1 # harmonisieren wenn erforderlich @@ -8033,6 +8037,46 @@ sub centralTask { } ###### + my $fiw = AttrVal ($name, 'affectConsForecastIdentWeekdays', undef); # 29.03.2025 + my $pc4 = AttrVal ($name, 'plantControl', ''); + + if (defined $fiw) { + my $newval = $pc4." consForecastIdentWeekdays=$fiw"; + CommandAttr (undef, "$name plantControl $newval"); + ::CommandDeleteAttr (undef, "$name affectConsForecastIdentWeekdays"); + } + ###### + + my $cfl = AttrVal ($name, 'affectConsForecastLastDays', undef); # 29.03.2025 + my $pc5 = AttrVal ($name, 'plantControl', ''); + + if (defined $cfl) { + my $newval = $pc5." consForecastLastDays=$cfl"; + CommandAttr (undef, "$name plantControl $newval"); + ::CommandDeleteAttr (undef, "$name affectConsForecastLastDays"); + } + ###### + + my $civ = AttrVal ($name, 'ctrlInterval', undef); # 31.03.2025 + my $pc6 = AttrVal ($name, 'plantControl', ''); + + if (defined $civ) { + my $newval = $pc6." cycleInterval=$civ"; + CommandAttr (undef, "$name plantControl $newval"); + ::CommandDeleteAttr (undef, "$name ctrlInterval"); + } + ###### + + my $cgd = AttrVal ($name, 'ctrlGenPVdeviation', undef); # 31.03.2025 + my $pc7 = AttrVal ($name, 'plantControl', ''); + + if (defined $cgd) { + my $newval = $pc7." genPVdeviation=$cgd"; + CommandAttr (undef, "$name plantControl $newval"); + ::CommandDeleteAttr (undef, "$name ctrlGenPVdeviation"); + } + ###### + my $n = 0; # 01.02.25 -> Datenmigration pvrlsum, pvfcsum, dnumsum in pvrl_*, pvfc_* for my $hh (1..24) { $hh = sprintf "%02d", $hh; @@ -10074,9 +10118,11 @@ sub _transferBatteryValues { my ($pou,$pounit) = split ":", $h->{pout}; # Readingname/Unit für aktuelle Batterieentladung my ($bin,$binunit) = split ":", $h->{intotal} // "-:-"; # Readingname/Unit der total in die Batterie eingespeisten Energie (Zähler) my ($bout,$boutunit) = split ":", $h->{outtotal} // "-:-"; # Readingname/Unit der total aus der Batterie entnommenen Energie (Zähler) - my $batchr = $h->{charge} // ""; # Readingname Ladezustand Batterie + my $batchr = $h->{charge} // ''; # Readingname Ladezustand Batterie my $instcap = $h->{cap}; # numerischer Wert (Wh) oder Readingname installierte Batteriekapazität - + my $pinmax = $h->{pinmax} // INFINIITY; # max. mögliche Ladeleistung + my $poutmax = $h->{poutmax} // INFINIITY; # max. mögliche Entladeleistung + return if(!$pin || !$pou); $pounit //= $piunit; @@ -10251,6 +10297,8 @@ sub _transferBatteryValues { $data{$name}{batteries}{$bn}{balias} = AttrVal ($badev, 'alias', $badev); # Alias Batterie Device $data{$name}{batteries}{$bn}{bpowerin} = $pbi; # momentane Batterieladung $data{$name}{batteries}{$bn}{bpowerout} = $pbo; # momentane Batterieentladung + $data{$name}{batteries}{$bn}{bpinmax} = $pinmax; # max. mögliche Ladeleistung + $data{$name}{batteries}{$bn}{bpoutmax} = $poutmax; # max. mögliche Entladeleistung $data{$name}{batteries}{$bn}{bcharge} = $soc; # Batterie SoC (%) $data{$name}{batteries}{$bn}{basynchron} = $h->{asynchron} // 0; # asynchroner Modus = X $data{$name}{batteries}{$bn}{bicon} = $h->{icon} if($h->{icon}); # Batterie Icon @@ -10578,8 +10626,10 @@ sub _batChargeRecmd { my $tomconfc = ReadingsNum ($name, 'Tomorrow_ConsumptionForecast', 0); # Verbrauchsprognose nächster Tag my $batoptsoc = ReadingsNum ($name, 'Battery_OptimumTargetSoC_'.$bn, 0); # aktueller optimierter SoC my $confcss = CurrentVal ($name, 'tdConFcTillSunset', 0); # Verbrauchsprognose bis Sonnenuntergang - my $csoc = BatteryVal ($hash, $bn, 'bcharge', 0); # aktuelle Ladung in % - my $cgbt = AttrVal ($name, 'ctrlBatSocManagement'.$bn, undef); + my $csoc = BatteryVal ($hash, $bn, 'bcharge', 0); # aktuelle Ladung in % + my $bpinmax = BatteryVal ($hash, $bn, 'bpinmax', INFINIITY); # max. mögliche Ladeleistung W + my $bpoutmax = BatteryVal ($hash, $bn, 'bpoutmax', INFINIITY); # max. mögliche Entladeleistung W + my $cgbt = AttrVal ($name, 'ctrlBatSocManagement'.$bn, undef); my $sf = __batCapShareFactor ($hash, $bn); # Anteilsfaktor der Batterie XX Kapazität an Gesamtkapazität my $lowSoc = 0; @@ -10654,9 +10704,16 @@ sub _batChargeRecmd { ## SOC-Prognose ################# # change V 1.47.0 - my $fceff = $pvfc - $confc; # effektiver PV Überschuß (effektiver Verbrauch wenn < 0) - $socwh += $crel ? ($fceff > 0 ? $fceff * STOREFFDEF : $fceff / STOREFFDEF) : - ($fceff > 0 ? 0 : $fceff / STOREFFDEF); # PV Prognose nur einbeziehen wenn Ladefreigabe + my $fceff = $pvfc - $confc; # effektiver PV Überschuß bzw. effektiver Verbrauch wenn < 0 + $fceff = $fceff > 0 ? ($fceff >= $bpinmax ? $bpinmax : $fceff) : + $fceff < 0 ? ($fceff <= $bpoutmax * -1 ? $bpoutmax * -1 : $fceff) : + $fceff; + + # debugLog ($paref, 'batteryManagement', "Bat $bn Charge Rcmd - max. possible Charging(+) / Discharging(-) Energy: $fceff Wh"); + + $socwh += $crel ? ($fceff > 0 ? $fceff * STOREFFDEF : $fceff / STOREFFDEF) : + ($fceff > 0 ? 0 : + $fceff / STOREFFDEF); # PV Überschuß (d.h. Aufladung) nur einbeziehen wenn Ladefreigabe $socwh = $socwh < $lowSocwh ? $lowSocwh : $socwh < $batoptsocwh ? $batoptsocwh : # SoC Prognose in Wh @@ -10673,13 +10730,13 @@ sub _batChargeRecmd { } ); # Readings NextHourXX_Bat_XX_ChargeForecast erstellen - my $msg = "(CurrSoc: $csoc %, SoCfc: $socwh Wh, whneed: $whneed, pvfc: $pvfc, rodpvfc: $rodpvfc, confcss: $confcss, SurpDay: $spday Wh, CurrPV: $pvCu W, CurrCons: $curcon W, Limit: $inplim W)"; + my $msg = "CurrSoc: $csoc %, SoCfc: $socwh Wh, whneed: $whneed, pvfc: $pvfc, rodpvfc: $rodpvfc, confcss: $confcss, SurpDay: $spday Wh, CurrPV: $pvCu W, CurrCons: $curcon W, Limit: $inplim W"; if ($num) { - $msg = "(SoCfc: $progsoc % / $socwh Wh, whneed: $whneed, pvfc: $pvfc, rodpvfc: $rodpvfc, confcss: $confcss, SurpDay: $spday Wh)"; + $msg = "SoCfc: $progsoc % / $socwh Wh, whneed: $whneed, pvfc: $pvfc, rodpvfc: $rodpvfc, confcss: $confcss, SurpDay: $spday Wh"; if (!$today) { - $msg = "(SoCfc: $progsoc % / $socwh Wh, whneed: $whneed, pvfc: $pvfc, tompvfc: $tompvfc, tomconfc: $tomconfc, SurpDay: $spday Wh)"; + $msg = "SoCfc: $progsoc % / $socwh Wh, whneed: $whneed, pvfc: $pvfc, tompvfc: $tompvfc, tomconfc: $tomconfc, SurpDay: $spday Wh"; } } else { @@ -10691,7 +10748,7 @@ sub _batChargeRecmd { $data{$name}{nexthours}{'NextHour'.$nhr}{'rcdchargebat'.$bn} = $crel; $data{$name}{nexthours}{'NextHour'.$nhr}{'soc'.$bn} = $progsoc; - debugLog ($paref, 'batteryManagement', "Bat $bn relLoad $stt -> $crel $msg"); + debugLog ($paref, 'batteryManagement', "Bat $bn relLoad $stt -> $crel ($msg)"); } } @@ -12518,8 +12575,8 @@ sub _calcConsForecast_circular { my $hash = $defs{$name}; my $acref = $data{$name}{consumers}; - my $swdfcfc = AttrVal ($name, 'affectConsForecastIdentWeekdays', 0); # nutze nur gleiche Wochentage (Mo...So) für Verbrauchsvorhersage - my $acld = AttrVal ($name, 'affectConsForecastLastDays', CONSFCLDAYS); # Beachtung Stundenwerte der letzten X Tage falls gesetzt + my $swdfcfc = CurrentVal ($name, 'consForecastIdentWeekdays', 0); # nutze nur gleiche Wochentage (Mo...So) für Verbrauchsvorhersage + my $acld = CurrentVal ($name, 'consForecastLastDays', CONSFCLDAYS); # Beachtung Stundenwerte der letzten X Tage falls gesetzt my $dt = timestringsFromOffset ($t, 86400); my $tomdayname = $dt->{dayname}; # Wochentagsname kommender Tag @@ -12800,8 +12857,7 @@ sub __evaluateArray { my $tname = $paref->{tname}; # Thresholdname, z.B. powerTrigger my $tholds = $paref->{tholds}; # Triggervorgaben, z.B. aus Reading powerTrigger - my $hash = $defs{$name}; - my $aaref = CurrentVal ($hash, $cobj, ''); + my $aaref = CurrentVal ($name, $cobj, ''); my @aa = (); @aa = @{$aaref} if (ref $aaref eq 'ARRAY'); @@ -12885,7 +12941,7 @@ sub _calcTodayPVdeviation { my $dp; - if (AttrVal ($name, 'ctrlGenPVdeviation', 'daily') eq 'daily') { + if (CurrentVal ($name, 'genPVdeviation', 'daily') eq 'daily') { my $sstime = timestringToTimestamp ($date.' '.ReadingsVal ($name, "Today_SunSet", '22:00').':00'); return if($t < $sstime); @@ -12895,7 +12951,7 @@ sub _calcTodayPVdeviation { my $pvfcd = ReadingsNum ($name, 'RestOfDayPVforecast', 0) - $pvfc; # PV Prognose bis jetzt return if(!$pvfcd); # Illegal division by zero verhindern - $dp = sprintf "%.2f", (100 - (100 * $pvre / abs $pvfcd)); # V 1.25.0 + $dp = sprintf "%.2f", (100 - (100 * $pvre / abs $pvfcd)); # V 1.25.0 } $data{$name}{circular}{99}{tdayDvtn} = $dp; @@ -13728,17 +13784,17 @@ sub entryGraphic { wlalias => AttrVal ($name, 'alias', $name), sheader => AttrNum ($name, 'graphicHeaderShow', 1), # Anzeigen des Grafik Headers hdrDetail => AttrVal ($name, 'graphicHeaderDetail', 'all'), # ermöglicht den Inhalt zu begrenzen, um bspw. passgenau in ftui einzubetten - flowgsize => CurrentVal ($hash, 'size', FLOWGSIZEDEF), # Größe Energieflußgrafik - flowgani => CurrentVal ($hash, 'animate', 1), # Animation Energieflußgrafik - flowgxshift => CurrentVal ($hash, 'shiftx', 0), # X-Verschiebung der Flußgrafikbox (muß negiert werden) - flowgyshift => CurrentVal ($hash, 'shifty', 0), # Y-Verschiebung der Flußgrafikbox (muß negiert werden) - flowgcons => CurrentVal ($hash, 'showconsumer', 1), # Verbraucher in der Energieflußgrafik anzeigen - flowgconX => CurrentVal ($hash, 'showconsumerdummy', 1), # Dummyverbraucher in der Energieflußgrafik anzeigen - flowgconsPower => CurrentVal ($hash, 'showconsumerpower', 1), # Verbraucher Leistung in der Energieflußgrafik anzeigen - flowgconsTime => CurrentVal ($hash, 'showconsumerremaintime', 1), # Verbraucher Restlaufeit in der Energieflußgrafik anzeigen - flowgconsDist => CurrentVal ($hash, 'consumerdist', FGCDDEF), # Abstand Verbrauchericons zueinander - flowgh2cDist => CurrentVal ($hash, 'h2consumerdist', 0), # Erweiterung des vertikalen Abstandes Haus -> Consumer - genpvdva => AttrVal ($name, 'ctrlGenPVdeviation', 'daily'), # Methode der Abweichungsberechnung + flowgsize => CurrentVal ($name, 'size', FLOWGSIZEDEF), # Größe Energieflußgrafik + flowgani => CurrentVal ($name, 'animate', 1), # Animation Energieflußgrafik + flowgxshift => CurrentVal ($name, 'shiftx', 0), # X-Verschiebung der Flußgrafikbox (muß negiert werden) + flowgyshift => CurrentVal ($name, 'shifty', 0), # Y-Verschiebung der Flußgrafikbox (muß negiert werden) + flowgcons => CurrentVal ($name, 'showconsumer', 1), # Verbraucher in der Energieflußgrafik anzeigen + flowgconX => CurrentVal ($name, 'showconsumerdummy', 1), # Dummyverbraucher in der Energieflußgrafik anzeigen + flowgconsPower => CurrentVal ($name, 'showconsumerpower', 1), # Verbraucher Leistung in der Energieflußgrafik anzeigen + flowgconsTime => CurrentVal ($name, 'showconsumerremaintime', 1), # Verbraucher Restlaufeit in der Energieflußgrafik anzeigen + flowgconsDist => CurrentVal ($name, 'consumerdist', FGCDDEF), # Abstand Verbrauchericons zueinander + flowgh2cDist => CurrentVal ($name, 'h2consumerdist', 0), # Erweiterung des vertikalen Abstandes Haus -> Consumer + genpvdva => CurrentVal ($name, 'genPVdeviation', 'daily'), # Methode der Abweichungsberechnung lang => getLang ($hash), debug => getDebug ($hash), # Debug Module }; @@ -16480,7 +16536,8 @@ END1 if (defined $car && CurrentVal ($name, 'homenodedyncol', 0)) { $car = 100 - $car; - my $pahcol = '#'.substr (Color::pahColor (0, 50, 100, $car, [102,205,0, 050,205,050, 247,203,159, 247,148,111, 255,51,15]), 0, 6); + #my $pahcol = '#'.substr (Color::pahColor (0, 50, 100, $car, [102,205,0, 050,205,050, 247,203,159, 247,148,111, 255,51,15]), 0, 6); + my $pahcol = '#'.__dynColor ($car, 0, 50, 100); # V 1.49.5 ($hicon, my $col) = split '@', $hicon; $hicon = $hicon.'@'.$pahcol; } @@ -17021,14 +17078,18 @@ sub __substituteIcon { return ($icon, $txt); } -################################################################ +################################################################### # liefert eine dynamische Farbe abhängig von "$val" zurück # https://www.w3schools.com/colors/colors_picker.asp -################################################################ +# https://wiki.fhem.de/wiki/Color#Skalenfarbe_mit_Color::pahColor +################################################################### sub __dynColor { my $val = shift; + my $beg = shift // 0; + my $mid = shift // 200; + my $end = shift // 400; - my $color = substr (Color::pahColor (0, 200, 400, $val, [102,205,0, 127,255,0, 251,158,4, 255,127,0, 255,0,0]), 0, 6); + my $color = substr (Color::pahColor ($beg, $mid, $end, $val, [40,198,45, 127,255,0, 251,158,4, 255,127,0, 255,0,0]), 0, 6); return $color; } @@ -19852,8 +19913,7 @@ sub checkPlantConfig { } if (isSolCastUsed ($hash)) { # allg. Settings bei Nutzung SolCast API - my $gdn = AttrVal ('global', 'dnsServer', ''); - my $osi = AttrVal ($name, 'ctrlSolCastAPIoptimizeReq', 0); + my $gdn = AttrVal ('global', 'dnsServer', ''); my $lam = StatusAPIVal ($hash, 'SolCast', '?All', 'response_message', 'success'); @@ -19863,13 +19923,6 @@ sub checkPlantConfig { $result->{'Common Settings'}{note} .= qq{set pvCorrectionFactor_Auto to "on_complex" is recommended if the SolCast efficiency factor is already adjusted.
}; } - if (!$osi) { - $result->{'Common Settings'}{state} = $warn; - $result->{'Common Settings'}{result} .= qq{Attribute ctrlSolCastAPIoptimizeReq is set to "$osi"
}; - $result->{'Common Settings'}{note} .= qq{set ctrlSolCastAPIoptimizeReq to "1" is recommended.
}; - $result->{'Common Settings'}{warn} = 1; - } - if ($lam =~ /You have exceeded your free daily limit/i) { $result->{'API Access'}{state} = $warn; $result->{'API Access'}{result} .= qq{The last message from SolCast API is:
"$lam"
}; @@ -19893,7 +19946,7 @@ sub checkPlantConfig { if (!$result->{'Common Settings'}{fault}) { $result->{'Common Settings'}{result} .= $hqtxt{fulfd}{$lang}.'
'; $result->{'Common Settings'}{note} .= qq{
checked parameters and attributes:
}; - $result->{'Common Settings'}{note} .= qq{pvCorrectionFactor_Auto, ctrlSolCastAPIoptimizeReq, global dnsServer
}; + $result->{'Common Settings'}{note} .= qq{pvCorrectionFactor_Auto, global->dnsServer
}; } } @@ -19959,12 +20012,12 @@ sub checkPlantConfig { if (!$result->{'Common Settings'}{fault}) { $result->{'Common Settings'}{result} .= $hqtxt{fulfd}{$lang}.'
'; $result->{'Common Settings'}{note} .= qq{
checked parameters and attributes:
}; - $result->{'Common Settings'}{note} .= qq{pvCorrectionFactor_Auto, global dnsServer, vrmCredentials
}; + $result->{'Common Settings'}{note} .= qq{pvCorrectionFactor_Auto, global->dnsServer, vrmCredentials
}; } } if (!$result->{'Common Settings'}{fault}) { - $result->{'Common Settings'}{note} .= qq{global latitude, global longitude, global altitude, global language
}; + $result->{'Common Settings'}{note} .= qq{global->latitude, global->longitude, global->altitude, global->language
}; $result->{'Common Settings'}{note} .= qq{event-on-change-reading, ctrlLanguage
}; } @@ -20802,7 +20855,7 @@ return; sub controller { my $name = shift; - my $interval = AttrVal ($name, 'ctrlInterval', DEFINTERVAL); # 0 wenn manuell gesteuert + my $interval = CurrentVal ($name, 'cycleInterval', DEFINTERVAL); # 0 wenn manuell gesteuert my $idval = IsDisabled ($name); my $disabled = $idval == 1 ? 1 : 0; my $inactive = $idval == 3 ? 1 : 0; @@ -20869,7 +20922,7 @@ sub isPrepared4AI { my $err; if (!isDWDUsed($hash) && !isOpenMeteoUsed($hash)) { - $err = qq(The selected SolarForecast Model cannot use AI support); + $err = qq(Unfortunately, AI support is not possible with the selected radiation API MODEL.); } elsif ($aidtabs) { $err = qq(The Perl module AI::DecisionTree is missing. Please install it with e.g. "sudo apt-get install libai-decisiontree-perl" for AI support); @@ -23857,7 +23910,9 @@ to ensure that the system configuration is correct. bchargewh current SoC (State of Charge) of the battery (Wh) binstcap installed battery capacity (Wh) bpowerin current charging power (W) + bpinmax maximum possible charging power (W) bpowerout current discharge power (W) + bpoutmax maximum possible discharging power (W) @@ -23979,42 +24034,6 @@ to ensure that the system configuration is correct.

      - -
    • affectConsForecastIdentWeekdays
      - If set, only the same weekdays (Mon..Sun) are included in the calculation of the consumption forecast.
      - Otherwise, all weekdays are used equally for the calculation.
      - The number of weekdays included is determined by the attribute - affectConsForecastLastDays.
      - (default: 0) -
    • -
      - - -
    • affectConsForecastLastDays
      - The specified number of historical daily values is included in the calculation of the consumption forecast.
      - For example, with the attribute value “1” only the previous day is taken into account, with the value “14” the previous 14 days.
      - The days actually taken into account may be less than specified if there are not enough values in the internal memory - are available.
      - (default: 60)

      - - Note: With an additionally set attribute - affectConsForecastIdentWeekdays - the specified number of past weekdays of the same type (Mon .. Sun) is taken into account.
      - In this case, if a value of “8” is set, the same weekdays of the past 8 weeks are taken into account. - are taken into account.
      -
    • -
      - - -
    • affectSolCastPercentile <10 | 50 | 90>
      - (only when using Model SolCastAPI)

      - - Selection of the probability range of the delivered SolCast data. - SolCast provides the 10 and 90 percent probability around the forecast mean (50).
      - (default: 50) -
    • -
      -
    • aiControl <Schlüssel1=Wert1> <Schlüssel2=Wert2> ...
      By optionally specifying the following key=value pairs, various properties of the AI support can be @@ -24372,34 +24391,6 @@ to ensure that the system configuration is correct.

    • - -
    • ctrlGenPVdeviation
      - Specifies the method for calculating the deviation between predicted and real PV generation. - The Reading Today_PVdeviation is created depending on this setting.

      - -
        - - - - -
        daily Calculation and creation of Today_PVdeviation is done after sunset (default)
        continuously Calculation and creation of Today_PVdeviation is done continuously
        -
      -

    • - - -
    • ctrlInterval <Sekunden>
      - Repetition interval of the data collection.
      - If ctrlInterval is explicitly set to “0”, no regular data collection takes place and must be started externally - with “get <name> data”.
      - (default: 70) -

      - - Note: Regardless of the set interval (even with “0”), data is collected automatically a few seconds - before the end and after the start of a full hour.
      - Furthermore, data is collected automatically when an event from a device defined as “asynchron” - device (consumer, meter, etc.) is received and processed. -

    • -
    • ctrlLanguage <DE | EN>
      Defines the used language of the device. The language definition has an effect on the module graphics and various @@ -24452,17 +24443,6 @@ to ensure that the system configuration is correct.

    • - -
    • ctrlSolCastAPIoptimizeReq
      - (only when using Model SolCastAPI)

      - - The default retrieval interval of the SolCast API is 1 hour. If this attribute is set, the interval is dynamically - adjustment of the interval with the goal to use the maximum possible fetches within - sunrise and sunset.
      - (default: 0) -
    • -
      -
    • ctrlSpecialReadings
      Readings are created for the selected key figures and indicators with the @@ -24513,8 +24493,8 @@ to ensure that the system configuration is correct.
    • ctrlUserExitFn {<Code>}
      - After each cycle (see the ctrlInterval attribute), the code given - in this attribute is executed. The code is to be enclosed in curly brackets {...}.
      + After each cycle (see the plantControl->cycleInterval attribute), + the code given in this attribute is executed. The code is to be enclosed in curly brackets {...}.
      The code is passed the variables $name and $hash, which contain the name of the SolarForecast device and its hash.
      In the SolarForecast Device, readings can be created and modified using the storeReading function. @@ -24934,41 +24914,66 @@ to ensure that the system configuration is correct.
    • plantControl <Schlüssel1=Wert1> <Schlüssel2=Wert2> ...
      By optionally specifying the 'Key=Value' pairs listed below, various properties of the overall - properties of the overall system can be set.
      + properties of the overall system can be set. The entry can be made in several lines.

        - - - - - - - - - - - - - - - - - - - - - - - -
        batteryPreferredCharge Consumers with the can mode are only switched on when the specified battery charge (%) is reached.
        Consumers with the must mode do not observe the priority charging of the battery.
        Wert: Integer 0..100, default: 0
        feedinPowerLimit Feed-in limit of the entire system into the public grid in watts.
        SolarForecast does not limit the feed-in, but uses this information
        within the battery charge management to avoid system curtailment.
        Value: Integer, default: unlimited
        consForecastInPlanning The key determines the procedure for scheduling registered consumers.
        0 - the consumers are scheduled on the basis of the PV forecast (default)
        1 - consumers are scheduled on the basis of the PV forecast and the consumption forecast
        showLink Display of a link to the detailed view of the device above the graphics area
        0 - Display off, 1 - Display on, default: 0
        backupFilesKeep Defines the number of generations of backup files.
        (see set <name> operatingMemory backup)
        If ctrlBackupFilesKeep explit is set to '0', no automatic generation and cleanup of backup files takes place.
        Manual execution with the aforementioned set command is still possible.
        Wert: Integer, default: 3
        + + backupFilesKeep Defines the number of generations of backup files. + (see set <name> operatingMemory backup) + If ctrlBackupFilesKeep explit is set to '0', no automatic generation and cleanup of backup files takes place. + Manual execution with the aforementioned set command is still possible. + Value: Integer, default: 3 + + batteryPreferredCharge Consumers with the can mode are only switched on when the specified battery charge (%) is reached. + Consumers with the must mode do not observe the priority charging of the battery. + Value: Integer 0..100, default: 0 + + consForecastIdentWeekdays If set, only the same weekdays (Mon..Sun) are included in the calculation of the consumption forecast. + Otherwise, all weekdays are used equally for the calculation. + Value: 0|1, default: 0 + + consForecastInPlanning The key determines the procedure for scheduling registered consumers. + 0 - the consumers are scheduled on the basis of the PV forecast (default) + 1 - consumers are scheduled on the basis of the PV forecast and the consumption forecast + + consForecastLastDays The specified number of historical days is included in the calculation of the consumption forecast. + For example, with the attribute value “1” only the previous day is taken into account, with the value “14” the previous 14 days. + The days taken into account may be fewer if there are not enough values in the internal memory. + If the key ‘consForecastIdentWeekdays’ is also set, the specified number of past weekdays + of the same day (Mon .. Sun) is taken into account. + For example, if the value is set to ‘8’, the same weekdays of the past 8 weeks are taken into account. + Value: Integer 0..180, default: 60 + + cycleInterval Repetition interval of the data collection in seconds. + If cycleInterval is explicitly set to ‘0’, there is no regular data collection and must be started externally + with ‘get <name> data’. + Value: Integer, default: 70 + Note: Regardless of the interval set (even with ‘0’), data is collected automatically a few seconds before the end + and after the start of a full hour. Data is also collected automatically when an event from a device defined + as “asynchronous” (consumer, meter, etc.) is received and processed. + + feedinPowerLimit Feed-in limit of the entire system into the public grid in watts. + SolarForecast does not limit the feed-in, but uses this information + within the battery charge management to avoid system curtailment. + Value: Integer, default: unlimited + + genPVdeviation Defines the method for calculating the deviation between forecast and actual PV generation. + The reading Today_PVdeviation is created depending on this setting. + daily - Calculation and creation of Today_PVdeviation takes place after sunset (default) + continuously - Calculation and creation of Today_PVdeviation is continuous + + showLink Display of a link to the detailed view of the device above the graphics area + 0 - Display off, 1 - Display on, default: 0 + +
        Beispiel:
        - attr <name> plantControl feedinPowerLimit=4800 consForecastInPlanning=1 showLink=1 backupFilesKeep=2 + attr <name> plantControl feedinPowerLimit=4800 consForecastInPlanning=1 showLink=1 backupFilesKeep=2 consForecastIdentWeekdays=1 consForecastLastDays=8 genPVdeviation=continuously
    • @@ -24976,7 +24981,8 @@ to ensure that the system configuration is correct.
    • setupBatteryDevXX <Battery Device Name> pin=<Readingname>:<Unit> pout=<Readingname>:<Unit> - cap=<Option> [intotal=<Readingname>:<Unit>] [outtotal=<Readingname>:<Unit>] + cap=<Option> [pinmax=<Integer>] [poutmax=<Integer>] + [intotal=<Readingname>:<Unit>] [outtotal=<Readingname>:<Unit>] [charge=<Readingname>] [asynchron=<Option>] [show=<Option>]
      [[icon=<recomm>@<Color>]:[<charge>@<Color>]:[<discharge>@<Color>]:[<omit>@<Color>]]


      @@ -24992,6 +24998,10 @@ to ensure that the system configuration is correct. pout Reading which provides the current battery discharge rate + pinmax the maximum possible charging power in watts (optional) + + poutmax the maximum possible discharge power in watts (optional) + intotal Reading which provides the total battery charge as a continuous counter (optional) If the reading violates the specification of a continuously rising counter, SolarForecast handles this error and reports the situation that has occurred with a log entry with verbose 2. @@ -25019,7 +25029,7 @@ to ensure that the system configuration is correct. 0 - no display of the device (default) 1..3[:top|bottom] - display of the device in level 1,2 or 3 (above|below) the bar - asynchron Data collection mode according to the ctrlInterval setting (synchronous) or additionally by + asynchron Data collection mode according to the plantControl->cycleInterval setting (synchronous) or additionally by event processing (asynchronous). 0 - no data collection after receiving an event from the device (default) 1 - trigger a data collection when an event is received from the device @@ -25091,7 +25101,7 @@ to ensure that the system configuration is correct. <Day> - Icon and optional color for activity after sunrise <Night> - Icon and optional color after sunset, otherwise the moon phase is displayed - asynchron Data collection mode according to the ctrlInterval setting (synchronous) or additionally by + asynchron Data collection mode according to the plantControl->cycleInterval setting (synchronous) or additionally by event processing (asynchronous). (optional) 0 - no data collection after receiving an event from the device (default) 1 - trigger a data collection when an event is received from the device @@ -25162,7 +25172,7 @@ to ensure that the system configuration is correct. <Reading>:<Currency> - Reading of the meter device that contains the remuneration : Currency <Device>:<Reading>:<Currency> - any device and reading containing the remuneration : Currency - asynchron Data collection mode according to the ctrlInterval setting (synchronous) or additionally by + asynchron Data collection mode according to the plantControl->cycleInterval setting (synchronous) or additionally by event processing (asynchronous). 0 - no data collection after receiving an event from the device (default) 1 - trigger a data collection when an event is received from the device @@ -25282,8 +25292,7 @@ to ensure that the system configuration is correct. A rooftop is equivalent to one setupInverterStrings in the SolarForecast context.
      Free API usage is limited to one daily rate API requests. The number of defined strings (rooftops) - increases the number of API requests required. The module optimizes the query cycles with the attribute - ctrlSolCastAPIoptimizeReq . + increases the number of API requests required. The module optimizes the query cycles automatically.

      ForecastSolar-API
      @@ -26372,7 +26381,9 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. bchargewh aktueller SoC (State of Charge) der Batterie (Wh) binstcap installierte Batteriekapazität (Wh) bpowerin momentane Ladeleistung (W) + bpinmax maximal mögliche Ladeleistung (W) bpowerout momentane Entladeleistung (W) + bpoutmax maximal mögliche Entladeleistung (W)
    @@ -26492,43 +26503,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.

        - -
      • affectConsForecastIdentWeekdays
        - Wenn gesetzt, werden zur Berechnung der Verbrauchsprognose nur gleiche Wochentage (Mo..So) einbezogen.
        - Anderenfalls werden alle Wochentage gleichberechtigt zur Kalkulation verwendet.
        - Die Anzahl der einbezogenen Wochentage wird durch das Attribut - affectConsForecastLastDays - bestimmt.
        - (default: 0) -
      • -
        - - -
      • affectConsForecastLastDays
        - Es wird die angegebene Anzahl historischer Tageswerte bei der Berechnung der Verbrauchsprognose einbezogen.
        - So wird z.B. mit dem Attributwert "1" nur der vorangegangene Tag berücksichtigt, mit dem Wert "14" die vergangenen 14 Tage.
        - Die tatsächlich berücksichtigten Tage können geringer als angegeben sein wenn noch nicht genügend Werte im internen Speicher - vorhanden sind.
        - (default: 60)

        - - Hinweis: Bei einem zusätzlich gesetzten Attribut - affectConsForecastIdentWeekdays - wird die angegebene Anzahl vergangener gleicher Wochentage (Mo .. So) berücksichtigt.
        - In diesem Fall werden bei einem gesetzten Wert von "8" die gleichen Wochentage der vergangenen 8 Wochen - berücksichtigt.
        -
      • -
        - - -
      • affectSolCastPercentile <10 | 50 | 90>
        - (nur bei Verwendung Model SolCastAPI)

        - - Auswahl des Wahrscheinlichkeitsbereiches der gelieferten SolCast-Daten. - SolCast liefert die 10- und 90-prozentige Wahrscheinlichkeit um den Prognosemittelwert (50) herum.
        - (default: 50) -
      • -
        -
      • aiControl <Schlüssel1=Wert1> <Schlüssel2=Wert2> ...
        Durch die optionale Angabe der nachfolgend aufgeführten Schlüssel=Wert Paare können verschiedene @@ -26886,34 +26860,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.

      • - -
      • ctrlGenPVdeviation
        - Legt die Methode zur Berechnung der Abweichung von prognostizierter und realer PV Erzeugung fest. - Das Reading Today_PVdeviation wird in Abhängigkeit dieser Einstellung erstellt.

        - -
          - - - - -
          daily Berechnung und Erstellung von Today_PVdeviation erfolgt nach Sonnenuntergang (default)
          continuously Berechnung und Erstellung von Today_PVdeviation erfolgt fortlaufend
          -
        -

      • - - -
      • ctrlInterval <Sekunden>
        - Wiederholungsintervall der Datensammlung.
        - Ist ctrlInterval explizit auf "0" gesetzt, erfolgt keine regelmäßige Datensammlung und muss mit - "get <name> data" extern gestartet werden.
        - (default: 70) -

        - - Hinweis: Unabhängig vom eingestellten Intervall (auch bei "0") erfolgt einige Sekunden vor dem Ende - sowie nach dem Beginn einer vollen Stunde eine automatische Datensammlung.
        - Weiterhin erfolgt eine automatische Datensammlung wenn ein Event eines als "asynchron" - definierten Gerätes (Consumer, Meter, etc.) empfangen und verarbeitet wird. -

      • -
      • ctrlLanguage <DE | EN>
        Legt die benutzte Sprache des Devices fest. Die Sprachendefinition hat Auswirkungen auf die Modulgrafik und @@ -26966,17 +26912,6 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.

      • - -
      • ctrlSolCastAPIoptimizeReq
        - (nur bei Verwendung Model SolCastAPI)

        - - Das default Abrufintervall der SolCast API beträgt 1 Stunde. Ist dieses Attribut gesetzt erfolgt ein dynamische - Anpassung des Intervalls mit dem Ziel die maximal möglichen Abrufe innerhalb von Sonnenauf- und untergang - auszunutzen.
        - (default: 0) -
      • -
        -
      • ctrlSpecialReadings
        Für die ausgewählten Kennzahlen und Indikatoren werden Readings mit dem @@ -27027,8 +26962,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
      • ctrlUserExitFn {<Code>}
        - Nach jedem Zyklus (siehe Attribut ctrlInterval ) wird der in diesem - Attribut abgegebene Code ausgeführt. Der Code ist in geschweifte Klammern {...} einzuschließen.
        + Nach jedem Zyklus (siehe Attribut plantControl->cycleInterval) wird der in + diesem Attribut abgegebene Code ausgeführt. Der Code ist in geschweifte Klammern {...} einzuschließen.
        Dem Code werden die Variablen $name und $hash übergeben, die den Namen des SolarForecast Device und dessen Hash enthalten.
        Im SolarForecast Device können Readings über die Funktion storeReading erzeugt und geändert werden. @@ -27445,41 +27380,66 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
      • plantControl <Schlüssel1=Wert1> <Schlüssel2=Wert2> ...
        Durch die optionale Angabe der nachfolgend aufgeführten 'Schlüssel=Wert' Paare können verschiedene - Eigenschaften der Gesamtanlage eingestellt werden.
        + Eigenschaften der Gesamtanlage eingestellt werden. Die Eingabe kann mehrzeilig erfolgen.

          - - - - - - - - - - - - - - - - - - - - - - - -
          batteryPreferredCharge Verbraucher mit dem Mode can werden erst dann eingeschaltet, wenn die angegebene Batterieladung (%) erreicht ist.
          Verbraucher mit dem Mode must beachten die Vorrangladung der Batterie nicht.
          Wert: Ganzzahl 0..100, default: 0
          feedinPowerLimit Einspeiselimit der Gesamtanlage in das öffentliche Netz in Watt.
          SolarForecast limitiert die Einspeisung nicht, verwendet diese Angabe jedoch
          innerhalb des Batterie-Lademanagements zur Vermeidung einer Anlagenabregelung.
          Wert: Ganzzahl, default: unbegrent
          consForecastInPlanning Der Schlüssel bestimmt die Vorgehensweise bei der Einplanung der registrierten Verbraucher.
          0 - die Einplanung der Verbraucher erfolgt auf Grundlage der PV Prognose (default)
          1 - die Einplanung der Verbraucher erfolgt auf Grundlage der PV Prognose und der Prognose des Verbrauchs
          showLink Anzeige eines Links zur Detailansicht des Device über dem Grafikbereich
          0 - Anzeige aus, 1 - Anzeige an, default: 0
          backupFilesKeep Legt die Anzahl der Generationen von Sicherungsdateien fest.
          (siehe set <name> operatingMemory backup)
          Ist ctrlBackupFilesKeep explit auf '0' gesetzt, erfolgt keine automatische Generierung und Bereinigung von Sicherungsdateien.
          Eine manuelle Ausführung mit dem genannten Set-Kommando ist weiterhin möglich.
          Wert: Ganzzahl, default: 3
          + + backupFilesKeep Legt die Anzahl der Generationen von Sicherungsdateien fest. + (siehe set <name> operatingMemory backup) + Ist ctrlBackupFilesKeep explit auf '0' gesetzt, erfolgt keine automatische Generierung und Bereinigung von Sicherungsdateien. + Eine manuelle Ausführung mit dem genannten Set-Kommando ist weiterhin möglich. + Wert: Ganzzahl, default: 3 + + batteryPreferredCharge Verbraucher mit dem Mode can werden erst dann eingeschaltet, wenn die angegebene Batterieladung (%) erreicht ist. + Verbraucher mit dem Mode must beachten die Vorrangladung der Batterie nicht. + Wert: Ganzzahl 0..100, default: 0 + + consForecastIdentWeekdays Wenn gesetzt, werden zur Berechnung der Verbrauchsprognose nur gleiche Wochentage (Mo..So) einbezogen. + Anderenfalls werden alle Wochentage gleichberechtigt zur Kalkulation verwendet. + Wert: 0|1, default: 0 + + consForecastInPlanning Der Schlüssel bestimmt die Vorgehensweise bei der Einplanung der registrierten Verbraucher. + 0 - die Einplanung der Verbraucher erfolgt auf Grundlage der PV Prognose (default) + 1 - die Einplanung der Verbraucher erfolgt auf Grundlage der PV Prognose und der Prognose des Verbrauchs + + consForecastLastDays Es wird die angegebene Anzahl historischer Tage bei der Berechnung der Verbrauchsprognose einbezogen. + So wird z.B. mit dem Attributwert "1" nur der vorangegangene Tag berücksichtigt, mit dem Wert '14' die vergangenen 14 Tage. + Die berücksichtigten Tage können geringer ausfallen, wenn noch nicht genügend Werte im internen Speicher vorhanden sind. + Bei einem zusätzlich gesetzten Schlüssel 'consForecastIdentWeekdays' wird die angegebene Anzahl vergangener + gleicher Wochentage (Mo .. So) berücksichtigt. + Zum Beispiel werden dann bei einem gesetzten Wert von '8' die gleichen Wochentage der vergangenen 8 Wochen berücksichtigt. + Wert: Ganzzahl 0..180, default: 60 + + cycleInterval Wiederholungsintervall der Datensammlung in Sekunden. + Ist cycleInterval explizit auf '0' gesetzt, erfolgt keine regelmäßige Datensammlung und muss mit 'get <name> data' + extern gestartet werden. + Wert: Ganzzahl, default: 70 + Hinweis: Unabhängig vom eingestellten Intervall (auch bei '0') erfolgt einige Sekunden vor dem Ende + sowie nach dem Beginn einer vollen Stunde eine automatische Datensammlung. Weiterhin erfolgt eine automatische Datensammlung + wenn ein Event eines als "asynchron" definierten Gerätes (Consumer, Meter, etc.) empfangen und verarbeitet wird. + + feedinPowerLimit Einspeiselimit der Gesamtanlage in das öffentliche Netz in Watt. + SolarForecast limitiert die Einspeisung nicht, verwendet diese Angabe jedoch + innerhalb des Batterie-Lademanagements zur Vermeidung einer Anlagenabregelung. + Wert: Ganzzahl, default: unbegrent + + genPVdeviation Legt die Methode zur Berechnung der Abweichung von prognostizierter und realer PV Erzeugung fest. + Das Reading Today_PVdeviation wird in Abhängigkeit dieser Einstellung erstellt. + daily - Berechnung und Erstellung von Today_PVdeviation erfolgt nach Sonnenuntergang (default) + continuously - Berechnung und Erstellung von Today_PVdeviation erfolgt fortlaufend + + showLink Anzeige eines Links zur Detailansicht des Device über dem Grafikbereich + 0 - Anzeige aus, 1 - Anzeige an, default: 0 + +
          Beispiel:
          - attr <name> plantControl feedinPowerLimit=4800 consForecastInPlanning=1 showLink=1 backupFilesKeep=2 + attr <name> plantControl feedinPowerLimit=4800 consForecastInPlanning=1 showLink=1 backupFilesKeep=2 consForecastIdentWeekdays=1 consForecastLastDays=8 genPVdeviation=continuously
      • @@ -27487,7 +27447,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
      • setupBatteryDevXX <Batterie Device Name> pin=<Readingname>:<Einheit> pout=<Readingname>:<Einheit> - cap=<Option> [intotal=<Readingname>:<Einheit>] [outtotal=<Readingname>:<Einheit>] + cap=<Option> [pinmax=<Ganzzahl>] [poutmax=<Ganzzahl>] + [intotal=<Readingname>:<Einheit>] [outtotal=<Readingname>:<Einheit>] [charge=<Readingname>] [asynchron=<Option>] [show=<Option>]
        [[icon=<empfohlen>@<Farbe>]:[<aufladen>@<Farbe>]:[<entladen>@<Farbe>]:[icon=<unterlassen>@<Farbe>]]


        @@ -27503,6 +27464,10 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. pout Reading welches die aktuelle Batterieentladeleistung liefert + pinmax die maximal mögliche Ladeleistung in Watt (optional) + + poutmax die maximal mögliche Entladeleistung in Watt (optional) + intotal Reading welches die totale Batterieladung als fortlaufenden Zähler liefert (optional) Sollte des Reading die Vorgabe eines stetig aufsteigenden Zählers verletzen, behandelt SolarForecast diesen Fehler und meldet die aufgetretene Situation durch einen Logeintrag mit verbose 2. @@ -27529,8 +27494,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. 0 - keine Anzeige des Gerätes (default) 1..3[:top|bottom] - Anzeige des Gerätes in der Ebene 1,2 oder 3 (über|unter) den Balken - asynchron Modus der Datensammlung entsprechend Einstellung ctrlInterval (synchron) oder zusätzlich durch - Eventverarbeitung (asynchron). + asynchron Modus der Datensammlung entsprechend Einstellung plantControl->cycleInterval (synchron) oder + zusätzlich durch Eventverarbeitung (asynchron). 0 - keine Datensammlung nach Empfang eines Events des Gerätes (default) 1 - auslösen einer Datensammlung bei Empfang eines Events des Gerätes @@ -27602,8 +27567,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. <Tag> - Icon und ggf. Farbe bei Aktivität nach Sonnenaufgang <Nacht> - Icon und ggf. Farbe nach Sonnenuntergang, sonst wird die Mondphase angezeigt - asynchron Modus der Datensammlung entsprechend Einstellung ctrlInterval (synchron) oder zusätzlich durch - Eventverarbeitung (asynchron). (optional) + asynchron Modus der Datensammlung entsprechend Einstellung plantControl->cycleInterval (synchron) oder + zusätzlich durch Eventverarbeitung (asynchron). (optional) 0 - keine Datensammlung nach Empfang eines Events des Gerätes (default) 1 - auslösen einer Datensammlung bei Empfang eines Events des Gerätes @@ -27674,7 +27639,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. <Reading>:<Währung> - Reading des Meter Device das die Vergütung enthält : Währung <Device>:<Reading>:<Währung> - beliebiges Device und Reading welches die Vergütung enthält : Währung - asynchron Modus der Datensammlung entsprechend Einstellung ctrlInterval (synchron) oder zusätzlich durch + asynchron Modus der Datensammlung entsprechend Einstellung plantControl->cycleInterval (synchron) oder zusätzlich durch Eventverarbeitung (asynchron). 0 - keine Datensammlung nach Empfang eines Events des Gerätes (default) 1 - auslösen einer Datensammlung bei Empfang eines Events des Gerätes @@ -27795,8 +27760,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. Ein Rooftop ist im SolarForecast-Kontext mit einem setupInverterString gleichzusetzen.
        Die kostenfreie API-Nutzung ist auf eine Tagesrate API-Anfragen begrenzt. Die Anzahl definierter Strings (Rooftops) - erhöht die Anzahl erforderlicher API-Anfragen. Das Modul optimiert die Abfragezyklen mit dem Attribut - ctrlSolCastAPIoptimizeReq . + erhöht die Anzahl erforderlicher API-Anfragen. Das Modul optimiert die Abfragezyklen automatisch.

        ForecastSolar-API