From 0744383100c291bb231eade01db74a3a4d2595c1 Mon Sep 17 00:00:00 2001 From: DS_Starter Date: Tue, 7 Oct 2025 19:37:12 +0000 Subject: [PATCH] 76_SolarForecast: contrib V1.59.1 git-svn-id: https://svn.fhem.de/fhem/trunk@30362 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/DS_Starter/76_SolarForecast.pm | 93 ++++++++++++++------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm index cc3edf356..1059f76bb 100644 --- a/fhem/contrib/DS_Starter/76_SolarForecast.pm +++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm @@ -160,7 +160,7 @@ BEGIN { # Versions History intern my %vNotesIntern = ( - "1.59.1" => "07.10.2025 ", + "1.59.1" => "07.10.2025 fixed transfer at day change, optimal SoC consideration in SoC forecast for optPower strategy ", "1.59.0" => "06.10.2025 new sub __normIconInnerScale to fix problem with chromium engine > 140.x, Forum: https://forum.fhem.de/index.php?msg=1349058 ", "1.58.8" => "06.10.2025 __batChargeOptTargetPower: minor Code change ", "1.58.7" => "05.10.2025 fix negative SoC forecast when using optPower Forum: https://forum.fhem.de/index.php?msg=1348954 ", @@ -11602,10 +11602,11 @@ return $sf; # Erstellung Batterie Ladefreigabe + SoC Prognose ################################################################ sub _batChargeMgmt { - my $paref = shift; - my $name = $paref->{name}; - my $chour = $paref->{chour}; - my $t = $paref->{t}; + my $paref = shift; + my $name = $paref->{name}; + my $chour = $paref->{chour}; + my $minute = $paref->{minute}; # aktuelle Minute (00-59) + my $t = $paref->{t}; return if(!isBatteryUsed ($name)); @@ -11800,7 +11801,7 @@ sub _batChargeMgmt { $spday = 0 if($spday < 0); # PV Überschuß Prognose bis Sonnenuntergang $confc *= (100 - $wou) / 100 if($pvfc > 0); # Gewichtung Prognose-Verbrauch als Anteil "Eigennutzung" (https://forum.fhem.de/index.php?msg=1348429) - my $surpls = sprintf "%.0f", ($pvfc - $confc); # PV-Überschuß der Stunde, wichtig keine Nachkommastellen! + my $surpls = $pvfc - $confc; ## Steuerung nach Ladefreigabe ################################ @@ -11814,14 +11815,14 @@ sub _batChargeMgmt { # Steuerhash für optimimierte Ladeleistung erstellen ###################################################### - my $surplswh = max (0, $surpls); + my $surplswh = max (0, (sprintf "%.0f", $surpls)); # wichtig keine Nachkommastellen! if ($strategy eq 'optPower' || $strategy eq 'loadRelease' && $today) { # bei loadRelease' nur den aktuellen Tag betrachten $hsurp->{$fd}{$hod}{nhr} = $nhr; $hsurp->{$fd}{$hod}{speff} = $surpls; # effektiver PV Überschuß bzw. effektiver Verbrauch wenn < 0 $hsurp->{$fd}{$hod}{surplswh} = $surplswh.'.'.$hod; # absoluter Überschuß in Wh der Stunde mit Sortierhilfe $hsurp->{$fd}{$hod}{$bn}{spday} = $spday; # (Rest)PV-Überschuß am laufenden Tag - $hsurp->{$fd}{$hod}{$bn}{initsocwh} = $socwh; + $hsurp->{$fd}{$hod}{$bn}{initsocwh} = $socwh; # durch LR fortgeschriebener SoC $hsurp->{$fd}{$hod}{$bn}{batinstcap} = $batinstcap; # installierte Batteriekapazität (Wh) $hsurp->{$fd}{$hod}{$bn}{goalwh} = $goalwh; # Ladeziel $hsurp->{$fd}{$hod}{$bn}{bpinmax} = $bpinmax; # max. mögliche Ladeleistung @@ -11838,6 +11839,9 @@ sub _batChargeMgmt { $hsurp->{$fd}{$hod}{$bn}{befficiency} = $befficiency; # Speicherwirkungsgrad } + $surpls = $surpls / 60 * (60 - int $minute) if(!$num); # aktuelle (Rest)-Stunde -> zeitgewichteter PV-Überschuß + $surpls = sprintf "%.0f", $surpls; # wichtig keine Nachkommastellen! + ## SOC-Prognose LR #################### my $speff = $surpls; # effektiver PV Überschuß bzw. effektiver Verbrauch wenn < 0 @@ -11904,9 +11908,11 @@ sub _batChargeMgmt { # leistungsoptimierte (optPower) Beladungssteuerung ##################################################### + my $trans = {}; # Übertrags-Hash Referenz + for my $lfd (0..max (0, keys %{$hsurp})) { $paref->{hsurp} = $hsurp->{$lfd}; - my ($hopt, $otp) = __batChargeOptTargetPower ($paref); + my ($hopt, $otp) = __batChargeOptTargetPower ($paref, $lfd, $trans); delete $paref->{hsurp}; ## Debuglog OTP @@ -11923,7 +11929,7 @@ sub _batChargeMgmt { for my $bat (sort @batteries) { next if(!defined $hopt->{$shod}{$bat}{batinstcap}); - my $ssocwh = $hopt->{$shod}{$bat}{runwh} // '-'; + my $ssocwh = $hopt->{$shod}{$bat}{runwh} // '-'; ## SOC-Prognose OTP ##################### @@ -12018,6 +12024,9 @@ return; ################################################################ sub __batChargeOptTargetPower { my $paref = shift; + my $lfd = shift; # laufender Tag (1..X) + my $trans = shift; # Übertrags-Hash Referenz + my $name = $paref->{name}; my $hsurp = $paref->{hsurp}; # Hashref Überschußhash @@ -12025,6 +12034,7 @@ sub __batChargeOptTargetPower { my @sortedhods = sort { $hsurp->{$a}{surplswh} <=> $hsurp->{$b}{surplswh} } keys %{$hsurp}; # Stunden aufsteigend nach PV-Überschuß sortiert my @batteries = grep { !/^(?:fd|speff|surplswh|nhr)$/xs } keys %{$hsurp->{24}}; my $otp; + my $fcendwh; for my $hod (sort { $a <=> $b } keys %{$hsurp}) { my $nhr = $hsurp->{$hod}{nhr}; @@ -12034,22 +12044,29 @@ sub __batChargeOptTargetPower { my @remaining_hods = grep { int $_ >= int $hod } @sortedhods; - for my $sbn (sort { $a <=> $b } @batteries) { # jede Batterie - my $bpinmax = $hsurp->{$hod}{$sbn}{bpinmax}; # Bat max. mögliche Ladelesitung - my $sbatinstcap = $hsurp->{$hod}{$sbn}{batinstcap}; # Kapa dieser Batterie + for my $sbn (sort { $a <=> $b } @batteries) { # jede Batterie + my $bpinmax = $hsurp->{$hod}{$sbn}{bpinmax}; # Bat max. mögliche Ladelesitung + my $batinstcap = $hsurp->{$hod}{$sbn}{batinstcap}; # Kapa dieser Batterie my $lowSocwh = $hsurp->{$hod}{$sbn}{lowSocwh}; # eingestellter lowSoc in Wh + my $batoptsocwh = $hsurp->{$hod}{$sbn}{batoptsocwh}; # optimaler SoC in Wh my $csocwh = $hsurp->{$hod}{$sbn}{csocwh}; # aktueller SoC in Wh my $bpinreduced = $hsurp->{$hod}{$sbn}{bpinreduced}; # Standardwert bei <=lowSoC -> Anforderungsladung vom Grid my $befficiency = $hsurp->{$hod}{$sbn}{befficiency}; # Speicherwirkungsgrad - my $runwh = defined $hsurp->{$hod}{$sbn}{fcnextwh} ? # Auswahl des zu verwendenden Prognose-SOC (Wh) - $hsurp->{$hod}{$sbn}{fcnextwh} : - ( $nhr eq '00' ? - $csocwh : - $hsurp->{$hod}{$sbn}{initsocwh} - ); + # Initialisierung / Fortschreibung Prognose-SOC (Wh) + ###################################################### + my $fc_next_wh = $hsurp->{$hod}{$sbn}{fcnextwh}; + my $init_soc_wh = $hsurp->{$hod}{$sbn}{initsocwh}; + my $transfer = $trans->{$sbn}{$lfd}{transfer}; - $runwh = min ($runwh, $sbatinstcap); + my $runwh = do { + if (defined $fc_next_wh) { $fc_next_wh } + elsif ($nhr eq '00') { $csocwh } + elsif (defined $transfer) { delete $trans->{$sbn}{$lfd}{transfer} } + else { $init_soc_wh } + }; + + $runwh = min ($runwh, $batinstcap); $hsurp->{$hod}{$sbn}{runwh} = sprintf "%.0f", $runwh; # Startwert für DebugLog ## Ziel und dessen Erreichbarkeit @@ -12072,7 +12089,13 @@ sub __batChargeOptTargetPower { $hsurp->{$hod}{$sbn}{pneedmin} = $bpinmax; $runwh += $hsurp->{$hod}{speff} / $befficiency; # um Verbrauch reduzieren - $hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", max ($lowSocwh, $runwh); # untere Begrenzung auf lowSoC + + $fcendwh = $runwh < $lowSocwh ? $lowSocwh : # fcendwh begrenzen + $runwh < $batoptsocwh ? $batoptsocwh : + $runwh > $batinstcap ? $batinstcap : + $runwh; + + $hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", $fcendwh; $hsurp->{$nexthod}{$sbn}{fcnextwh} = $hsurp->{$hod}{$sbn}{fcendwh} if(defined $nextnhr); # Startwert kommende Stunde if ($nhr eq '00') { @@ -12120,20 +12143,28 @@ sub __batChargeOptTargetPower { $otp->{$sbn}{target} = $target; } - - - $hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", min ($goalwh, $runwh # Endwert Prognose aktuelle Stunde - + $befficiency - * ($nhr eq '00' - ? $otp->{$sbn}{target} - : $spls - ) - ); + $fcendwh = min ($goalwh, $runwh # Endwert Prognose aktuelle Stunde + + $befficiency + * ($nhr eq '00' + ? $otp->{$sbn}{target} + : $spls + ) + ); + + $fcendwh = $runwh < $lowSocwh ? $lowSocwh : # fcendwh begrenzen + $runwh < $batoptsocwh ? $batoptsocwh : + $runwh > $batinstcap ? $batinstcap : + $runwh; - $hsurp->{$nexthod}{$sbn}{fcnextwh} = $hsurp->{$hod}{$sbn}{fcendwh} if(defined $nextnhr); # Startwert kommende Stunde + $hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", $fcendwh; + $hsurp->{$nexthod}{$sbn}{fcnextwh} = $hsurp->{$hod}{$sbn}{fcendwh} if(defined $nextnhr); # Startwert kommende Stunde } } + for my $bat (sort { $a <=> $b } @batteries) { + $trans->{$bat}{$lfd + 1}{transfer} = $hsurp->{24}{$bat}{fcendwh}; # Übertrag SoC-Prognose für kommenden Tag + } + return ($hsurp, $otp); }