diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm index b0e5fff32..aedfd7a0a 100644 --- a/fhem/contrib/DS_Starter/76_SolarForecast.pm +++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm @@ -160,9 +160,10 @@ BEGIN { # Versions History intern my %vNotesIntern = ( - "1.52.5" => "22.05.2025 edit commandref, _batChargeMgmt: add load management time slot, ctrlBatSocManagementXX: new key lcSlot ". + "1.52.5" => "25.05.2025 edit commandref, _batChargeMgmt: add load management time slot, ctrlBatSocManagementXX: new key lcSlot ". "check attribute values for prohibited occurrence [...] Forum: https://forum.fhem.de/index.php?msg=1342147 ". - "_flowGraphic: bugfix chain style in case of logical on/off Forum: https://forum.fhem.de/index.php?msg=1342122 ", + "_flowGraphic: bugfix chain style in case of logical on/off Forum: https://forum.fhem.de/index.php?msg=1342122 ". + "_attrBatteryDev: more checks (cap) ", "1.52.4" => "20.05.2025 commandref edited, setupInverterDevXX: change pv to pvOut, new key pvIn ". "fix devision by zero -Forum: https://forum.fhem.de/index.php?msg=1341884, __calcFcQuality: minor code change ". "ctrlSpecialReadings: new Topic BatWeightedTotalSOC ", @@ -7339,22 +7340,26 @@ sub _attrBatteryDev { ## no critic "not used" my $bn = (split 'setupBatteryDev', $aName)[1]; my $valid = { - pin => '', - pout => '', - pinmax => '', - poutmax => '', - intotal => '', - outtotal => '', - cap => '', - charge => '', - icon => '', - show => '', - asynchron => '', + pin => { comp => '.+', must => 1, act => 0 }, + pout => { comp => '.+', must => 1, act => 0 }, + pinmax => { comp => '\d+', must => 0, act => 0 }, + poutmax => { comp => '\d+', must => 0, act => 0 }, + intotal => { comp => '.*', must => 0, act => 0 }, + outtotal => { comp => '.*', must => 0, act => 0 }, + cap => { comp => '((?:\d+$|(?!\d+(?:\.\d+)?:)[^:]+:(?:k?Wh)$))', must => 1, act => 0 }, + charge => { comp => '.*', must => 0, act => 0 }, + icon => { comp => '.*', must => 0, act => 0 }, + show => { comp => '(?:[0-3](?::(?:top|bottom))?)', must => 0, act => 0 }, + asynchron => { comp => '(0|1)', must => 0, act => 0 }, }; if ($paref->{cmd} eq 'set') { my ($err, $badev, $h) = isDeviceValid ( { name => $name, obj => $aVal, method => 'string' } ); return $err if($err); + + for my $mkey (keys %{$valid}) { + return qq{The key '$mkey' is mandatory for setting in attribute '$aName'} if($valid->{$mkey}{must} && !exists $h->{$mkey}); + } for my $key (keys %{$h}) { return 'The keys entered must not contain square brackets [...]' if($key =~ /[\[\]]+/xs); # Absturzschutz! @@ -7362,29 +7367,30 @@ sub _attrBatteryDev { ## no critic "not used" if (!grep /^$key$/, keys %{$valid}) { return qq{The key '$key' is not a valid key in attribute '$aName'}; } - } + + my $comp = $valid->{$key}{comp}; + next if(!$comp); - 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->{$key} =~ /^$comp$/xs) { + if ($valid->{$key}{act}) { + $paref->{akey} = $key; + $paref->{keyval} = $h->{$key}; - if ($h->{pinmax} && $h->{pinmax} !~ /^\d+$/xs) { - return qq{The key “pinmax” may only be specified by whole numbers}; - } + my $err = __attrKeyAction ($paref); - if ($h->{poutmax} && $h->{poutmax} !~ /^\d+$/xs) { - return qq{The key “poutmax” may only be specified by whole numbers}; - } + delete $paref->{keyval}; + delete $paref->{akey}; - if ($h->{show} && $h->{show} =~ /:/xs) { - my ($show, $pos) = split ':', $h->{show}; - $pos //= 'xx'; - - if ($pos !~ /^(top|bottom)$/xs) { - return qq{The key 'show' is not set correctly. Please note the command reference.}; + return $err if($err); + } + } + else { + return "The key '$key=$h->{$key}' is not specified correctly. Please refer to the command reference."; } } + ## 2. Durchlauf - Endprüfung + ############################# if (($h->{pin} !~ /-/xs && $h->{pin} !~ /:/xs) || ($h->{pout} !~ /-/xs && $h->{pout} !~ /:/xs)) { return qq{The keys 'pin' and/or 'pout' are not set correctly. Please note the command reference.}; @@ -7398,6 +7404,8 @@ sub _attrBatteryDev { ## no critic "not used" delete $data{$name}{batteries}{$bn}{bicon}; delete $data{$name}{batteries}{$bn}{bshowingraph}; delete $data{$name}{batteries}{$bn}{bposingraph}; + delete $data{$name}{batteries}{$bn}{bpinmax}; + delete $data{$name}{batteries}{$bn}{bpoutmax}; } elsif ($paref->{cmd} eq 'del') { readingsDelete ($hash, 'Current_PowerBatIn_'.$bn); @@ -11462,7 +11470,7 @@ sub _batChargeMgmt { my $batinstcap = BatteryVal ($name, $bn, 'binstcap', 0); # installierte Batteriekapazität Wh if (!$inplim || !$batinstcap) { - debugLog ($paref, 'batteryManagement', "WARNING - The requirements for dynamic battery charge recommendation are not met. Exit."); + debugLog ($paref, 'batteryManagement', "WARNING - The requirements for dynamic battery charge recommendation are not met. Check the key 'cap' for Bat '$bn'. Exit."); return; } @@ -11634,10 +11642,10 @@ sub _batChargeMgmt { $data{$name}{nexthours}{'NextHour'.$nhr}{socprogwhsum} = $hsoc{$nhr}{socprogwhsum}; my $today = NexthoursVal ($name, 'NextHour'.$nhr, 'today', 0); - my $hody = NexthoursVal ($name, 'NextHour'.$nhr, 'hourofday', ''); + my $hod = NexthoursVal ($name, 'NextHour'.$nhr, 'hourofday', ''); - if ($today && $hody) { # heutiger Tag - writeToHistory ( { paref => $paref, key => 'socprogwhsum', val => $hsoc{$nhr}{socprogwhsum}, hour => $hody } ); + if ($today && $hod) { # heutiger Tag + writeToHistory ( { paref => $paref, key => 'socprogwhsum', val => $hsoc{$nhr}{socprogwhsum}, hour => $hod } ); } } } @@ -17143,8 +17151,8 @@ sub __batteryOnBeam { my $bpos = BatteryVal ($name, $bn, 'bposingraph', 'totp'); next if($bshow != $paref->{chartlvl} || $bpos ne $paref->{beampos}); # Anzeige nur auf Grafikebene "chartlvl" bzw. oberhalb/unterhalb der Balken - $ret .= ""; # freier Platz am Anfang - my $ii = 0; + $ret .= ""; # freier Platz am Anfang + my $ii = 0; for my $i (0..($maxhours * 2) - 1) { my $skip = __dontNightshowSkipSync ($name, $paref, $i); @@ -17197,7 +17205,7 @@ sub __batteryOnBeam { debugLog ($paref, 'graphic', "Battery $bn pos >$i< day: $day_str, time: $time_str, Power ('-' = out): ".(defined $bpower ? $bpower : 'undef'). " W, Rcmd: ".(defined $hfcg->{$i}{'rcdchargebat'.$bn} ? $hfcg->{$i}{'rcdchargebat'.$bn} : 'undef'). - ", SoC: ".(defined $soc ? $soc : 'undef')." %, lcintime: $lcintime"); + ", SoC: ".(defined $soc ? $soc : 'undef')." %, lcintime: ".(defined $lcintime ? $lcintime : 'undef')); } $ret .= "" if($ret); # freier Platz am Ende der Icon Zeile @@ -25626,6 +25634,10 @@ to ensure that the system configuration is correct. 0 - the stored energy consumption shares are retained as part of the general consumption forecast (default) 1 - the general consumption forecast is reduced by the stored energy consumption shares. 2 - as with '1', but the consumer's planning data is included in the forecast for the coming hours. + Note: When using exconfc, plantControl->consForecastIdentWeekdays=1 and plantControl->consForecastLastDays=4 + should be set. + See the explanations in the German Wiki +
@@ -26358,7 +26370,7 @@ to ensure that the system configuration is correct. this error and reports the situation that has occurred with a log entry with verbose 2. cap installed battery capacity. Option can be: - numerical value - direct specification of the battery capacity in Wh without specifying the unit! + Integer - direct specification of the battery capacity in Wh without specifying the unit! <Readingname>:<unit> - Reading which provides the capacity and unit (Wh, kWh) charge Reading which provides the current state of charge (SOC in percent) (optional) @@ -28229,6 +28241,10 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. 0 - die gespeicherten Energieverbrauchsanteile bleiben als Bestandteil der allgemeinen Verbrauchsprognose erhalten (default) 1 - die allgemeine Verbrauchsprognose wird um die gespeicherten Energieverbrauchsanteile reduziert. 2 - wie bei '1', jedoch gehen die Planungsdaten des Verbrauchers bei der Prognose der kommenden Stunden wieder mit ein. + Hinweis: Bei Verwendung von exconfc sollte plantControl->consForecastIdentWeekdays=1 und plantControl->consForecastLastDays=4 + gesetzt werden. + Siehe dazu die Erläuterungen im Wiki +
@@ -28960,7 +28976,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden. SolarForecast diesen Fehler und meldet die aufgetretene Situation durch einen Logeintrag mit verbose 2. cap installierte Batteriekapazität. Option kann sein: - numerischer Wert - direkte Angabe der Batteriekapazität in Wh ohne die Einheit anzugeben! + Ganzzahl - direkte Angabe der Batteriekapazität in Wh ohne die Einheit anzugeben! <Readingname>:<Einheit> - Reading welches die Kapazität liefert und Einheit (Wh, kWh) charge Reading welches den aktuellen Ladezustand (SOC in Prozent) liefert (optional)