76_SolarForecast: new special Reading BatRatio

git-svn-id: https://svn.fhem.de/fhem/trunk@30548 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
DS_Starter
2025-11-22 19:59:56 +00:00
parent 209f66d94f
commit 625f37f317
2 changed files with 90 additions and 59 deletions

View File

@@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # 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 # Do not insert empty lines here, update check depends on it
- feature: 76_SolarForecast: new special Reading BatRatio
- bugfix: 76_SolarForecast: fix consumption till sunset,SOC use of consumption - bugfix: 76_SolarForecast: fix consumption till sunset,SOC use of consumption
- feature: 76_SolarForecast: Version 1.60.5 - feature: 76_SolarForecast: Version 1.60.5
- feature: 76_SolarForecast: Version 1.60.4 - feature: 76_SolarForecast: Version 1.60.4

View File

@@ -162,6 +162,7 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.60.7" => "21.11.2025 new special Reading BatRatio, minor code chenges ",
"1.60.6" => "18.11.2025 _createSummaries: fix tdConFcTillSunset, _batSocTarget: apply 75% of tomorrow consumption ", "1.60.6" => "18.11.2025 _createSummaries: fix tdConFcTillSunset, _batSocTarget: apply 75% of tomorrow consumption ",
"1.60.5" => "16.11.2025 ___csmSpecificEpieces: implement EPIECMAXOPHRS , ___batAdjustPowerByMargin: adjust pow with otpMargin ". "1.60.5" => "16.11.2025 ___csmSpecificEpieces: implement EPIECMAXOPHRS , ___batAdjustPowerByMargin: adjust pow with otpMargin ".
"__solCast_ApiResponse: evaluation of httpheader ". "__solCast_ApiResponse: evaluation of httpheader ".
@@ -1468,6 +1469,7 @@ my %hcsr = (
BatPowerIn_Sum => { fnr => 5, fn => \&CurrentVal, par => 'batpowerinsum', par1 => '', unit => ' W', def => '-' }, BatPowerIn_Sum => { fnr => 5, fn => \&CurrentVal, par => 'batpowerinsum', par1 => '', unit => ' W', def => '-' },
BatPowerOut_Sum => { fnr => 5, fn => \&CurrentVal, par => 'batpoweroutsum', par1 => '', unit => ' W', def => '-' }, BatPowerOut_Sum => { fnr => 5, fn => \&CurrentVal, par => 'batpoweroutsum', par1 => '', unit => ' W', def => '-' },
BatWeightedTotalSOC => { fnr => 2, fn => \&CurrentVal, par => 'batsoctotal', par1 => '', unit => ' %', def => 0 }, BatWeightedTotalSOC => { fnr => 2, fn => \&CurrentVal, par => 'batsoctotal', par1 => '', unit => ' %', def => 0 },
BatRatio => { fnr => 5, fn => \&CurrentVal, par => 'batRatio', par1 => '', unit => '', def => '-' },
SunHours_Remain => { fnr => 5, fn => \&CurrentVal, par => '', par1 => '', unit => '', def => 0 }, # fnr => 3 -> Custom Calc SunHours_Remain => { fnr => 5, fn => \&CurrentVal, par => '', par1 => '', unit => '', def => 0 }, # fnr => 3 -> Custom Calc
SunMinutes_Remain => { fnr => 5, fn => \&CurrentVal, par => '', par1 => '', unit => '', def => 0 }, SunMinutes_Remain => { fnr => 5, fn => \&CurrentVal, par => '', par1 => '', unit => '', def => 0 },
dayAfterTomorrowPVforecast => { fnr => 5, fn => \&CurrentVal, par => 'dayAfterTomorrowPVfc', par1 => '', unit => ' Wh', def => 0 }, dayAfterTomorrowPVforecast => { fnr => 5, fn => \&CurrentVal, par => 'dayAfterTomorrowPVfc', par1 => '', unit => ' Wh', def => 0 },
@@ -1913,7 +1915,7 @@ sub Set {
"plantConfiguration:check,save,restore ". "plantConfiguration:check,save,restore ".
"powerTrigger:textField-long ". "powerTrigger:textField-long ".
"pvCorrectionFactor_Auto:noLearning,on_simple".($ipai ? ',on_simple_ai,' : ',')."on_complex".($ipai ? ',on_complex_ai,on_complex_api_ai,' : ',')."off ". "pvCorrectionFactor_Auto:noLearning,on_simple".($ipai ? ',on_simple_ai,' : ',')."on_complex".($ipai ? ',on_complex_ai,on_complex_api_ai,' : ',')."off ".
"reset:widgetList,$resetnum,select,$resets,2,textField,use only when arguments are needed ". "reset:widgetList,$resetnum,select,$resets,2,textField,fill in only if arguments are needed ".
$cf." " $cf." "
; ;
@@ -2573,9 +2575,8 @@ sub _setreset { ## no critic "not used"
} }
Log3 ($name, 3, qq{$name - stored PV correction factor of hour "$circh" from pvCircular and pvHistory deleted}); Log3 ($name, 3, qq{$name - stored PV correction factor of hour "$circh" from pvCircular and pvHistory deleted});
return;
} }
else {
for my $hod (keys %{$data{$name}{circular}}) { for my $hod (keys %{$data{$name}{circular}}) {
delete $data{$name}{circular}{$hod}{pvcorrf}; delete $data{$name}{circular}{$hod}{pvcorrf};
delete $data{$name}{circular}{$hod}{quality}; delete $data{$name}{circular}{$hod}{quality};
@@ -2596,6 +2597,7 @@ sub _setreset { ## no critic "not used"
Log3 ($name, 3, qq{$name - all stored PV correction factors from pvCircular and pvHistory deleted}); Log3 ($name, 3, qq{$name - all stored PV correction factors from pvCircular and pvHistory deleted});
} }
}
return; return;
} }
@@ -7765,6 +7767,7 @@ sub _attrBatSocManagement { ## no critic "not used"
} }
else { else {
deleteReadingspec ($hash, 'Battery_.*'); deleteReadingspec ($hash, 'Battery_.*');
$data{$name}{current}{'batRatio'.$bn};
} }
delete $data{$name}{circular}{99}{'lastTsMaxSocRchd'.$bn}; delete $data{$name}{circular}{99}{'lastTsMaxSocRchd'.$bn};
@@ -9188,7 +9191,7 @@ sub centralTask {
_calcConsForecast_circular ($centpars); # neue Verbrauchsprognose über pvCircular _calcConsForecast_circular ($centpars); # neue Verbrauchsprognose über pvCircular
_evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren _evaluateTrigger ($centpars); # Schwellenwerte der Trigger bewerten und signalisieren
_calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen _calcReadingsTomorrowPVFc ($centpars); # zusätzliche Readings Tomorrow_HourXX_PVforecast berechnen
_calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang) _calcTodayPVdeviation ($centpars); # Vorhersageabweichung erstellen (nach Sonnenuntergang)
_calcDataEveryFullHour ($centpars); # Daten berechnen/speichern die nur einmal nach jeder vollen Stunde ermittelt werden _calcDataEveryFullHour ($centpars); # Daten berechnen/speichern die nur einmal nach jeder vollen Stunde ermittelt werden
@@ -11621,7 +11624,7 @@ sub _batSocTarget {
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> Battery share factor of total required load: $sf"); Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> Battery share factor of total required load: $sf");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> today -> PV fc: $pvfctd Wh, con till sunset: $tdconsset Wh, Surp: $surptd Wh"); Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> today -> PV fc: $pvfctd Wh, con till sunset: $tdconsset Wh, Surp: $surptd Wh");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> tomorrow -> PV fc: $pvfctm Wh, con till sunset: $constm Wh, Surp: $surptm Wh (".(PERCCONINSOC * 100)."% con)"); Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> tomorrow -> PV fc: $pvfctm Wh, con till sunset: $constm Wh, Surp: $surptm Wh (".(PERCCONINSOC * 100)."% con)");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> selected energy for charging (the higher Surp value from above): $pvexpraw Wh"); Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> selected energy for charging (the higher positive Surp value from above): $pvexpraw Wh");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> expected energy for charging after application Share factor: $pvexpect Wh"); Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> expected energy for charging after application Share factor: $pvexpect Wh");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - compare with SoC history -> preliminary new Target: $target %"); Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - compare with SoC history -> preliminary new Target: $target %");
} }
@@ -12397,7 +12400,14 @@ sub __batChargeOptTargetPower {
$achievable = 0; $achievable = 0;
} }
storeReading ('Battery_TargetAchievable_'.$sbn, $achievable) if($nhr eq '00'); if ($nhr eq '00') {
storeReading ('Battery_TargetAchievable_'.$sbn, $achievable);
$ratio = sprintf "%.2f", ___batRatio ($runwhneed, $remainingSurp, $befficiency);
$data{$name}{current}{'batRatio'.$sbn} = $ratio;
$otp->{$sbn}{ratio} = $ratio;
$otp->{$sbn}{remainingSurp} = $remainingSurp;
}
$hsurp->{$hod}{$sbn}{loadrel} = $runwhneed > 0 ? 1 : 0; # Ladefreigabe abhängig von Ziel-SoC Erfüllung $hsurp->{$hod}{$sbn}{loadrel} = $runwhneed > 0 ? 1 : 0; # Ladefreigabe abhängig von Ziel-SoC Erfüllung
$hsurp->{$hod}{$sbn}{achievelog} = "charging target: $goalwh Wh, E requirement incl. efficiency: ". $hsurp->{$hod}{$sbn}{achievelog} = "charging target: $goalwh Wh, E requirement incl. efficiency: ".
@@ -12465,7 +12475,7 @@ sub __batChargeOptTargetPower {
my $pneedmin = $limpower * (1 + $otpMargin / 100); # optPower: Sicherheitsaufschlag my $pneedmin = $limpower * (1 + $otpMargin / 100); # optPower: Sicherheitsaufschlag
if ($strategy eq 'smartPower') { if ($strategy eq 'smartPower') {
($pneedmin) = ___batAdjustPowerByMargin ($limpower, # smartPower: Sicherheitsaufschlag abfallend proportional zum linearen Überschuss $pneedmin = ___batAdjustPowerByMargin ($limpower, # smartPower: Sicherheitsaufschlag abfallend proportional zum linearen Überschuss
$bpinmax, $bpinmax,
$runwhneed, $runwhneed,
$otpMargin, $otpMargin,
@@ -12502,16 +12512,13 @@ sub __batChargeOptTargetPower {
} }
if ($strategy eq 'smartPower') { # smartPower: Sicherheitsaufschlag linear absenkend if ($strategy eq 'smartPower') { # smartPower: Sicherheitsaufschlag linear absenkend
($target, $ratio) = ___batAdjustPowerByMargin ($limpower, # smartPower: agressivere Ladeleistung, Sicherheitsaufschlag abfallend proportional zum linearen Überschuss $target = ___batAdjustPowerByMargin ($limpower, # smartPower: agressivere Ladeleistung, Sicherheitsaufschlag abfallend proportional zum linearen Überschuss
$bpinmax, $bpinmax,
$runwhneed, $runwhneed,
$otpMargin, $otpMargin,
$remainingSurp, $remainingSurp,
$befficiency $befficiency
); );
$otp->{$sbn}{ratio} = sprintf ("%.2f", $ratio);
$otp->{$sbn}{remainingSurp} = $remainingSurp;
} }
my $gfeedin = CurrentVal ($name, 'gridfeedin', 0); # aktuelle Netzeinspeisung my $gfeedin = CurrentVal ($name, 'gridfeedin', 0); # aktuelle Netzeinspeisung
@@ -12559,6 +12566,20 @@ sub __batChargeOptTargetPower {
return ($hsurp, $otp); return ($hsurp, $otp);
} }
################################################################
# Ratio zwischen PV-Überschuß und benötigter Ladeenergie
# berechnen
################################################################
sub ___batRatio {
my ($rwh, $surp, $beff) = @_;
return 0 if($surp <= 0.0 || !defined $rwh || $rwh <= 0.0);
my $ratio = $surp * 100.0 * $beff / $rwh; # beff -> Batterie Effizienz als Anteil 0.1 .. 1
return $ratio;
}
################################################################ ################################################################
# Verbleibende Aktivstunden und deren Überschußsumme liefern # Verbleibende Aktivstunden und deren Überschußsumme liefern
################################################################ ################################################################
@@ -12590,12 +12611,10 @@ return ($remainingSurp, \@remaining_hods);
sub ___batAdjustPowerByMargin { sub ___batAdjustPowerByMargin {
my ($limpower, $pinmax, $runwhneed, $otpMargin, $remainingSurp, $befficiency) = @_; my ($limpower, $pinmax, $runwhneed, $otpMargin, $remainingSurp, $befficiency) = @_;
return $limpower if(!defined $runwhneed || $runwhneed <= 0);
my $pow; my $pow;
my $ratio = 0; my $ratio = ___batRatio ($runwhneed, $remainingSurp, $befficiency);
return ($limpower, $ratio) if(!defined $runwhneed || $runwhneed <= 0);
$ratio = $remainingSurp * 100.0 * $befficiency / $runwhneed; # befficiency als Anteil 0.1 .. 1
my $limWithMargin = $limpower * (1.0 + $otpMargin / 100.0); # Hinweis: das ist bewusst ein permanenter Sicherheitsaufschlag my $limWithMargin = $limpower * (1.0 + $otpMargin / 100.0); # Hinweis: das ist bewusst ein permanenter Sicherheitsaufschlag
$limpower = min ($limpower, $pinmax); # limpower !> pinmax um invertierte Interpolation zu vermeiden $limpower = min ($limpower, $pinmax); # limpower !> pinmax um invertierte Interpolation zu vermeiden
$limWithMargin = min ($limWithMargin, $pinmax); $limWithMargin = min ($limWithMargin, $pinmax);
@@ -12605,7 +12624,7 @@ sub ___batAdjustPowerByMargin {
elsif ($ratio >= 100 + $otpMargin) { $pow = $limWithMargin } elsif ($ratio >= 100 + $otpMargin) { $pow = $limWithMargin }
else { $pow = $pinmax - ($pinmax - $limWithMargin) * ($ratio - 100.0) / $otpMargin } else { $pow = $pinmax - ($pinmax - $limWithMargin) * ($ratio - 100.0) / $otpMargin }
return ($pow, $ratio); return $pow;
} }
################################################################ ################################################################
@@ -12967,7 +12986,7 @@ sub _createSummaries {
$next4HoursSum->{Consumption} += $confc / 60 * $minute if($h == 4); $next4HoursSum->{Consumption} += $confc / 60 * $minute if($h == 4);
} }
if ($istdy) { if ($fd == 0) {
$restOfDaySum->{PV} += $pvfc; $restOfDaySum->{PV} += $pvfc;
$restOfDaySum->{Consumption} += $confc; $restOfDaySum->{Consumption} += $confc;
$tdConFcTillSunset += $confc if(int ($hod) < int ($dtsset->{hour}) + 1); $tdConFcTillSunset += $confc if(int ($hod) < int ($dtsset->{hour}) + 1);
@@ -15086,9 +15105,9 @@ return;
} }
################################################################ ################################################################
# Schwellenwerte auswerten und signalisieren # Schwellenwerte für Trigger auswerten und signalisieren
################################################################ ################################################################
sub _evaluateThresholds { sub _evaluateTrigger {
my $paref = shift; my $paref = shift;
my $name = $paref->{name}; my $name = $paref->{name};
@@ -15155,13 +15174,13 @@ sub __evaluateArray {
if ($cond eq "on" && $gen1 > $h->{$key}) { if ($cond eq "on" && $gen1 > $h->{$key}) {
next if($gen2 < $h->{$key}); next if($gen2 < $h->{$key});
next if($gen3 < $h->{$key}); next if($gen3 < $h->{$key});
storeReading ("${tname}_${knum}", 'on') if(ReadingsVal($name, "${tname}_${knum}", "off") eq "off"); storeReading ("${tname}_${knum}", 'on') if(ReadingsVal($name, "${tname}_${knum}", 'off') eq 'off');
} }
if ($cond eq "off" && $gen1 < $h->{$key}) { if ($cond eq "off" && $gen1 < $h->{$key}) {
next if($gen2 > $h->{$key}); next if($gen2 > $h->{$key});
next if($gen3 > $h->{$key}); next if($gen3 > $h->{$key});
storeReading ("${tname}_${knum}", 'off') if(ReadingsVal($name, "${tname}_${knum}", "on") eq "on"); storeReading ("${tname}_${knum}", 'off') if(ReadingsVal($name, "${tname}_${knum}", 'on') eq 'on');
} }
} }
@@ -15697,6 +15716,7 @@ sub _genSpecialReadings {
readingsDelete ($hash, $prpo.'_'.$item); readingsDelete ($hash, $prpo.'_'.$item);
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'todayConsumptionForecast'); deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'todayConsumptionForecast');
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'tomorrowConsumptionForecast'); deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'tomorrowConsumptionForecast');
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'BatRatio');
} }
return if(!@csr); return if(!@csr);
@@ -15752,6 +15772,14 @@ sub _genSpecialReadings {
storeReading ($prpo.'_'.$kpi, $bsum); storeReading ($prpo.'_'.$kpi, $bsum);
} }
elsif ($kpi eq 'BatRatio') {
for my $bn (1..MAXBATTERIES) { # für jede Batterie
$bn = sprintf "%02d", $bn;
my $ratio = &{$hcsr{$kpi}{fn}} ($name, $hcsr{$kpi}{par}.$bn, $def);
storeReading ($prpo.'_'.$kpi.'_'.$bn, sprintf ("%.0f", $ratio)) if($ratio ne '-');
}
}
elsif ($kpi =~ /daysUntilBatteryCare_/xs) { elsif ($kpi =~ /daysUntilBatteryCare_/xs) {
my $bn = (split "_", $kpi)[1]; # Batterienummer extrahieren my $bn = (split "_", $kpi)[1]; # Batterienummer extrahieren
my $d2c = &{$hcsr{$kpi}{fn}} ($hash, $hcsr{$kpi}{par}, 'days2care'.$bn, $def); my $d2c = &{$hcsr{$kpi}{fn}} ($hash, $hcsr{$kpi}{par}, 'days2care'.$bn, $def);
@@ -28155,6 +28183,7 @@ to ensure that the system configuration is correct.
<colgroup> <col width="27%"> <col width="73%"> </colgroup> <colgroup> <col width="27%"> <col width="73%"> </colgroup>
<tr><td> <b>BatPowerIn_Sum</b> </td><td>the sum of the current battery charging power of all defined battery devices </td></tr> <tr><td> <b>BatPowerIn_Sum</b> </td><td>the sum of the current battery charging power of all defined battery devices </td></tr>
<tr><td> <b>BatPowerOut_Sum</b> </td><td>the sum of the current battery discharge power of all defined battery devices </td></tr> <tr><td> <b>BatPowerOut_Sum</b> </td><td>the sum of the current battery discharge power of all defined battery devices </td></tr>
<tr><td> <b>BatRatio</b> </td><td>The ratio of PV surplus/required charging energy to the battery's charging target (loadTarget) </td></tr>
<tr><td> <b>BatWeightedTotalSOC</b> </td><td>the resulting (weighted) SOC across all installed batteries in % </td></tr> <tr><td> <b>BatWeightedTotalSOC</b> </td><td>the resulting (weighted) SOC across all installed batteries in % </td></tr>
<tr><td> <b>allStringsFullfilled</b> </td><td>Fulfillment status of error-free generation of all strings </td></tr> <tr><td> <b>allStringsFullfilled</b> </td><td>Fulfillment status of error-free generation of all strings </td></tr>
<tr><td> <b>conForecastComingNight</b> </td><td>Consumption forecast from the coming sunset to the coming sunrise. If the sunset has already passed, </td></tr> <tr><td> <b>conForecastComingNight</b> </td><td>Consumption forecast from the coming sunset to the coming sunrise. If the sunset has already passed, </td></tr>
@@ -30939,6 +30968,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<colgroup> <col width="27%"> <col width="73%"> </colgroup> <colgroup> <col width="27%"> <col width="73%"> </colgroup>
<tr><td> <b>BatPowerIn_Sum</b> </td><td>die Summe der momentanen Batterieladeleistung aller definierten Batterie Geräte </td></tr> <tr><td> <b>BatPowerIn_Sum</b> </td><td>die Summe der momentanen Batterieladeleistung aller definierten Batterie Geräte </td></tr>
<tr><td> <b>BatPowerOut_Sum</b> </td><td>die Summe der momentanen Batterieentladeleistung aller definierten Batterie Geräte </td></tr> <tr><td> <b>BatPowerOut_Sum</b> </td><td>die Summe der momentanen Batterieentladeleistung aller definierten Batterie Geräte </td></tr>
<tr><td> <b>BatRatio</b> </td><td>das Verhältnis (Ratio) von PV-Überschuß / benötigter Ladeenergie zum Ladeziel (loadTarget) der Batterie(n) </td></tr>
<tr><td> <b>BatWeightedTotalSOC</b> </td><td>der resultierende (gewichtete) SOC über alle installierten Batterien in % </td></tr> <tr><td> <b>BatWeightedTotalSOC</b> </td><td>der resultierende (gewichtete) SOC über alle installierten Batterien in % </td></tr>
<tr><td> <b>allStringsFullfilled</b> </td><td>Erfüllungsstatus der fehlerfreien Generierung aller Strings </td></tr> <tr><td> <b>allStringsFullfilled</b> </td><td>Erfüllungsstatus der fehlerfreien Generierung aller Strings </td></tr>
<tr><td> <b>conForecastComingNight</b> </td><td>Verbrauchsprognose vom kommenden Sonnenuntergang bis zum kommenden Sonnenaufgang. Ist der Sonnenuntergang </td></tr> <tr><td> <b>conForecastComingNight</b> </td><td>Verbrauchsprognose vom kommenden Sonnenuntergang bis zum kommenden Sonnenaufgang. Ist der Sonnenuntergang </td></tr>