diff --git a/fhem/CHANGED b/fhem/CHANGED
index b1b0aa806..fcaa6390d 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.58.6
- bugfix: 72_FRITZBOX: Fehler bei rename von Devices
- bugfix: 76_SolarForecast: opt load if battery load control is deactivated
- change: 76_SolarForecast: Version 1.58.4
diff --git a/fhem/FHEM/76_SolarForecast.pm b/fhem/FHEM/76_SolarForecast.pm
index e7a4d12ce..269f5f909 100644
--- a/fhem/FHEM/76_SolarForecast.pm
+++ b/fhem/FHEM/76_SolarForecast.pm
@@ -21,7 +21,7 @@
# You should have received a copy of the GNU General Public License
# along with fhem. If not, see .
#
-# This copyright notice MUST APPEAR in all copies of the script!
+# This copyright notice MUST APPEAR in all copies of the script!
#
#########################################################################################################################
#
@@ -160,6 +160,10 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
+ "1.58.6" => "03.10.2025 __batChargeMgmt code changed, new sub ___batChargeSaveResults, remove reading Battery_ChargeRecommended_XX ".
+ "_calcReadingsTomorrowPVFc: bugfix generating readings of tomorrow ".
+ "__batChargeOptTargetPower: complete rework, Attr ctrlBatSocManagementXX new keys 'loadStrategy', 'weightOwnUse' ".
+ "new battery key setupBatteryDevXX->efficiency ",
"1.58.5" => "24.09.2025 __batChargeOptTargetPower: fix if battery load control is deactivated ",
"1.58.4" => "23.09.2025 __batChargeOptTargetPower: user a better surplus value, excess based on average removed & some other code optimization ",
"1.58.3" => "17.09.2025 __batChargeOptTargetPower: minor code change, consider bpinmax & lcintime ",
@@ -463,7 +467,7 @@ use constant {
PRDEF => 0.9, # default Performance Ratio (PR)
SFTYMARGIN_20 => 20, # Sicherheitszuschlag 20%
SFTYMARGIN_50 => 50, # Sicherheitszuschlag 50%
- STOREFFDEF => 0.90, # default Batterie Effizienz (https://www.energie-experten.org/erneuerbare-energien/photovoltaik/stromspeicher/wirkungsgrad)
+ STOREFFDEF => 87, # default Batterie Effizienz (https://www.energie-experten.org/erneuerbare-energien/photovoltaik/stromspeicher/wirkungsgrad)
TEMPCOEFFDEF => -0.45, # default Temperaturkoeffizient Pmpp (%/°C) lt. Datenblatt Solarzelle
TEMPMODINC => 25, # default Temperaturerhöhung an Solarzellen gegenüber Umgebungstemperatur bei wolkenlosem Himmel
TEMPBASEDEF => 25, # Temperatur Module bei Nominalleistung
@@ -1564,10 +1568,15 @@ my %hfspvh = (
$hfspvh{'batprogsoc'.$bn}{validkey} = undef;
$hfspvh{'batprogsoc'.$bn}{fpar} = undef;
- $hfspvh{'lcintimebat'.$bn}{fn} = \&_storeVal; # Ladesteurung der Batterie In Time, d.h. war sie aktiv? (1 - Ja, 0 - Nein)
+ $hfspvh{'lcintimebat'.$bn}{fn} = \&_storeVal; # Ladesteuerung der Batterie In Time, d.h. war sie aktiv? (1 - Ja, 0 - Nein)
$hfspvh{'lcintimebat'.$bn}{storname} = 'lcintimebat'.$bn;
$hfspvh{'lcintimebat'.$bn}{validkey} = undef;
$hfspvh{'lcintimebat'.$bn}{fpar} = undef;
+
+ $hfspvh{'strategybat'.$bn}{fn} = \&_storeVal; # Ladestrategie der Batterie
+ $hfspvh{'strategybat'.$bn}{storname} = 'strategybat'.$bn;
+ $hfspvh{'strategybat'.$bn}{validkey} = undef;
+ $hfspvh{'strategybat'.$bn}{fpar} = undef;
$hfspvh{'batmaxsoc'.$bn}{fn} = \&_storeVal; # max. erreichter SOC des Tages
$hfspvh{'batmaxsoc'.$bn}{storname} = 'batmaxsoc'.$bn;
@@ -7402,6 +7411,7 @@ sub _attrBatteryDev { ## no critic "not used"
show => { comp => '(?:[0-3](?::(?:top|bottom))?)', must => 0, act => 0 },
label => { comp => '(none|below|beside)', must => 0, act => 0 },
asynchron => { comp => '(0|1)', must => 0, act => 0 },
+ efficiency => { comp => '(100|[1-9]?[0-9])', must => 0, act => 0 },
};
if ($paref->{cmd} eq 'set') {
@@ -7459,13 +7469,13 @@ sub _attrBatteryDev { ## no critic "not used"
delete $data{$name}{batteries}{$bn}{bpinmax};
delete $data{$name}{batteries}{$bn}{bpinreduced};
delete $data{$name}{batteries}{$bn}{bpoutmax};
+ delete $data{$name}{batteries}{$bn}{befficiency};
}
elsif ($paref->{cmd} eq 'del') {
readingsDelete ($hash, 'Current_PowerBatIn_'.$bn);
readingsDelete ($hash, 'Current_PowerBatOut_'.$bn);
readingsDelete ($hash, 'Current_BatCharge_'.$bn);
readingsDelete ($hash, 'Battery_ChargeOptTargetPower_'.$bn);
- readingsDelete ($hash, 'Battery_ChargeRecommended_'.$bn);
readingsDelete ($hash, 'Battery_ChargeUnrestricted_'.$bn);
readingsDelete ($hash, 'Battery_ChargeRequest_'.$bn);
readingsDelete ($hash, 'Battery_OptimumTargetSoC_'.$bn);
@@ -7518,6 +7528,8 @@ sub _attrBatSocManagement { ## no critic "not used"
careCycle => { comp => '\d+', must => 0, act => 0 },
loadAbort => { comp => '(?:100|[1-9]?[0-9]):\d+(?::(?:100|[1-9]?[0-9]))?', must => 0, act => 0 },
safetyMargin => { comp => '(?:100|[1-9]?\d)(?::(?:100|[1-9]?\d))?', must => 0, act => 0 },
+ loadStrategy => { comp => '(loadRelease|optPower)', must => 0, act => 0 },
+ weightOwnUse => { comp => '(100|[1-9]?[0-9])', must => 0, act => 0 },
};
my ($a, $h) = parseParams ($aVal);
@@ -8915,6 +8927,11 @@ sub centralTask {
}
}
+ for my $bn (1..MAXBATTERIES) { # 02.10.
+ $bn = sprintf "%02d", $bn;
+ readingsDelete ($hash, 'Battery_ChargeRecommended_'.$bn);
+ }
+
##########################################################################################################################
@@ -11105,7 +11122,7 @@ sub _transferBatteryValues {
my $instcap = $h->{cap}; # numerischer Wert (Wh) oder Readingname installierte Batteriekapazität
my $pinmax = $h->{pinmax} // INFINITE; # max. mögliche Ladeleistung
my $pinreduced = $h->{pinreduced} // $pinmax; # reduzierte Ladeleistung (z.B. bei Ladung aus dem Grid)
- my $poutmax = $h->{poutmax} // INFINITE; # max. mögliche Entladeleistung
+ my $poutmax = $h->{poutmax} // INFINITE; # max. mögliche Entladeleistung
next if(!$pin || !$pou);
@@ -11292,6 +11309,7 @@ sub _transferBatteryValues {
$data{$name}{batteries}{$bn}{bposingraph} = $pos; # Anzeigeposition in Balkengrafik
$data{$name}{batteries}{$bn}{blabel} = $label; # Batterie SoC-Beschriftung in Balkengrafik
$data{$name}{batteries}{$bn}{bchargewh} = BatteryVal ($name, $bn, 'binstcap', 0) * $soc / 100; # Batterie SoC (Wh)
+ $data{$name}{batteries}{$bn}{befficiency} = $h->{efficiency}; # Speicherwirkungsgrad
$num++;
$socsum += $soc;
@@ -11521,19 +11539,21 @@ sub __parseAttrBatSoc {
my $name = shift;
my $cgbt = shift // return;
- my ($urMargin, $otpMargin);
+ my ($lrMargin, $otpMargin);
my ($pa, $ph) = parseParams ($cgbt);
- ($urMargin, $otpMargin) = split ':', $ph->{safetyMargin} if(defined $ph->{safetyMargin});
+ ($lrMargin, $otpMargin) = split ':', $ph->{safetyMargin} if(defined $ph->{safetyMargin});
my $parsed = {
- lowSoc => $ph->{lowSoc},
- upSoc => $ph->{upSoC},
- maxSoc => $ph->{maxSoC} // MAXSOCDEF, # optional (default: MAXSOCDEF)
- careCycle => $ph->{careCycle} // CARECYCLEDEF, # Ladungszyklus (Maintenance) für maxSoC in Tagen
- lcslot => $ph->{lcSlot},
- loadAbort => $ph->{loadAbort},
- urMargin => $urMargin,
- otpMargin => $otpMargin,
+ lowSoc => $ph->{lowSoc},
+ upSoc => $ph->{upSoC},
+ maxSoc => $ph->{maxSoC} // MAXSOCDEF, # optional (default: MAXSOCDEF)
+ careCycle => $ph->{careCycle} // CARECYCLEDEF, # Ladungszyklus (Maintenance) für maxSoC in Tagen
+ lcslot => $ph->{lcSlot},
+ loadAbort => $ph->{loadAbort},
+ loadStrategy => $ph->{loadStrategy},
+ weightOwnUse => $ph->{weightOwnUse},
+ lrMargin => $lrMargin,
+ otpMargin => $otpMargin,
};
return $parsed;
@@ -11593,7 +11613,12 @@ sub _batChargeMgmt {
my $bpin = CurrentVal ($name, 'batpowerinsum', 0); # aktuelle Batterie Ladeleistung (Summe über alle Batterien)
my $gfeedin = CurrentVal ($name, 'gridfeedin', 0); # aktuelle Netzeinspeisung
my $inplim = 0;
-
+
+ my $hsurp = {}; # Hashreferenz Überschuß
+ my $hsoc = {}; # Hashreferenz
+ my $values = {}; # Hashreferenz
+ my $progsoc;
+
## Inverter Limits ermitteln
##############################
for my $in (1..MAXINVERTER) {
@@ -11616,10 +11641,7 @@ sub _batChargeMgmt {
debugLog ($paref, 'batteryManagement', "ChargeMgmt - The limit for grid feed-in is: $feedinlim W");
## Schleife über alle Batterien
- #################################
- my %hsoc; # Hilfshash
- my $hsurp = {}; # Hashreferenz Überschuß
-
+ #################################
for my $bn (1..MAXBATTERIES) { # für jede Batterie
$bn = sprintf "%02d", $bn;
@@ -11633,32 +11655,39 @@ sub _batChargeMgmt {
next;
}
- my $maxfctim = timestringToTimestamp (ReadingsVal ($name, 'Today_MaxPVforecastTime', '')) // $t;
- my $rodpvfc = ReadingsNum ($name, 'RestOfDayPVforecast', 0); # PV Prognose Rest des Tages
- my $tompvfc = ReadingsNum ($name, 'Tomorrow_PVforecast', 0); # PV Prognose nächster Tag
- 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 ($name, $bn, 'bcharge', 0); # aktuelle Ladung in %
- my $bpinmax = BatteryVal ($name, $bn, 'bpinmax', INFINITE); # max. mögliche Ladeleistung W
- my $bpoutmax = BatteryVal ($name, $bn, 'bpoutmax', INFINITE); # max. mögliche Entladeleistung W
- my $bpowerin = BatteryVal ($name, $bn, 'bpowerin', INFINITE); # aktuelle Ladeleistung 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;
- my $loadAbort = '';
- my ($lcslot, $urMargin, $otpMargin);
+ my $maxfctim = timestringToTimestamp (ReadingsVal ($name, 'Today_MaxPVforecastTime', '')) // $t;
+ my $rodpvfc = ReadingsNum ($name, 'RestOfDayPVforecast', 0); # PV Prognose Rest des Tages
+ my $tompvfc = ReadingsNum ($name, 'Tomorrow_PVforecast', 0); # PV Prognose nächster Tag
+ 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 ($name, $bn, 'bcharge', 0); # aktuelle Ladung in %
+ my $csocwh = BatteryVal ($name, $bn, 'bchargewh', 0); # aktuelle Ladung in Wh
+ my $bpinmax = BatteryVal ($name, $bn, 'bpinmax', INFINITE); # max. mögliche Ladeleistung W
+ my $bpoutmax = BatteryVal ($name, $bn, 'bpoutmax', INFINITE); # max. mögliche Entladeleistung W
+ my $bpowerin = BatteryVal ($name, $bn, 'bpowerin', INFINITE); # aktuelle Ladeleistung W
+ my $bpinreduced = BatteryVal ($name, $bn, 'bpinreduced', 0); # Standardwert bei <=lowSoC -> Anforderungsladung vom Grid
+ my $befficiency = BatteryVal ($name, $bn, 'befficiency', STOREFFDEF) / 100; # Speicherwirkungsgrad
+ my $cgbt = AttrVal ($name, 'ctrlBatSocManagement'.$bn, undef);
+ my $sf = __batCapShareFactor ($hash, $bn); # Anteilsfaktor der Batterie XX Kapazität an Gesamtkapazität
+ my $strategy = 'loadRelease'; # 'loadRelease' oder 'optPower'
+ my $wou = 0; # Gewichtung Prognose-Verbrauch als Anteil "Eigennutzung" (https://forum.fhem.de/index.php?msg=1348429)
+ my $lowSoc = 0;
+ my $loadAbort = '';
+ my $lrMargin = SFTYMARGIN_50;
+ my $otpMargin = SFTYMARGIN_20;
+ my $lcslot;
if ($cgbt) {
- my $parsed = __parseAttrBatSoc ($name, $cgbt);
- $lowSoc = $parsed->{lowSoc} // 0;
- $lcslot = $parsed->{lcslot};
- $loadAbort = $parsed->{loadAbort};
- $urMargin = $parsed->{urMargin};
- $otpMargin = $parsed->{otpMargin};
+ my $parsed = __parseAttrBatSoc ($name, $cgbt);
+ $lowSoc = $parsed->{lowSoc} // 0;
+ $lcslot = $parsed->{lcslot};
+ $loadAbort = $parsed->{loadAbort};
+ $lrMargin = $parsed->{lrMargin} // $lrMargin; # Sicherheitszuschlag LR (%)
+ $otpMargin = $parsed->{otpMargin} // $otpMargin; # Sicherheitszuschlag OTP (%)
+ $strategy = $parsed->{loadStrategy} // $strategy;
+ $wou = $parsed->{weightOwnUse} // $wou;
}
-
- my $margin = defined $urMargin ? $urMargin : SFTYMARGIN_50; # Sicherheitszuschlag (%)
## generelle Ladeabbruchbedingung evaluieren
##############################################
@@ -11691,14 +11720,16 @@ sub _batChargeMgmt {
my $socwh = sprintf "%.0f", ($batinstcap * $csoc / 100); # aktueller SoC in Wh
my $whneed = $batinstcap - $socwh;
- # Debug Log
- #############
+ # Debuglog
+ ############
if ($paref->{debug} =~ /batteryManagement/) {
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - General load termination condition: $labortCond");
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - control time Slot - Slot start: $lcstart, Slot end: $lcend");
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - Installed Battery capacity: $batinstcap Wh, Percentage of total capacity: ".(sprintf "%.1f", $sf*100)." %");
+ Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - Battery efficiency used: ".($befficiency * 100)." %");
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - The PV generation, consumption and surplus listed below are based on the battery's share of total installed capacity!");
- Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeLR - used safety margin: $margin %");
+ Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeLR - used safety margin: $lrMargin %");
+ Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeLR - weighted self-consumption: $wou %");
}
## Auswertung für jede kommende Stunde
@@ -11710,6 +11741,8 @@ sub _batChargeMgmt {
my $nhr = sprintf "%02d", $num;
my $hod = NexthoursVal ($name, 'NextHour'.$nhr, 'hourofday', undef);
my $nhstt = NexthoursVal ($name, 'NextHour'.$nhr, 'starttime', undef);
+ my $stt = (split /[-:]/, $nhstt)[2];
+ $stt =~ s/\s/\//;
next if(!defined ($hod) || !defined ($nhstt));
@@ -11718,8 +11751,8 @@ sub _batChargeMgmt {
my $pvfc = NexthoursVal ($name, 'NextHour'.$nhr, 'pvfc', 0);
if ($fd == 2 && $fh == 0) {
- $tompvfc = CurrentVal ($name, 'dayAfterTomorrowPVfc', 0); # PV Prognose übernächster Tag
- $tomconfc = CurrentVal ($name, 'dayAfterTomorrowConfc', 0); # Verbrauchsprognose übernächster Tag
+ $tompvfc = CurrentVal ($name, 'dayAfterTomorrowPVfc', 0); # PV Prognose übernächster Tag
+ $tomconfc = CurrentVal ($name, 'dayAfterTomorrowConfc', 0); # Verbrauchsprognose übernächster Tag
}
## Zeitfenster für aktives Lademanagement anwenden
@@ -11744,8 +11777,8 @@ sub _batChargeMgmt {
$tomconfc = sprintf "%.0f", ($sf * $tomconfc);
$tompvfc = sprintf "%.0f", ($sf * $tompvfc);
- ## PV-Überschuß und (Rest)Tagesüberschuß
- ##########################################
+ ## PV-Überschuß und (Rest)Tagesüberschuß heute/morgen
+ #######################################################
if ($today) { # heutiger Tag
$confcss -= $confc; # Verbrauch bis Sonnenuntergang - Verbrauch Fc aktuelle Stunde
$confcss = 0 if($confcss < 0);
@@ -11761,60 +11794,68 @@ sub _batChargeMgmt {
}
$spday = 0 if($spday < 0); # PV Überschuß Prognose bis Sonnenuntergang
- my $surpls = sprintf "%.0f", ($pvfc - $confc); # effektiver PV Überschuß bzw. effektiver Verbrauch wenn < 0
+ $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!
## Steuerung nach Ladefreigabe
################################
- if ( $whneed * (1 + ($margin / 100)) >= $spday ) {$crel = 1} # Ladefreigabe wenn benötigte Ladeenergie >= Restüberschuß des Tages zzgl. Sicherheitsaufschlag
- if ( !$num && ($pvCu - $curcon) >= $inplim ) {$crel = 1} # Ladefreigabe wenn akt. PV Leistung - Abschläge >= WR-Leistungsbegrenzung
- if ( !$bpin && $gfeedin > $feedinlim ) {$crel = 1} # V 1.49.6 Ladefreigabe wenn akt. keine Bat-Ladung UND akt. Einspeisung > Einspeiselimit der Anlage
- if ( $bpin && ($gfeedin - $bpin) > $feedinlim ) {$crel = 1} # V 1.49.6 Ladefreigabe wenn akt. Bat-Ladung UND Eispeisung - Bat-Ladung > Einspeiselimit der Anlage
- if ( !$cgbt ) {$crel = 1} # Ladefreigabe wenn kein BatSoc-Management
- if ( !$lcintime ) {$crel = 1} # Ladefreigabe wenn nicht innerhalb Zeitslot für Ladesteuerung
- if ( $labortCond ) {$crel = 0} # keine Ladefreigabe bei genereller Abbruchbedingung
-
+ if ( $whneed * (1 + ($lrMargin / 100)) >= $spday ) {$crel = 1} # Ladefreigabe wenn benötigte Ladeenergie >= Restüberschuß des Tages zzgl. Sicherheitsaufschlag
+ if ( !$num && ($pvCu - $curcon) >= $inplim ) {$crel = 1} # Ladefreigabe wenn akt. PV Leistung - Abschläge >= WR-Leistungsbegrenzung
+ if ( !$bpin && $gfeedin > $feedinlim ) {$crel = 1} # V 1.49.6 Ladefreigabe wenn akt. keine Bat-Ladung UND akt. Einspeisung > Einspeiselimit der Anlage
+ if ( $bpin && ($gfeedin - $bpin) > $feedinlim ) {$crel = 1} # V 1.49.6 Ladefreigabe wenn akt. Bat-Ladung UND Eispeisung - Bat-Ladung > Einspeiselimit der Anlage
+ if ( !$cgbt ) {$crel = 1} # Ladefreigabe wenn kein BatSoc-Management
+ if ( !$lcintime ) {$crel = 1} # Ladefreigabe wenn nicht innerhalb Zeitslot für Ladesteuerung
+ if ( $labortCond ) {$crel = 0} # keine Ladefreigabe bei genereller Abbruchbedingung
+
# Steuerhash für optimimierte Ladeleistung erstellen
######################################################
my $surplswh = max (0, $surpls);
- if ($today) { # nur Heute
- $hsurp->{$hod}{hod} = $hod;
- $hsurp->{$hod}{nhr} = $nhr;
- $hsurp->{$hod}{surpls} = $lcintime ? $surplswh.'.'.$hod : 0; # Überschuß in Wh der Stunde mit Sortierhilfe
- $hsurp->{$hod}{$bn}{spday} = $spday; # (Rest)PV-Überschuß am laufenden Tag
- $hsurp->{$hod}{$bn}{initsocwh} = $socwh;
- $hsurp->{$hod}{$bn}{batinstcap} = $batinstcap;
- $hsurp->{$hod}{$bn}{bpinmax} = $bpinmax; # max. mögliche Ladeleistung
- $hsurp->{$hod}{$bn}{otpMargin} = $otpMargin; # Sicherheitszuschlag für Berechnungen
- $hsurp->{$hod}{$bn}{lcintime} = $lcintime; # Ladesteuerung "In Time" oder "nicht In Time"
+ 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}{batinstcap} = $batinstcap; # installierte Batteriekapazität (Wh)
+ $hsurp->{$fd}{$hod}{$bn}{bpinmax} = $bpinmax; # max. mögliche Ladeleistung
+ $hsurp->{$fd}{$hod}{$bn}{bpinreduced} = $bpinreduced; # Standardwert bei <=lowSoC -> Anforderungsladung vom Grid
+ $hsurp->{$fd}{$hod}{$bn}{bpoutmax} = $bpoutmax; # max. mögliche Entladeleistung
+ $hsurp->{$fd}{$hod}{$bn}{lowSocwh} = $lowSocwh; # eingestellter lowSoC in Wh
+ $hsurp->{$fd}{$hod}{$bn}{batoptsocwh} = $batoptsocwh; # optimaler SoC in Wh
+ $hsurp->{$fd}{$hod}{$bn}{csocwh} = $csocwh; # aktueller SoC in Wh
+ $hsurp->{$fd}{$hod}{$bn}{otpMargin} = $otpMargin; # Sicherheitszuschlag für Berechnungen
+ $hsurp->{$fd}{$hod}{$bn}{lcintime} = $lcintime; # Ladesteuerung "In Time" oder "nicht In Time"
+ $hsurp->{$fd}{$hod}{$bn}{stt} = $stt; # Day/Time für Debuglog
+ $hsurp->{$fd}{$hod}{$bn}{strategy} = $strategy; # Ladestrategie
+ $hsurp->{$fd}{$hod}{$bn}{weightOwnUse} = $wou; # Gewichtung Prognose-Verbrauch als Anteil "Eigennutzung" (https://forum.fhem.de/index.php?msg=1348429)
+ $hsurp->{$fd}{$hod}{$bn}{befficiency} = $befficiency; # Speicherwirkungsgrad
}
- ## SOC-Prognose
- ################# # change V 1.47.0
- my $fceff = $surpls; # wichtig keine Nachkommastellen!
+ ## SOC-Prognose LR
+ ####################
+ my $speff = $surpls; # effektiver PV Überschuß bzw. effektiver Verbrauch wenn < 0
- $fceff = $fceff > 0 ? ($fceff >= $bpinmax ? $bpinmax : $fceff) :
- $fceff < 0 ? ($fceff <= $bpoutmax * -1 ? $bpoutmax * -1 : $fceff) :
- $fceff;
+ $speff = $speff > 0 ? ($speff >= $bpinmax ? $bpinmax : $speff) :
+ $speff < 0 ? ($speff <= -$bpoutmax ? -$bpoutmax : $speff) :
+ $speff;
+
+ my $delta = $speff > 0 ? ($crel ? $speff * $befficiency : 0) : # PV Überschuß (d.h. Aufladung) nur einbeziehen wenn Ladefreigabe
+ $speff < 0 ? $speff / $befficiency : # Verbrauch einbeziehen
+ 0;
- $socwh += $crel ? ($fceff > 0 ? $fceff * STOREFFDEF : $fceff / STOREFFDEF) :
- ($fceff > 0 ? 0 : $fceff / STOREFFDEF); # PV Überschuß (d.h. Aufladung) nur einbeziehen wenn Ladefreigabe
+ $socwh += $delta;
- $socwh = $socwh < $lowSocwh ? $lowSocwh :
- $socwh < $batoptsocwh ? $batoptsocwh : # SoC Prognose in Wh
+ $socwh = $socwh < $lowSocwh ? $lowSocwh : # SoC begrenzen
+ $socwh < $batoptsocwh ? $batoptsocwh :
$socwh > $batinstcap ? $batinstcap :
$socwh;
- $socwh = sprintf "%.0f", $socwh;
- my $progsoc = sprintf "%.1f", (100 * $socwh / $batinstcap); # Prognose SoC in %
-
- __createNextHoursSFCReadings ( {name => $name,
- nhr => $nhr,
- bn => $bn,
- progsoc => $progsoc
- }
- ); # Readings NextHourXX_Bat_XX_ChargeForecast erstellen
-
+ $socwh = sprintf "%.0f", $socwh; # SoC Prognose in Wh
+ $progsoc = sprintf "%.1f", (100 * $socwh / $batinstcap); # Prognose SoC in %
+
+ ## Debuglog LR
+ ################
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, inTime: ".($cgbt ? $lcintime : '-');
if ($num) {
@@ -11824,50 +11865,116 @@ sub _batChargeMgmt {
$msg = "SoCfc: $progsoc % / $socwh Wh, whneed: $whneed, pvfc: $pvfc, roTomPV: $tompvfc, roTomCON: $tomconfc, SurpDay: $spday Wh, inTime: ".($cgbt ? $lcintime : '-');
}
}
- else {
- storeReading ('Battery_ChargeRecommended_'.$bn, $crel);
- storeReading ('Battery_ChargeUnrestricted_'.$bn, $crel);
- storeReading ('Battery_ChargeAbort_'.$bn, $labortCond) if ($loadAbort); # Ladeabbruchbedingung
- }
+
+ debugLog ($paref, 'batteryManagement', "Bat $bn ChargeLR $stt - lc: $crel, $msg");
+ ## Fortschreibung
+ ###################
$whneed = $batinstcap - $socwh;
+
+ ## Speicherung und Readings erstellen LR
+ ##########################################
+ $values = { hsoc => $hsoc,
+ bn => $bn,
+ nhr => $nhr,
+ progsoc => $progsoc,
+ socwh => $socwh,
+ today => $today,
+ hod => $hod,
+ loopid => 'LR',
+ strategy => $strategy,
+ crel => $crel,
+ labortCond => $labortCond,
+ loadAbort => $loadAbort,
+ cgbt => $cgbt,
+ lcintime => $lcintime,
+ };
- $data{$name}{nexthours}{'NextHour'.$nhr}{'rcdchargebat'.$bn} = $crel;
- $data{$name}{nexthours}{'NextHour'.$nhr}{'soc'.$bn} = $progsoc;
- $data{$name}{nexthours}{'NextHour'.$nhr}{'lcintimebat'.$bn} = $lcintime if($cgbt); # Ladesteuerung "In Time", "nicht In Time" oder nicht verwendet
- $hsoc{$nhr}{socprogwhsum} += $socwh; # Hilfshash Aufsummierung SoC-Prognose (Wh) über alle Batterien
+ ___batChargeSaveResults ($paref, $values);
- # prognostizierten Daten in pvHistory speichern
- #################################################
- if ($today && $hod) { # heutiger Tag
- writeToHistory ( { paref => $paref, key => 'batprogsoc'.$bn, val => $progsoc, hour => $hod } );
- writeToHistory ( { paref => $paref, key => 'lcintimebat'.$bn, val => $lcintime, hour => $hod } ) if($cgbt);
- }
-
- my $stt = (split /[-:]/, $nhstt)[2];
- $stt =~ s/\s/\//;
-
- debugLog ($paref, 'batteryManagement', "Bat $bn ChargeLR $stt -> $crel ($msg)");
+ $values = {};
+ }
+ }
+
+ # leistungsoptimierte (optPower) Beladungssteuerung
+ #####################################################
+ for my $lfd (0..max (0, keys %{$hsurp})) {
+ $paref->{hsurp} = $hsurp->{$lfd};
+ my ($hopt, $otp) = __batChargeOptTargetPower ($paref);
+ delete $paref->{hsurp};
+
+ ## Debuglog OTP
+ #################
+ if ($paref->{debug} =~ /batteryManagement/ && !$lfd) {
+ Log3 ($name, 1, "$name DEBUG> ChargeOTP - The limit for grid feed-in is $feedinlim W");
+ }
+
+ ## Speicherung und Readings erstellen OTP
+ ###########################################
+ for my $shod (sort { $a <=> $b } keys %{$hopt}) {
+ my $nhr = $hopt->{$shod}{nhr};
+ my @batteries = grep { !/^(?:fd|speff|surplswh|nhr)$/xs } keys %{$hopt->{24}};
+
+ for my $bat (sort @batteries) {
+ my $ssocwh = $hopt->{$shod}{$bat}{runwh} // '-';
+
+ ## SOC-Prognose OTP
+ #####################
+ my $fcendwh = $hopt->{$shod}{$bat}{fcendwh} // 0;
+ $progsoc = sprintf "%.1f", (100 * $fcendwh / $hopt->{$shod}{$bat}{batinstcap}); # Prognose SoC in %
+
+ ## Speicherung und Readings erstellen OTP
+ ##########################################
+ $values = { hsoc => $hsoc,
+ otp => $otp,
+ bn => $bat,
+ nhr => $nhr,
+ progsoc => $progsoc,
+ socwh => $fcendwh,
+ hod => $shod,
+ loopid => 'OTP',
+ strategy => $hopt->{$shod}{$bat}{strategy},
+ crel => 1,
+ };
+
+ ___batChargeSaveResults ($paref, $values);
+
+ ## Debuglog OTP
+ #################
+ if ($paref->{debug} =~ /batteryManagement/) {
+ my $lcintime = $hopt->{$shod}{$bat}{lcintime};
+ my $spls = int $hopt->{$shod}{surplswh};
+ my $pneedmin = $hopt->{$shod}{$bat}{pneedmin};
+ my $ttt = $hopt->{$shod}{$bat}{stt};
+
+ if ($nhr eq '00') {
+ $pneedmin = $otp->{$bat}{target} // 0;
+ my $achievable = $hopt->{$shod}{$bat}{achievable};
+ my $otpMargin = $hopt->{$shod}{$bat}{otpMargin};
+ my $weightOwnUse = $hopt->{$shod}{$bat}{weightOwnUse};
+ Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP - used safety margin: $otpMargin %");
+ Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP - weighted self-consumption: $weightOwnUse %");
+ Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP - is the charging goal likely to be achieved? - $achievable");
+ }
+
+ Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP $ttt - hod: $shod / $nhr, lc: $lcintime, SoC S/E: $ssocwh / $fcendwh Wh, Surplus: $spls Wh, OTP: $pneedmin W");
+ }
+ }
}
}
- # leistungsoptimierte Beladungssteuerung
- ##########################################
- $paref->{hsurp} = $hsurp;
- my $hopt = __batChargeOptTargetPower ($paref);
- delete $paref->{hsurp};
# prognostizierten SOC über alle Batterien speichern
######################################################
- for my $nhr (keys %hsoc) {
- if (defined $hsoc{$nhr}{socprogwhsum}) {
- $data{$name}{nexthours}{'NextHour'.$nhr}{socprogwhsum} = $hsoc{$nhr}{socprogwhsum};
+ for my $nhr (keys %{$hsoc}) {
+ if (defined $hsoc->{$nhr}{socprogwhsum}) {
+ $data{$name}{nexthours}{'NextHour'.$nhr}{socprogwhsum} = $hsoc->{$nhr}{socprogwhsum};
my $today = NexthoursVal ($name, 'NextHour'.$nhr, 'today', 0);
my $hod = NexthoursVal ($name, 'NextHour'.$nhr, 'hourofday', '');
if ($today && $hod) { # heutiger Tag
- writeToHistory ( { paref => $paref, key => 'socprogwhsum', val => $hsoc{$nhr}{socprogwhsum}, hour => $hod } );
+ writeToHistory ( { paref => $paref, key => 'socprogwhsum', val => $hsoc->{$nhr}{socprogwhsum}, hour => $hod } );
}
}
}
@@ -11905,129 +12012,240 @@ return;
sub __batChargeOptTargetPower {
my $paref = shift;
my $name = $paref->{name};
- my $hsurp = $paref->{hsurp} // return; # Hashref Überschußhash
+ my $hsurp = $paref->{hsurp}; # Hashref Überschußhash
- my $fipl = CurrentVal ($name, 'feedinPowerLimit', INFINITE);
- my @sorted = sort { $hsurp->{$a}{surpls} <=> $hsurp->{$b}{surpls} } keys %{$hsurp};
- my $sphrs = scalar grep { int( $hsurp->{$_}{surpls} ) >= 1 } @sorted; # Stunden mit Überschuß >= 1
- my @batteries = grep { !/^(?:hod|surpls|nhr)$/xs } keys %{$hsurp->{24}};
+ my $fipl = CurrentVal ($name, 'feedinPowerLimit', INFINITE);
+ 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;
- ## Kalkulation / Logik
- ########################
- for my $shod (@sorted) {
- my $spls = int $hsurp->{$shod}{surpls};
- my $newshod = sprintf "%02d", (int $shod + 1);
+ for my $hod (sort { $a <=> $b } keys %{$hsurp}) {
+ my $spls = int $hsurp->{$hod}{surplswh};
+ my $newshod = sprintf "%02d", (int $hod + 1);
+ my $nhr = $hsurp->{$hod}{nhr};
- for my $sbn (sort @batteries) { # jede Batterie
- my $bpinmax = $hsurp->{$shod}{$sbn}{bpinmax}; # Bat max. mögliche Ladelesitung
-
- if (!$hsurp->{$shod}{$sbn}{lcintime}) { # Ladesteuerung nicht "In Time"
- $hsurp->{$shod}{$sbn}{pneedmin} = $bpinmax;
+ 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
+ my $lowSocwh = $hsurp->{$hod}{$sbn}{lowSocwh}; # eingestellter lowSoc 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}
+ );
+
+ $runwh = min ($runwh, $sbatinstcap);
+ $hsurp->{$hod}{$sbn}{runwh} = sprintf "%.0f", $runwh; # Startwert für DebugLog
+
+ if (!$spls) { # Ladesteuerung nicht "In Time"
+ $hsurp->{$hod}{$sbn}{achievable} = 'undetermined, calculation is starting with next hour with surplus';
+ $hsurp->{$hod}{$sbn}{pneedmin} = $bpinmax;
- if ($hsurp->{$shod}{nhr} eq '00') {
- $otp->{$sbn}{target} = $bpinmax;
- storeReading ('Battery_ChargeOptTargetPower_'.$sbn, $bpinmax.' W');
+ $runwh += $hsurp->{$hod}{speff} / $befficiency; # um Verbrauch reduzieren
+ $hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", $runwh;
+
+ if ($nhr eq '00') {
+ $otp->{$sbn}{target} = $csocwh <= $lowSocwh ? $bpinreduced : $bpinmax;
}
next;
- }
-
- my $bpinreduced = BatteryVal ($name, $sbn, 'bpinreduced', 0); # Standardwert wenn z.B. kein Überschuß oder Zwangsladung vom Grid
- my $crgwh = BatteryVal ($name, $sbn, 'bchargewh', 0); # aktueller Ladezustand Batterie
- my $runwh = defined $hsurp->{$shod}{$sbn}{fcnextwh} ? # Auswahl des zu verwendenden Prognose-SOC (Wh)
- $hsurp->{$shod}{$sbn}{fcnextwh} :
- ( $hsurp->{$shod}{nhr} eq '00' ?
- $crgwh :
- $hsurp->{$shod}{$sbn}{initsocwh}
- );
+ }
- my $otpMargin = $hsurp->{$shod}{$sbn}{otpMargin};
- my $margin = defined $otpMargin ? $otpMargin : SFTYMARGIN_20;
+ my $otpMargin = $hsurp->{$hod}{$sbn}{otpMargin};
+ my $runwhneed = $sbatinstcap - $runwh;
- if (!$spls) { # auf kleine Sollladeleistung setzen wenn kein Überschuß
- $hsurp->{$shod}{$sbn}{pneedmin} = $bpinreduced;
-
- if ($hsurp->{$shod}{nhr} eq '00') {
- $otp->{$sbn}{target} = $bpinreduced;
- storeReading ('Battery_ChargeOptTargetPower_'.$sbn, $bpinreduced.' W');
- }
-
- next;
- }
+ my $fref = ___batFindMinPhWh ($hsurp, \@remaining_hods, $runwhneed, $befficiency);
+ my $needraw = min ($fref->{ph}, $spls); # Ladeleistung auf Surplus begrenzen
+
+ $needraw *= 1 + ($otpMargin / 100); # 1. Sicherheitsaufschlag
+ $needraw = $bpinmax if(!$hsurp->{$hod}{$sbn}{lcintime});
+ $needraw = sprintf "%.0f", $needraw;
+ $needraw = max ($needraw, $bpinreduced); # Mindestladeleistung bpinreduced sicherstellen
+ $needraw = min ($needraw, $bpinmax); # Begrenzung auf max. mögliche Batterieleistung
- my $sbatinstcap = $hsurp->{$shod}{$sbn}{batinstcap}; # Kapa dieser Batterie
- $runwh = min ($runwh, $sbatinstcap);
- my $runwhneed = $sbatinstcap - $runwh;
- my $needraw = $sphrs ? $runwhneed / $sphrs : $runwhneed; # Ladeleistung initial
- $needraw *= 1 + ($margin / 100); # Sicherheitsaufschlag
-
- $needraw = max (0, $needraw);
- $hsurp->{$shod}{$sbn}{runwh} = sprintf "%.0f", $runwh;
- $hsurp->{$shod}{$sbn}{sphrs} = $sphrs; # Reststunden mit diesem Überschuß
- my $pneedmin = sprintf "%.0f", $spls > $needraw ? # Mindestladeleistung bzw. Energie bei 1h (Wh)
- $needraw ? $needraw : $bpinreduced :
- $spls;
- $hsurp->{$shod}{$sbn}{pneedmin} = min ($pneedmin, $hsurp->{$shod}{$sbn}{bpinmax}); # Begrenzung auf max. mögliche Batterieleistung
-
- if (defined $hsurp->{$newshod}) {
- $hsurp->{$newshod}{$sbn}{fcnextwh} = min ($sbatinstcap, $runwh + $hsurp->{$shod}{$sbn}{pneedmin});
- }
-
- if ($hsurp->{$shod}{nhr} eq '00') {
- my $target = max ($bpinreduced, $hsurp->{$shod}{$sbn}{pneedmin});
-
- if (NexthoursVal ($name, 'NextHour00', 'DoN', 0)) {
- $target *= 1 + ($margin / 100); # 2. Sicherheitsaufschlag
- }
+ $hsurp->{$hod}{$sbn}{pneedmin} = $needraw;
+ $hsurp->{$hod}{$sbn}{achievable} = 'goal: '.(sprintf "%.0f", $runwhneed).' Wh -> '.($fref->{achievable} ? 'yes' : 'no');
+
+
+ ## NextHour 00 bearbeiten
+ ###########################
+ if ($nhr eq '00') {
+ my $target = $hsurp->{$hod}{$sbn}{pneedmin};
+ $target *= 1 + ($otpMargin / 100); # 2. Sicherheitsaufschlag
my $gfeedin = CurrentVal ($name, 'gridfeedin', 0); # aktuelle Netzeinspeisung
my $bpin = CurrentVal ($name, 'batpowerinsum', 0); # aktuelle Batterie Ladeleistung (Summe über alle Batterien)
my $inc = 0;
- if ( !$bpin && $gfeedin > $fipl ) {$inc = $gfeedin - $fipl} # Ladefreigabe wenn akt. keine Bat-Ladung UND akt. Einspeisung > Einspeiselimit der Anlage
- if ( $bpin && ($gfeedin - $bpin) > $fipl ) {$inc = $bpin + (($gfeedin - $bpin) - $fipl)} # Ladefreigabe wenn akt. Bat-Ladung UND Eispeisung - Bat-Ladung > Einspeiselimit der Anlage
-
-
+ if ( !$bpin && $gfeedin > $fipl ) {$inc = $gfeedin - $fipl} # Ladeleistung wenn akt. keine Bat-Ladung UND akt. Einspeisung > Einspeiselimit der Anlage
+ if ( $bpin && ($gfeedin - $bpin) > $fipl ) {$inc = $bpin + (($gfeedin - $bpin) - $fipl)} # Ladeleistung wenn akt. Bat-Ladung UND Eispeisung - Bat-Ladung > Einspeiselimit der Anlage
+
$target = sprintf "%.0f", max ($target, $inc); # Einspeiselimit berücksichtigen
- $target = min ($bpinmax, $target); # 2. Begrenzung auf max. mögliche Batterieleistung
+ $target = min (($csocwh <= $lowSocwh ? $bpinreduced : $bpinmax), $target); # 2. Begrenzung auf max. mögliche Batterieleistung bzw. bpinreduced bei Unterschreitung lowSoc
$otp->{$sbn}{target} = $target;
-
- storeReading ('Battery_ChargeOptTargetPower_'.$sbn, $target.' W');
- }
+ }
+
+
+
+ $hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", min ($sbatinstcap, $runwh # Endwert Prognose aktuelle Stunde
+ + $befficiency
+ * ($nhr eq '00'
+ ? $otp->{$sbn}{target}
+ : $hsurp->{$hod}{$sbn}{pneedmin}
+ )
+ );
+
+ $hsurp->{$newshod}{$sbn}{fcnextwh} = $hsurp->{$hod}{$sbn}{fcendwh}; # Startwert kommende Stunde
+ }
+ }
+
+return ($hsurp, $otp);
+}
+
+################################################################
+# Weiterschreibung übergebenen SoC in Wh, Rückgabe
+# weitergeschriebenen SoC in %
+################################################################
+sub ___batSocWhForecast {
+ my $paref = shift;
+
+
+return;
+}
+
+###############################################################################################
+# Errechnet minimal benötigte konstante Ladeleistung: $ph Wh via Binärsuche Iteration
+#
+# - Wenn die Summe aller surplswh geringer ist als der Bedarf, wird Ereq automatisch auf
+# diesen Maximalwert gesetzt und liefert so die tatsächlich erreichbare Energie.
+# - gewichtete Stundenkapazität @hods enthält die Stunden-Keys sortiert von der niedrigsten
+# bis zur höchsten Leistung. In jeder Binärsuche-Iteration addiert das Skript
+# min(ph, surplswh) für jede Stunde, wodurch die konstant gewählte Leistung ph gemäß der
+# verfügbaren Kapazität gewichtet wird.
+# - Rückgabe Nach X Iterationen steht $high als kleinstmöglicher Wert für ph bereit. Er
+# garantiert entweder das Erreichen von Ereq Wh oder – falls das Ziel unerreichbar war –
+# die vollständige Ausnutzung der vorhandenen Kapazität.
+###############################################################################################
+sub ___batFindMinPhWh {
+ my ($hsurp, $aref, $runwhneed, $befficiency) = @_;
+ my @hods = @$aref;
+
+ my $Ereq = $runwhneed; # 1. Benötigte Energie (Wh) bestimmen
+ my $achievable = 1;
+ my $total = 0; # 2. Gesamtkapazität aller Stunden mit PV-Überschuß ermitteln
+ $total += $hsurp->{$_}{surplswh} for @hods;
+
+ if ($total * $befficiency < $Ereq) {
+ $achievable = 0;
+ #$Ereq = $total; # 3. Wenn Ziel nicht erreichbar: Ereq auf Maximum setzen
+ }
+
+ my $low = 0; # 4. Binärsuche für konstante Ladeleistung ph (Wh/h)
+ my $high = max map { $hsurp->{$_}{surplswh} } @hods;
+ my $eps = 0.5; # minimale Genauigkeit in Wh (1e-3)
+ my $max_iter = 100; # Zwangsabbruch nach X Durchläufen
+ my $loop = 0;
+
+ while (($high - $low) > $eps) {
+ last if ++$loop > $max_iter;
+
+ my $mid = ($low + $high) / 2;
+ my $charged = 0;
+
+ for my $hod (@hods) {
+ my $cap = $hsurp->{$hod}{surplswh};
+ $charged += $mid < $cap ? $mid : $cap;
+ }
+
+ $charged >= $Ereq ? ($high = $mid) : ($low = $mid);
+ }
+
+ $high = max (0, $high);
+
+return { ph => (sprintf "%.0f", $high), iterations => $loop, blur => (sprintf "%.4f", ($high - $low)), achievable => $achievable };
+}
+
+################################################################
+# Speicherung Ergebnisse aus Batterie Lademanagement
+################################################################
+sub ___batChargeSaveResults {
+ my $paref = shift;
+ my $values = shift;
+
+ my $name = $paref->{name};
+ my $hsoc = $values->{hsoc}; # Referenz SoC-Hash
+ my $otp = $values->{otp}; # Referenz OTP-Hash
+ my $bn = $values->{bn}; # Batterie Nummer
+ my $nhr = $values->{nhr}; # zweistellige lfd. Nexthour
+ my $progsoc = $values->{progsoc}; # Prognose-SoC in %
+ my $socwh = $values->{socwh}; # Prognose-SoC in Wh
+ my $today = $values->{today}; # Statusbit aktueller Tag
+ my $hod = $values->{hod}; # Stunde des Tages
+ my $loopid = $values->{loopid}; # in welcher Loop ist sub aufgerufen?
+ my $strategy = $values->{strategy}; # welche Lade-Strategie wird verwendet
+
+ my $crel = $values->{crel}; # nur in Schleife 'loadRelease' mitgeben
+ my $labortCond = $values->{labortCond}; # nur in Schleife 'loadRelease' mitgeben
+ my $loadAbort = $values->{loadAbort}; # nur in Schleife 'loadRelease' mitgeben
+ my $cgbt = $values->{cgbt}; # nur in Schleife 'loadRelease' mitgeben
+ my $lcintime = $values->{lcintime}; # nur in Schleife 'loadRelease' mitgeben
+
+ ## in Schleife 'loadRelease' setzen
+ #####################################
+ if ($loopid eq 'LR') {
+ $data{$name}{nexthours}{'NextHour'.$nhr}{'rcdchargebat'.$bn} = $crel;
+ $data{$name}{nexthours}{'NextHour'.$nhr}{'lcintimebat'.$bn} = $lcintime if($cgbt); # nur einmal bei 'loadRelease' setzen -> Ladesteuerung "In Time", "nicht In Time" oder nicht verwendet
+ $data{$name}{nexthours}{'NextHour'.$nhr}{'strategybat'.$bn} = $strategy;
+
+ if ($nhr eq '00') {
+ storeReading ('Battery_ChargeUnrestricted_'.$bn, $crel);
+ storeReading ('Battery_ChargeAbort_'.$bn, $labortCond) if ($loadAbort); # Ladeabbruchbedingung
}
- $sphrs-- if($spls); # Reststunden mit Überschuß
- }
-
- ## Debuglog
- #############
- if ($paref->{debug} =~ /batteryManagement/) {
- Log3 ($name, 1, "$name DEBUG> ChargeOTP - The limit for grid feed-in is $fipl W");
- Log3 ($name, 1, "$name DEBUG> ChargeOTP - NOTE: The hours listed below are the estimated number of hours remaining on the current day with at least the respective PV surplus.");
-
- for my $k (sort { $a <=> $b } keys %{$hsurp}) {
- for my $bat (sort @batteries) {
- my $sphrs = defined $hsurp->{$k}{$bat}{sphrs} ?
- '('.($hsurp->{$k}{$bat}{sphrs} ? $hsurp->{$k}{$bat}{sphrs} : 1).' hrs)' :
- '';
-
- my $ssocwh = $hsurp->{$k}{$bat}{runwh} // '-';
- my $otpMargin = $hsurp->{$k}{$bat}{otpMargin};
- my $margin = defined $otpMargin ? $otpMargin : SFTYMARGIN_20;
- my $spls = int $hsurp->{$k}{surpls};
- my $needmin = max (BatteryVal ($name, $bat, 'bpinreduced', 0), $hsurp->{$k}{$bat}{pneedmin} // 0);
-
- if ($hsurp->{$k}{nhr} eq '00') { # Target für aktuelle Stunde
- $needmin = $otp->{$bat}{target} // 0;
- }
-
- Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP - hod: $k, Start SoC: $ssocwh Wh, Surplus: $spls Wh $sphrs, OTP: $needmin W, safety: $margin %");
- }
+ if ($today && $hod) {
+ writeToHistory ( { paref => $paref, key => 'lcintimebat'.$bn, val => $lcintime, hour => $hod } ) if($cgbt);
+ writeToHistory ( { paref => $paref, key => 'strategybat'.$bn, val => $strategy, hour => $hod } );
}
}
-return $hsurp;
+ ## in Schleife 'optPower' setzen
+ ##################################
+ if ($loopid eq 'OTP') {
+ $data{$name}{nexthours}{'NextHour'.$nhr}{'rcdchargebat'.$bn} = $crel; # immer Freigabe bei optPower (für Anzeige)
+
+ if ($nhr eq '00') { # Target für aktuelle Stunde
+ my $needmin = $otp->{$bn}{target} // 0;
+ storeReading ('Battery_ChargeOptTargetPower_'.$bn, $needmin.' W');
+ }
+ }
+
+ ## abhängig von Strategie in entsprechender Schleife setzen
+ #############################################################
+ if (($loopid eq 'LR' && $strategy eq 'loadRelease') || ($loopid eq 'OTP' && $strategy eq 'optPower')) {
+ if ($today && $hod) {
+ writeToHistory ( { paref => $paref, key => 'batprogsoc'.$bn, val => $progsoc, hour => $hod } );
+ }
+
+ __createNextHoursSFCReadings ( {name => $name,
+ nhr => $nhr,
+ bn => $bn,
+ progsoc => $progsoc
+ }
+ ); # Readings NextHourXX_Bat_XX_ChargeForecast erstellen
+
+ $data{$name}{nexthours}{'NextHour'.$nhr}{'soc'.$bn} = $progsoc;
+
+ $hsoc->{$nhr}{socprogwhsum} += $socwh; # Hilfshash Aufsummierung SoC-Prognose (Wh) über alle Batterien
+ }
+
+return;
}
################################################################
@@ -12146,13 +12364,12 @@ sub _createSummaries {
$tdConFcTillSunset -= ($confc / 60) * $diflasth;
}
}
- else {
- $tomorrowSum->{PV} += $pvfc if(int($nhday) == int($tmoday));
-
- if (int($nhday) == int($datmoday)) {
- $daftertomSum->{PV} += $pvfc;
- $daftertomSum->{Consumption} += $confc;
- }
+ elsif ($nhday eq $tmoday) {
+ $tomorrowSum->{PV} += $pvfc;
+ }
+ elsif ($nhday eq $datmoday) {
+ $daftertomSum->{PV} += $pvfc;
+ $daftertomSum->{Consumption} += $confc;
}
}
@@ -14316,23 +14533,24 @@ return;
# erstellen
################################################################
sub _calcReadingsTomorrowPVFc {
- my $paref = shift;
- my $name = $paref->{name};
+ my $paref = shift;
+ my $name = $paref->{name};
+ my $t = $paref->{t};
my $hash = $defs{$name};
- my $h = $data{$name}{nexthours};
my $hods = AttrVal ($name, 'ctrlNextDayForecastReadings', '');
- return if(!keys %{$h} || !$hods);
+ return if(!$hods || !keys %{$data{$name}{nexthours}});
+
+ my $dt = timestringsFromOffset ($t, 86400);
+ my $tmoday = $dt->{day}; # Tomorrow Day (01..31)
- for my $idx (sort keys %{$h}) {
- my $today = NexthoursVal ($hash, $idx, 'today', 1);
- next if($today); # aktueller Tag wird nicht benötigt
+ for my $idx (sort keys %{$data{$name}{nexthours}}) {
+ my $day = NexthoursVal ($hash, $idx, 'day', 'dd');
+ next if($day ne $tmoday); # aktueller Tag wird nicht benötigt
my $hod = NexthoursVal ($hash, $idx, 'hourofday', '');
- next if(!$hod);
-
- next if($hods !~ /$hod/xs); # diese Stunde des Tages soll nicht erzeugt werden
+ next if(!$hod || $hods !~ /$hod/xs); # diese Stunde des Tages soll nicht erzeugt werden
my $pvfc = NexthoursVal ($hash, $idx, 'pvfc', 0);
@@ -17469,6 +17687,7 @@ sub _beamFillupBatValues {
$hh->{$day_str}{$time_str}{'rcdchargebat'.$bn} = $rcdc;
$hh->{$day_str}{$time_str}{'lcintimebat'.$bn} = NexthoursVal ($name, $idx, 'lcintimebat'.$bn, undef);
+ $hh->{$day_str}{$time_str}{'strategybat'.$bn} = NexthoursVal ($name, $idx, 'strategybat'.$bn, undef);
$hh->{$day_str}{$time_str}{'soc'.$bn} = NexthoursVal ($name, $idx, 'soc'.$bn, undef);
}
}
@@ -17491,6 +17710,7 @@ sub _beamFillupBatValues {
#####################################
$hfcg->{$kdx}{'rcdchargebat'.$bn} = $hh->{$ds}{$ts}{'rcdchargebat'.$bn} if(defined $hh->{$ds}{$ts}{'rcdchargebat'.$bn});
$hfcg->{$kdx}{'lcintimebat'.$bn} = $hh->{$ds}{$ts}{'lcintimebat'.$bn} if(defined $hh->{$ds}{$ts}{'lcintimebat'.$bn});
+ $hfcg->{$kdx}{'strategybat'.$bn} = $hh->{$ds}{$ts}{'strategybat'.$bn} if(defined $hh->{$ds}{$ts}{'strategybat'.$bn});
$hfcg->{$kdx}{'soc'.$bn} = $hh->{$ds}{$ts}{'soc'.$bn} if(defined $hh->{$ds}{$ts}{'soc'.$bn});
## Auffüllen mit History Werten (Achtung: Stundenverschieber relativ zu Nexthours)
@@ -17498,10 +17718,12 @@ sub _beamFillupBatValues {
if (!defined $hh->{$ds}{$ts}{'rcdchargebat'.$bn}) {
my $histsoc = HistoryVal ($hash, $ds, (sprintf "%02d", $ts+1), 'batsoc'.$bn, undef);
my $lcintime = HistoryVal ($hash, $ds, (sprintf "%02d", $ts+1), 'lcintimebat'.$bn, undef);
+ my $strategy = HistoryVal ($hash, $ds, (sprintf "%02d", $ts+1), 'strategybat'.$bn, undef);
if (defined $histsoc) {
$hfcg->{$kdx}{'rcdchargebat'.$bn} = 'hist';
$hfcg->{$kdx}{'lcintimebat'.$bn} = $lcintime;
+ $hfcg->{$kdx}{'strategybat'.$bn} = $strategy;
$hfcg->{$kdx}{'soc'.$bn} = $histsoc;
}
}
@@ -18095,6 +18317,11 @@ sub __batteryOnBeam {
$time_str = (split ":", $time_str)[0]; # Forum: https://forum.fhem.de/index.php?msg=1332721
my $soc = $hfcg->{$i}{'soc'.$bn};
my $lcintime = $hfcg->{$i}{'lcintimebat'.$bn}; # Lademanagement für Batterie XX ist aktiviert
+ my $strategy = $hfcg->{$i}{'strategybat'.$bn} // '-'; # Ladestrategie
+
+ my $stysymbol = $strategy eq 'loadRelease' ? 'ldreleas' :
+ $strategy eq 'optPower' ? 'optchpow' :
+ 'norate';
my ($bpower, $currsoc);
@@ -18112,7 +18339,7 @@ sub __batteryOnBeam {
flag => $hfcg->{$i}{'rcdchargebat'.$bn},
msg1 => $balias,
msg2 => $lcintime,
- msg3 => $htitles{ldreleas}{$lang},
+ msg3 => $htitles{$stysymbol}{$lang},
soc => $soc,
pcurr => $bpower,
lang => $lang
@@ -20906,7 +21133,7 @@ sub _listDataPoolPvHist {
$prdl .= "pprl${pn}: $pprl";
}
- my ($btotin, $batin, $btotout, $batout, $batmsoc, $batssoc, $batprogsoc, $batsoc, $lcintime);
+ my ($btotin, $batin, $btotout, $batout, $batmsoc, $batssoc, $batprogsoc, $batsoc, $lcintime, $lcstrategy);
for my $bn (1..MAXBATTERIES) { # + alle Batterien
$bn = sprintf "%02d", $bn;
my $hbtotin = HistoryVal ($name, $day, $key, 'batintotal'.$bn, '-');
@@ -20918,6 +21145,7 @@ sub _listDataPoolPvHist {
my $hbatprogsoc = HistoryVal ($name, $day, $key, 'batprogsoc'.$bn, '-');
my $hbatsoc = HistoryVal ($name, $day, $key, 'batsoc'.$bn, '-');
my $intime = HistoryVal ($name, $day, $key, 'lcintimebat'.$bn, '-');
+ my $strategy = HistoryVal ($name, $day, $key, 'strategybat'.$bn, '-');
if ($export eq 'csv') {
$hexp->{$day}{$key}{"BatteryInTotal${bn}"} = $hbtotin;
@@ -20929,6 +21157,7 @@ sub _listDataPoolPvHist {
$hexp->{$day}{$key}{"BatteryProgSoc${bn}"} = $hbatprogsoc;
$hexp->{$day}{$key}{"BatterySoc${bn}"} = $hbatsoc;
$hexp->{$day}{$key}{"BatteryLCinTime${bn}"} = $intime;
+ $hexp->{$day}{$key}{"BatteryStrategy${bn}"} = $strategy;
}
$btotin .= ', ' if($btotin);
@@ -20949,6 +21178,8 @@ sub _listDataPoolPvHist {
$batsoc .= "batsoc${bn}: $hbatsoc";
$lcintime .= ', ' if($lcintime);
$lcintime .= "lcintimebat${bn}: $intime";
+ $lcstrategy .= ', ' if($lcstrategy);
+ $lcstrategy .= "strategybat${bn}: $strategy";
}
$ret .= "\n " if($ret);
@@ -20981,7 +21212,9 @@ sub _listDataPoolPvHist {
$ret .= "\n " if($key ne '99');
$ret .= $lcintime if($key ne '99');
$ret .= "\n " if($key ne '99');
-
+ $ret .= $lcstrategy if($key ne '99');
+ $ret .= "\n " if($key ne '99');
+
$ret .= $batin;
$ret .= "\n ";
$ret .= $batout;
@@ -21382,16 +21615,19 @@ sub _listDataPoolNextHours {
my $socprgs = NexthoursVal ($name, $idx, 'socprogwhsum', '-');
my $dinrang = NexthoursVal ($name, $idx, 'DaysInRange', '-');
- my ($rcdbat, $socs, $lcintime);
+ my ($rcdbat, $socs, $lcintime, $lcstrategy);
for my $bn (1..MAXBATTERIES) { # alle Batterien
$bn = sprintf "%02d", $bn;
my $rcdcharge = NexthoursVal ($name, $idx, 'rcdchargebat'.$bn, '-');
my $intime = NexthoursVal ($name, $idx, 'lcintimebat'.$bn, '-');
+ my $strategy = NexthoursVal ($name, $idx, 'strategybat'.$bn, '-');
my $socxx = NexthoursVal ($name, $idx, 'soc'.$bn, '-');
$rcdbat .= ', ' if($rcdbat);
$rcdbat .= "rcdchargebat${bn}: $rcdcharge";
$lcintime .= ', ' if($lcintime);
$lcintime .= "lcintimebat${bn}: $intime";
+ $lcstrategy .= ', ' if($lcstrategy);
+ $lcstrategy .= "strategybat${bn}: $strategy";
$socs .= ', ' if($socs);
$socs .= "soc${bn}: $socxx";
}
@@ -21413,6 +21649,8 @@ sub _listDataPoolNextHours {
$sq .= $rcdbat;
$sq .= "\n ";
$sq .= $lcintime;
+ $sq .= "\n ";
+ $sq .= $lcstrategy;
}
return $sq;
@@ -26217,6 +26455,7 @@ to ensure that the system configuration is correct.
| today | has value '1' if start date on current day |
| rcdchargebatXX | Charging recommendation with full power for battery XX (1 - Yes, 0 - No) |
| lcintimebatXX | Charge management for battery XX is activated or will be activated (1 - Yes, 0 - No) |
+ | strategybatXX | the selected charging strategy |
| rr1c | Total precipitation during the last hour kg/m2 |
| rrange | range of total rain |
| socXX | current (NextHour00) or predicted SoC (%) of battery XX |
@@ -26268,6 +26507,7 @@ to ensure that the system configuration is correct.
| feedprice | Remuneration for the feed-in of one kWh. The currency of the price is defined in the setupMeterDev. |
| hourscsmeXX | total active hours of the day from ConsumerXX |
| lcintimebatXX | the charge management for battery XX was activated (1 - Yes, 0 - No) |
+ | strategybatXX | the selected charging strategy |
| minutescsmXX | total active minutes in the hour of ConsumerXX |
| plantderated | Timestamp of the first curtailment event of the system in this hour, otherwise '0' |
| pprlXX | Energy generation of producer XX (see attribute setupOtherProducerXX) in the hour (Wh) |
@@ -26427,9 +26667,11 @@ to ensure that the system configuration is correct.
| basynchron | Mode of processing received battery events |
| bcharge | current SoC (State of Charge) of the battery (%) |
| bchargewh | current SoC (State of Charge) of the battery (Wh) |
+ | befficiency | Storage efficiency (%) |
| binstcap | installed battery capacity (Wh) |
| bpowerin | current charging power (W) |
| bpinmax | maximum possible charging power (W) |
+ | bpinreduced | reduced charging power (W), e.g. when SoC <= lowSoC |
| bpowerout | current discharge power (W) |
| bpoutmax | maximum possible discharging power (W) |
| bloadAbortCond | general load termination condition (boolean) |
@@ -26852,7 +27094,7 @@ to ensure that the system configuration is correct.
ctrlBatSocManagementXX lowSoc=<Value> upSoC=<Value> [maxSoC=<Value>] [careCycle=<Value>]
[lcSlot=<hh:mm>-<hh:mm>] [loadAbort=<SoC1>:<MinPwr>:<SoC2>]
- [safetyMargin=<Value>[:<Value>]]
+ [safetyMargin=<Value>[:<Value>]] [loadStrategy=<Value>] [weightOwnUse=<Wert>]
If a battery device (setupBatteryDevXX) is installed, this attribute activates the battery SoC and charge management
for this battery device.
@@ -26897,6 +27139,11 @@ to ensure that the system configuration is correct.
| | If the current SoC falls below the specified SoC2, the Battery_ChargeAbort_XX=0 is set. |
| | If SoC2 is not specified, SoC2=SoC1. |
| | |
+ | loadStrategy | The selected charging strategy is taken into account when displaying the battery in bar graph. |
+ | | The generation of tax readings is not affected. The specification is optional. |
+ | | For more information on selecting a strategy, see german Wiki. |
+ | | Value: loadRelease or optPower, default: loadRelease |
+ | | |
| safetyMargin | When calculating the load clearance and optimized load capacity, safety margins are taken |
| | into account in the predicted load requirements. |
| | Deviating from the default, this parameter can be used to specify individual safety margins |
@@ -26905,6 +27152,11 @@ to ensure that the system configuration is correct.
| | surcharge used to calculate the optimized load capacity. Both values are percentages. |
| | Value: 0..100[:0..100] (integers) |
| | |
+ | weightOwnUse | Optional weighting of the hourly consumption forecast as an additional usable portion for |
+ | | battery charging in %. Technically, the available PV surplus is increased to calculate the |
+ | | optimized charging power by reducing the calculated consumption by the specified percentage. |
+ | | Value: 0..100 default: 0 |
+ | | |
@@ -26912,7 +27164,7 @@ to ensure that the system configuration is correct.
All SoC values are whole numbers in %. The following applies: 'lowSoc' < 'upSoC' < 'maxSoC'.
Example:
- attr <name> ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 lcSlot=11:00-17:30 loadAbort=99:40:90 safetyMargin=30
+ attr <name> ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 lcSlot=11:00-17:30 loadAbort=99:40:90 safetyMargin=30 weightOwnUse=20
@@ -27577,9 +27829,9 @@ to ensure that the system configuration is correct.
- setupBatteryDevXX <Battery Device Name> pin=<Readingname>:<Unit> pout=<Readingname>:<Unit> cap=<Option>
- [pinmax=<Integer>] [pinreduced=<Integer>] [poutmax=<Integer>] [intotal=<Readingname>:<Unit>]
- [outtotal=<Readingname>:<Unit>] [charge=<Readingname>] [asynchron=<Option>] [show=<Option>]
+ setupBatteryDevXX <Battery Device Name> pin=<Readingname>:<Unit> pout=<Readingname>:<Unit> cap=<Option>
+ [pinmax=<Integer>] [pinreduced=<Integer>] [poutmax=<Integer>] [intotal=<Readingname>:<Unit>] [efficiency=<Value>]
+ [outtotal=<Readingname>:<Unit>] [charge=<Readingname>] [asynchron=<Option>] [show=<Option>]
[label=<Option>] [[icon=<recomm>@<Color>]:[<charge>@<Color>]:[<discharge>@<Color>]:[<omit>@<Color>]]
Specifies an arbitrary Device and its Readings to deliver the battery performance data.
@@ -27618,6 +27870,11 @@ to ensure that the system configuration is correct.
| | |
| Unit | the respective unit (W,Wh,kW,kWh) |
| | |
+ | efficiency | Optional specification of the energy storage efficiency in %. This efficiency describes not |
+ | | only the battery itself, but also the chain of effects, including the inverters involved. |
+ | | Depending on the type of coupling and other factors, the typical efficiency is between 75 and 90%. |
+ | | Value: 0..100 default: 87 |
+ | | |
| icon | Icon and/or (only) color of the battery in the bar graph according to the status (optional). |
| | The identifier (e.g. blue), HEX value (e.g. #d9d9d9) or 'dyn' can be specified as the color. |
| | If 'dyn' is used, the icon is colored depending on the SoC value. |
@@ -28894,6 +29151,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| today | hat Wert '1' wenn Startdatum am aktuellen Tag |
| rcdchargebatXX | Aufladeempfehlung mit voller Leistung für Batterie XX (1 - Ja, 0 - Nein) |
| lcintimebatXX | Lademanagement für Batterie XX ist aktiviert bzw. wird aktiviert sein (1 - Ja, 0 - Nein) |
+ | strategybatXX | die gewählte Ladestrategie |
| rr1c | Gesamtniederschlag in der letzten Stunde kg/m2 |
| rrange | Bereich des Gesamtniederschlags |
| socXX | aktueller (NextHour00) oder prognostizierter SoC (%) der Batterie XX |
@@ -28946,6 +29204,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| avgcycmntscsmXX | durchschnittliche Dauer eines Einschaltzyklus des Tages von ConsumerXX in Minuten |
| hourscsmeXX | Summe Aktivstunden des Tages von ConsumerXX |
| lcintimebatXX | das Lademanagement für Batterie XX war aktiviert (1 - Ja, 0 - Nein) |
+ | strategybatXX | die gewählte Ladestrategie |
| minutescsmXX | Summe Aktivminuten in der Stunde von ConsumerXX |
| plantderated | Zeitstempel des ersten Abregelungsvorfalls der Anlage in dieser Stunde, sonst '0' |
| pprlXX | Energieerzeugung des Produzenten XX (siehe Attribut setupOtherProducerXX) in der Stunde (Wh) |
@@ -29105,9 +29364,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| basynchron | Modus der Verarbeitung empfangener Batterie-Events |
| bcharge | aktueller SoC (State of Charge) der Batterie (%) |
| bchargewh | aktueller SoC (State of Charge) der Batterie (Wh) |
+ | befficiency | Wirkungsgrad des Speichers (%) |
| binstcap | installierte Batteriekapazität (Wh) |
| bpowerin | momentane Ladeleistung (W) |
| bpinmax | maximal mögliche Ladeleistung (W) |
+ | bpinreduced | reduzierte Ladeleistung (W) z.B. wenn SoC <= lowSoC |
| bpowerout | momentane Entladeleistung (W) |
| bpoutmax | maximal mögliche Entladeleistung (W) |
| bloadAbortCond | generelle Ladeabbruchbedingung |
@@ -29529,7 +29790,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
ctrlBatSocManagementXX lowSoc=<Wert> upSoC=<Wert> [maxSoC=<Wert>] [careCycle=<Wert>]
[lcSlot=<hh:mm>-<hh:mm>] [loadAbort=<SoC1>:<MinPwr>:<SoC2>]
- [safetyMargin=<Wert>[:<Wert>]]
+ [safetyMargin=<Wert>[:<Wert>]] [loadStrategy=<Wert>] [weightOwnUse=<Wert>]
Sofern ein Batterie Device (setupBatteryDevXX) installiert ist, aktiviert dieses Attribut das Batterie
SoC- und Lade-Management für dieses Batteriegerät.
@@ -29575,6 +29836,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| | Fällt der aktuelle SoC wieder unter den SoC2, wird Battery_ChargeAbort_XX=0 gesetzt. |
| | Ist SoC2 nicht angegeben, gilt SoC2=SoC1. |
| | |
+ | loadStrategy | Bei der Anzeige der Batterie in der Balkengrafik wird die gewählte Ladestrategie berücksichtigt. |
+ | | Die Generierung der Steuerreadings wird nicht beeinflusst. Die Angabe ist optional. |
+ | | Weitere Informationen zur Auswahl der Strategie siehe Wiki. |
+ | | Wert: loadRelease oder optPower, default: loadRelease |
+ | | |
| safetyMargin | Bei der Berechnung der Ladefreigabe und optimierten Ladeleistung werden Sicherheitszuschläge |
| | auf den prognostizierten Ladungsbedarf berücksichtigt. |
| | Abweichend vom Default können mit diesem Parameter individuelle Sicherheitszuschläge getrennt |
@@ -29583,6 +29849,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| | Zuschlag bei der Berechnung der optimierten Ladeleistung. Beide Angaben sind Prozentwerte. |
| | Wert: 0..100[:0..100] (Ganzzahlen) |
| | |
+ | weightOwnUse | Optionale Gewichtung der stündlichen Verbrauchsprognose als zusätzlich verwendbaren Anteil zur |
+ | | Batterieladung in %. Technisch wird der verfügbare PV-Überschuß zur Berechnung der optimierten |
+ | | Ladeleistung erhöht indem der kalkulierte Verbrauch um den angegebenen Prozentsatz gesenkt wird. |
+ | | Wert: 0..100 default: 0 |
+ | | |
@@ -29590,7 +29861,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Alle SoC-Werte sind ganze Zahlen in %. Dabei gilt: 'lowSoc' < 'upSoC' < 'maxSoC'.
Beispiel:
- attr <name> ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 lcSlot=11:00-17:30 loadAbort=99:40:90 safetyMargin=30
+ attr <name> ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 lcSlot=11:00-17:30 loadAbort=99:40:90 safetyMargin=30 weightOwnUse=20
@@ -30254,7 +30525,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
setupBatteryDevXX <Batterie Device Name> pin=<Readingname>:<Einheit> pout=<Readingname>:<Einheit> cap=<Option>
- [pinmax=<Ganzzahl>] [pinreduced=<Ganzzahl>] [poutmax=<Ganzzahl>] [intotal=<Readingname>:<Einheit>]
+ [pinmax=<Ganzzahl>] [pinreduced=<Ganzzahl>] [poutmax=<Ganzzahl>] [intotal=<Readingname>:<Einheit>] [efficiency=<Wert>]
[outtotal=<Readingname>:<Einheit>] [charge=<Readingname>] [asynchron=<Option>] [show=<Option>]
[label=<Option>] [[icon=<empfohlen>@<Farbe>]:[<aufladen>@<Farbe>]:[<entladen>@<Farbe>]:[icon=<unterlassen>@<Farbe>]]
@@ -30293,6 +30564,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| | |
| Einheit | die jeweilige Einheit (W,Wh,kW,kWh) |
| | |
+ | efficiency | Optionale Angabe des Wirkungsgrades der Energiespeicherung in %. Dieser Wirkungsgrad beschreibt nicht |
+ | | nur die Batterie selbst, sondern die Wirkkette inkl. der betroffenen Wechselrichter. |
+ | | Je nach Koppelart und anderen Faktoren liegt der typische Wirkungsgrad zwischen 75 - 90 %. |
+ | | Wert: 0..100 default: 87 |
+ | | |
| icon | Icon und/oder (nur) Farbe der Batterie in der Balkengrafik entsprechend des Status (optional). |
| | Als Farbe kann der Bezeichner (z.B. blue), HEX-Wert (z.B. #d9d9d9) oder 'dyn' angegeben werden. |
| | Wird 'dyn' verwendet, erfolgt eine vom SoC-Wert abhängige Einfärbung des Icon. |
@@ -30315,6 +30591,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| | 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 |
+ | | |
diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm
index 96dda2f4c..269f5f909 100644
--- a/fhem/contrib/DS_Starter/76_SolarForecast.pm
+++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm
@@ -162,7 +162,8 @@ BEGIN {
my %vNotesIntern = (
"1.58.6" => "03.10.2025 __batChargeMgmt code changed, new sub ___batChargeSaveResults, remove reading Battery_ChargeRecommended_XX ".
"_calcReadingsTomorrowPVFc: bugfix generating readings of tomorrow ".
- "__batChargeOptTargetPower: complete rework, Attr ctrlBatSocManagementXX new keys 'loadStrategy', 'weightOwnUse' ",
+ "__batChargeOptTargetPower: complete rework, Attr ctrlBatSocManagementXX new keys 'loadStrategy', 'weightOwnUse' ".
+ "new battery key setupBatteryDevXX->efficiency ",
"1.58.5" => "24.09.2025 __batChargeOptTargetPower: fix if battery load control is deactivated ",
"1.58.4" => "23.09.2025 __batChargeOptTargetPower: user a better surplus value, excess based on average removed & some other code optimization ",
"1.58.3" => "17.09.2025 __batChargeOptTargetPower: minor code change, consider bpinmax & lcintime ",
@@ -466,7 +467,7 @@ use constant {
PRDEF => 0.9, # default Performance Ratio (PR)
SFTYMARGIN_20 => 20, # Sicherheitszuschlag 20%
SFTYMARGIN_50 => 50, # Sicherheitszuschlag 50%
- STOREFFDEF => 0.90, # default Batterie Effizienz (https://www.energie-experten.org/erneuerbare-energien/photovoltaik/stromspeicher/wirkungsgrad)
+ STOREFFDEF => 87, # default Batterie Effizienz (https://www.energie-experten.org/erneuerbare-energien/photovoltaik/stromspeicher/wirkungsgrad)
TEMPCOEFFDEF => -0.45, # default Temperaturkoeffizient Pmpp (%/°C) lt. Datenblatt Solarzelle
TEMPMODINC => 25, # default Temperaturerhöhung an Solarzellen gegenüber Umgebungstemperatur bei wolkenlosem Himmel
TEMPBASEDEF => 25, # Temperatur Module bei Nominalleistung
@@ -7410,6 +7411,7 @@ sub _attrBatteryDev { ## no critic "not used"
show => { comp => '(?:[0-3](?::(?:top|bottom))?)', must => 0, act => 0 },
label => { comp => '(none|below|beside)', must => 0, act => 0 },
asynchron => { comp => '(0|1)', must => 0, act => 0 },
+ efficiency => { comp => '(100|[1-9]?[0-9])', must => 0, act => 0 },
};
if ($paref->{cmd} eq 'set') {
@@ -7467,6 +7469,7 @@ sub _attrBatteryDev { ## no critic "not used"
delete $data{$name}{batteries}{$bn}{bpinmax};
delete $data{$name}{batteries}{$bn}{bpinreduced};
delete $data{$name}{batteries}{$bn}{bpoutmax};
+ delete $data{$name}{batteries}{$bn}{befficiency};
}
elsif ($paref->{cmd} eq 'del') {
readingsDelete ($hash, 'Current_PowerBatIn_'.$bn);
@@ -7526,7 +7529,7 @@ sub _attrBatSocManagement { ## no critic "not used"
loadAbort => { comp => '(?:100|[1-9]?[0-9]):\d+(?::(?:100|[1-9]?[0-9]))?', must => 0, act => 0 },
safetyMargin => { comp => '(?:100|[1-9]?\d)(?::(?:100|[1-9]?\d))?', must => 0, act => 0 },
loadStrategy => { comp => '(loadRelease|optPower)', must => 0, act => 0 },
- weightOwnUse => { comp => '(?:100|[1-9]?\d)(?::(?:100|[1-9]?\d))?', must => 0, act => 0 },
+ weightOwnUse => { comp => '(100|[1-9]?[0-9])', must => 0, act => 0 },
};
my ($a, $h) = parseParams ($aVal);
@@ -11119,7 +11122,7 @@ sub _transferBatteryValues {
my $instcap = $h->{cap}; # numerischer Wert (Wh) oder Readingname installierte Batteriekapazität
my $pinmax = $h->{pinmax} // INFINITE; # max. mögliche Ladeleistung
my $pinreduced = $h->{pinreduced} // $pinmax; # reduzierte Ladeleistung (z.B. bei Ladung aus dem Grid)
- my $poutmax = $h->{poutmax} // INFINITE; # max. mögliche Entladeleistung
+ my $poutmax = $h->{poutmax} // INFINITE; # max. mögliche Entladeleistung
next if(!$pin || !$pou);
@@ -11306,6 +11309,7 @@ sub _transferBatteryValues {
$data{$name}{batteries}{$bn}{bposingraph} = $pos; # Anzeigeposition in Balkengrafik
$data{$name}{batteries}{$bn}{blabel} = $label; # Batterie SoC-Beschriftung in Balkengrafik
$data{$name}{batteries}{$bn}{bchargewh} = BatteryVal ($name, $bn, 'binstcap', 0) * $soc / 100; # Batterie SoC (Wh)
+ $data{$name}{batteries}{$bn}{befficiency} = $h->{efficiency}; # Speicherwirkungsgrad
$num++;
$socsum += $soc;
@@ -11663,6 +11667,7 @@ sub _batChargeMgmt {
my $bpoutmax = BatteryVal ($name, $bn, 'bpoutmax', INFINITE); # max. mögliche Entladeleistung W
my $bpowerin = BatteryVal ($name, $bn, 'bpowerin', INFINITE); # aktuelle Ladeleistung W
my $bpinreduced = BatteryVal ($name, $bn, 'bpinreduced', 0); # Standardwert bei <=lowSoC -> Anforderungsladung vom Grid
+ my $befficiency = BatteryVal ($name, $bn, 'befficiency', STOREFFDEF) / 100; # Speicherwirkungsgrad
my $cgbt = AttrVal ($name, 'ctrlBatSocManagement'.$bn, undef);
my $sf = __batCapShareFactor ($hash, $bn); # Anteilsfaktor der Batterie XX Kapazität an Gesamtkapazität
my $strategy = 'loadRelease'; # 'loadRelease' oder 'optPower'
@@ -11670,7 +11675,7 @@ sub _batChargeMgmt {
my $lowSoc = 0;
my $loadAbort = '';
my $lrMargin = SFTYMARGIN_50;
- my $otpMargin = SFTYMARGIN_20;
+ my $otpMargin = SFTYMARGIN_20;
my $lcslot;
if ($cgbt) {
@@ -11721,6 +11726,7 @@ sub _batChargeMgmt {
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - General load termination condition: $labortCond");
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - control time Slot - Slot start: $lcstart, Slot end: $lcend");
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - Installed Battery capacity: $batinstcap Wh, Percentage of total capacity: ".(sprintf "%.1f", $sf*100)." %");
+ Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - Battery efficiency used: ".($befficiency * 100)." %");
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeMgmt - The PV generation, consumption and surplus listed below are based on the battery's share of total installed capacity!");
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeLR - used safety margin: $lrMargin %");
Log3 ($name, 1, "$name DEBUG> Bat $bn ChargeLR - weighted self-consumption: $wou %");
@@ -11823,6 +11829,7 @@ sub _batChargeMgmt {
$hsurp->{$fd}{$hod}{$bn}{stt} = $stt; # Day/Time für Debuglog
$hsurp->{$fd}{$hod}{$bn}{strategy} = $strategy; # Ladestrategie
$hsurp->{$fd}{$hod}{$bn}{weightOwnUse} = $wou; # Gewichtung Prognose-Verbrauch als Anteil "Eigennutzung" (https://forum.fhem.de/index.php?msg=1348429)
+ $hsurp->{$fd}{$hod}{$bn}{befficiency} = $befficiency; # Speicherwirkungsgrad
}
## SOC-Prognose LR
@@ -11833,8 +11840,8 @@ sub _batChargeMgmt {
$speff < 0 ? ($speff <= -$bpoutmax ? -$bpoutmax : $speff) :
$speff;
- my $delta = $speff > 0 ? ($crel ? $speff * STOREFFDEF : 0) : # PV Überschuß (d.h. Aufladung) nur einbeziehen wenn Ladefreigabe
- $speff < 0 ? $speff / STOREFFDEF : # Verbrauch einbeziehen
+ my $delta = $speff > 0 ? ($crel ? $speff * $befficiency : 0) : # PV Überschuß (d.h. Aufladung) nur einbeziehen wenn Ladefreigabe
+ $speff < 0 ? $speff / $befficiency : # Verbrauch einbeziehen
0;
$socwh += $delta;
@@ -12025,7 +12032,8 @@ sub __batChargeOptTargetPower {
my $lowSocwh = $hsurp->{$hod}{$sbn}{lowSocwh}; # eingestellter lowSoc 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' ?
@@ -12040,7 +12048,7 @@ sub __batChargeOptTargetPower {
$hsurp->{$hod}{$sbn}{achievable} = 'undetermined, calculation is starting with next hour with surplus';
$hsurp->{$hod}{$sbn}{pneedmin} = $bpinmax;
- $runwh += $hsurp->{$hod}{speff} / STOREFFDEF; # um Verbrauch reduzieren
+ $runwh += $hsurp->{$hod}{speff} / $befficiency; # um Verbrauch reduzieren
$hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", $runwh;
if ($nhr eq '00') {
@@ -12053,7 +12061,7 @@ sub __batChargeOptTargetPower {
my $otpMargin = $hsurp->{$hod}{$sbn}{otpMargin};
my $runwhneed = $sbatinstcap - $runwh;
- my $fref = ___batFindMinPhWh ($hsurp, \@remaining_hods, $runwhneed);
+ my $fref = ___batFindMinPhWh ($hsurp, \@remaining_hods, $runwhneed, $befficiency);
my $needraw = min ($fref->{ph}, $spls); # Ladeleistung auf Surplus begrenzen
$needraw *= 1 + ($otpMargin / 100); # 1. Sicherheitsaufschlag
@@ -12069,7 +12077,7 @@ sub __batChargeOptTargetPower {
## NextHour 00 bearbeiten
###########################
if ($nhr eq '00') {
- my $target = max ($bpinreduced, $hsurp->{$hod}{$sbn}{pneedmin});
+ my $target = $hsurp->{$hod}{$sbn}{pneedmin};
$target *= 1 + ($otpMargin / 100); # 2. Sicherheitsaufschlag
my $gfeedin = CurrentVal ($name, 'gridfeedin', 0); # aktuelle Netzeinspeisung
@@ -12086,10 +12094,13 @@ sub __batChargeOptTargetPower {
- $hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", min ($sbatinstcap, $runwh + ($nhr eq '00' ? # Endwert Prognose aktuelle Stunde
- $otp->{$sbn}{target} :
- $hsurp->{$hod}{$sbn}{pneedmin}
- ));
+ $hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", min ($sbatinstcap, $runwh # Endwert Prognose aktuelle Stunde
+ + $befficiency
+ * ($nhr eq '00'
+ ? $otp->{$sbn}{target}
+ : $hsurp->{$hod}{$sbn}{pneedmin}
+ )
+ );
$hsurp->{$newshod}{$sbn}{fcnextwh} = $hsurp->{$hod}{$sbn}{fcendwh}; # Startwert kommende Stunde
}
@@ -12123,7 +12134,7 @@ return;
# die vollständige Ausnutzung der vorhandenen Kapazität.
###############################################################################################
sub ___batFindMinPhWh {
- my ($hsurp, $aref, $runwhneed) = @_;
+ my ($hsurp, $aref, $runwhneed, $befficiency) = @_;
my @hods = @$aref;
my $Ereq = $runwhneed; # 1. Benötigte Energie (Wh) bestimmen
@@ -12131,7 +12142,7 @@ sub ___batFindMinPhWh {
my $total = 0; # 2. Gesamtkapazität aller Stunden mit PV-Überschuß ermitteln
$total += $hsurp->{$_}{surplswh} for @hods;
- if ($total < $Ereq) {
+ if ($total * $befficiency < $Ereq) {
$achievable = 0;
#$Ereq = $total; # 3. Wenn Ziel nicht erreichbar: Ereq auf Maximum setzen
}
@@ -26656,9 +26667,11 @@ to ensure that the system configuration is correct.
| basynchron | Mode of processing received battery events |
| bcharge | current SoC (State of Charge) of the battery (%) |
| bchargewh | current SoC (State of Charge) of the battery (Wh) |
+ | befficiency | Storage efficiency (%) |
| binstcap | installed battery capacity (Wh) |
| bpowerin | current charging power (W) |
| bpinmax | maximum possible charging power (W) |
+ | bpinreduced | reduced charging power (W), e.g. when SoC <= lowSoC |
| bpowerout | current discharge power (W) |
| bpoutmax | maximum possible discharging power (W) |
| bloadAbortCond | general load termination condition (boolean) |
@@ -27816,9 +27829,9 @@ to ensure that the system configuration is correct.
- setupBatteryDevXX <Battery Device Name> pin=<Readingname>:<Unit> pout=<Readingname>:<Unit> cap=<Option>
- [pinmax=<Integer>] [pinreduced=<Integer>] [poutmax=<Integer>] [intotal=<Readingname>:<Unit>]
- [outtotal=<Readingname>:<Unit>] [charge=<Readingname>] [asynchron=<Option>] [show=<Option>]
+ setupBatteryDevXX <Battery Device Name> pin=<Readingname>:<Unit> pout=<Readingname>:<Unit> cap=<Option>
+ [pinmax=<Integer>] [pinreduced=<Integer>] [poutmax=<Integer>] [intotal=<Readingname>:<Unit>] [efficiency=<Value>]
+ [outtotal=<Readingname>:<Unit>] [charge=<Readingname>] [asynchron=<Option>] [show=<Option>]
[label=<Option>] [[icon=<recomm>@<Color>]:[<charge>@<Color>]:[<discharge>@<Color>]:[<omit>@<Color>]]
Specifies an arbitrary Device and its Readings to deliver the battery performance data.
@@ -27857,6 +27870,11 @@ to ensure that the system configuration is correct.
| | |
| Unit | the respective unit (W,Wh,kW,kWh) |
| | |
+ | efficiency | Optional specification of the energy storage efficiency in %. This efficiency describes not |
+ | | only the battery itself, but also the chain of effects, including the inverters involved. |
+ | | Depending on the type of coupling and other factors, the typical efficiency is between 75 and 90%. |
+ | | Value: 0..100 default: 87 |
+ | | |
| icon | Icon and/or (only) color of the battery in the bar graph according to the status (optional). |
| | The identifier (e.g. blue), HEX value (e.g. #d9d9d9) or 'dyn' can be specified as the color. |
| | If 'dyn' is used, the icon is colored depending on the SoC value. |
@@ -29346,9 +29364,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| basynchron | Modus der Verarbeitung empfangener Batterie-Events |
| bcharge | aktueller SoC (State of Charge) der Batterie (%) |
| bchargewh | aktueller SoC (State of Charge) der Batterie (Wh) |
+ | befficiency | Wirkungsgrad des Speichers (%) |
| binstcap | installierte Batteriekapazität (Wh) |
| bpowerin | momentane Ladeleistung (W) |
| bpinmax | maximal mögliche Ladeleistung (W) |
+ | bpinreduced | reduzierte Ladeleistung (W) z.B. wenn SoC <= lowSoC |
| bpowerout | momentane Entladeleistung (W) |
| bpoutmax | maximal mögliche Entladeleistung (W) |
| bloadAbortCond | generelle Ladeabbruchbedingung |
@@ -30505,7 +30525,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
setupBatteryDevXX <Batterie Device Name> pin=<Readingname>:<Einheit> pout=<Readingname>:<Einheit> cap=<Option>
- [pinmax=<Ganzzahl>] [pinreduced=<Ganzzahl>] [poutmax=<Ganzzahl>] [intotal=<Readingname>:<Einheit>]
+ [pinmax=<Ganzzahl>] [pinreduced=<Ganzzahl>] [poutmax=<Ganzzahl>] [intotal=<Readingname>:<Einheit>] [efficiency=<Wert>]
[outtotal=<Readingname>:<Einheit>] [charge=<Readingname>] [asynchron=<Option>] [show=<Option>]
[label=<Option>] [[icon=<empfohlen>@<Farbe>]:[<aufladen>@<Farbe>]:[<entladen>@<Farbe>]:[icon=<unterlassen>@<Farbe>]]
@@ -30544,6 +30564,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| | |
| Einheit | die jeweilige Einheit (W,Wh,kW,kWh) |
| | |
+ | efficiency | Optionale Angabe des Wirkungsgrades der Energiespeicherung in %. Dieser Wirkungsgrad beschreibt nicht |
+ | | nur die Batterie selbst, sondern die Wirkkette inkl. der betroffenen Wechselrichter. |
+ | | Je nach Koppelart und anderen Faktoren liegt der typische Wirkungsgrad zwischen 75 - 90 %. |
+ | | Wert: 0..100 default: 87 |
+ | | |
| icon | Icon und/oder (nur) Farbe der Batterie in der Balkengrafik entsprechend des Status (optional). |
| | Als Farbe kann der Bezeichner (z.B. blue), HEX-Wert (z.B. #d9d9d9) oder 'dyn' angegeben werden. |
| | Wird 'dyn' verwendet, erfolgt eine vom SoC-Wert abhängige Einfärbung des Icon. |
@@ -30566,6 +30591,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| | 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 |
+ | | |