2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-16 16:56:04 +00:00

76_Solarforcast: contrib 1.6.0

git-svn-id: https://svn.fhem.de/fhem/trunk@28303 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2023-12-21 10:05:54 +00:00
parent e8ee4af07e
commit c11029a59b

View File

@ -155,7 +155,7 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.6.0" => "20.12.2023 store daily batmaxsoc in pvHistory, new attr ctrlBatSocManagement, reading Battery_OptimumTargetSoC ". "1.6.0" => "21.12.2023 store daily batmaxsoc in pvHistory, new attr ctrlBatSocManagement, reading Battery_OptimumTargetSoC ".
"currentBatteryDev: new optional key 'cap', adapt cloud2bin,temp2bin,rain2bin ". "currentBatteryDev: new optional key 'cap', adapt cloud2bin,temp2bin,rain2bin ".
"minor internal changes, isAddSwitchOffCond: change hysteresis algo, ctrlDebug: new entry batteryManagement ". "minor internal changes, isAddSwitchOffCond: change hysteresis algo, ctrlDebug: new entry batteryManagement ".
"check longitude, latitude in general audit, use coordinates (if set) for sun calc ", "check longitude, latitude in general audit, use coordinates (if set) for sun calc ",
@ -472,7 +472,7 @@ my $defmaxvar = 0.5;
my $definterval = 70; # Standard Abfrageintervall my $definterval = 70; # Standard Abfrageintervall
my $defslidenum = 3; # max. Anzahl der Arrayelemente in Schieberegistern my $defslidenum = 3; # max. Anzahl der Arrayelemente in Schieberegistern
my $maxSoCdef = 95; # default Wert (%) auf den die Batterie maximal aufgeladen werden soll bzw. als aufgeladen gilt my $maxSoCdef = 95; # default Wert (%) auf den die Batterie maximal aufgeladen werden soll bzw. als aufgeladen gilt
my $carecycledef = 30; # max. Anzahl Tage die zwischen der Batterieladung auf maxSoC liegen dürfen my $carecycledef = 20; # max. Anzahl Tage die zwischen der Batterieladung auf maxSoC liegen dürfen
my $batSocChgDay = 5; # prozentuale SoC Änderung pro Tag my $batSocChgDay = 5; # prozentuale SoC Änderung pro Tag
my @widgetreadings = (); # Array der Hilfsreadings als Attributspeicher my @widgetreadings = (); # Array der Hilfsreadings als Attributspeicher
@ -1827,6 +1827,8 @@ sub _setbatteryDevice { ## no critic "not used"
delete $data{$type}{$name}{circular}{'99'}{batintot}; delete $data{$type}{$name}{circular}{'99'}{batintot};
delete $data{$type}{$name}{circular}{'99'}{initdaybatouttot}; delete $data{$type}{$name}{circular}{'99'}{initdaybatouttot};
delete $data{$type}{$name}{circular}{'99'}{batouttot}; delete $data{$type}{$name}{circular}{'99'}{batouttot};
delete $data{$type}{$name}{circular}{'99'}{lastTsMaxSocRchd};
delete $data{$type}{$name}{circular}{'99'}{nextTsMaxSocChge};
readingsSingleUpdate ($hash, "currentBatteryDev", $arg, 1); readingsSingleUpdate ($hash, "currentBatteryDev", $arg, 1);
createAssociatedWith ($hash); createAssociatedWith ($hash);
@ -2315,10 +2317,10 @@ sub _setreset { ## no critic "not used"
} }
if ($prop eq 'currentBatterySet') { if ($prop eq 'currentBatterySet') {
readingsDelete ($hash, 'Current_PowerBatIn'); readingsDelete ($hash, 'Current_PowerBatIn');
readingsDelete ($hash, 'Current_PowerBatOut'); readingsDelete ($hash, 'Current_PowerBatOut');
readingsDelete ($hash, 'Current_BatCharge'); readingsDelete ($hash, 'Current_BatCharge');
readingsDelete ($hash, 'Battery_OptimumTargetSoC'); deleteReadingspec ($hash, 'Battery_.*');
undef @{$data{$type}{$name}{current}{socslidereg}}; undef @{$data{$type}{$name}{current}{socslidereg}};
delete $data{$type}{$name}{circular}{'99'}{lastTsMaxSocRchd}; delete $data{$type}{$name}{circular}{'99'}{lastTsMaxSocRchd};
delete $data{$type}{$name}{circular}{'99'}{nextTsMaxSocChge}; delete $data{$type}{$name}{circular}{'99'}{nextTsMaxSocChge};
@ -4318,8 +4320,11 @@ sub Attr {
} }
} }
else { else {
deleteReadingspec ($hash, 'Battery_OptimumTargetSoC'); deleteReadingspec ($hash, 'Battery_.*');
} }
delete $data{$type}{$name}{circular}{'99'}{lastTsMaxSocRchd};
delete $data{$type}{$name}{circular}{'99'}{nextTsMaxSocChge};
} }
if($aName eq 'ctrlGenPVdeviation' && $aVal eq 'daily') { if($aName eq 'ctrlGenPVdeviation' && $aVal eq 'daily') {
@ -5494,27 +5499,17 @@ sub _transferWeatherValues {
my $fcname = ReadingsVal($name, 'currentWeatherDev', ""); # Weather Forecast Device my $fcname = ReadingsVal($name, 'currentWeatherDev', ""); # Weather Forecast Device
return if(!$fcname || !$defs{$fcname}); return if(!$fcname || !$defs{$fcname});
my $err = checkdwdattr ($name,$fcname,\@dweattrmust); my $err = checkdwdattr ($name, $fcname, \@dweattrmust);
$paref->{state} = $err if($err); $paref->{state} = $err if($err);
my $type = $paref->{type}; debugLog ($paref, 'collectData', "collect Weather data - device: $fcname =>");
debugLog ($paref, "collectData", "collect Weather data - device: $fcname =>"); my $time_str;
my $type = $paref->{type};
my ($time_str); $paref->{fcname} = $fcname;
my ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss) = __sunRS ($paref); # Sonnenauf- und untergang
my $fc0_sr = ReadingsVal ($fcname, "fc0_SunRise", "23:59"); # Sonnenaufgang heute delete $paref->{fcname};
my $fc0_ss = ReadingsVal ($fcname, "fc0_SunSet", "00:00"); # Sonnenuntergang heute
my $fc1_sr = ReadingsVal ($fcname, "fc1_SunRise", "23:59"); # Sonnenaufgang morgen
my $fc1_ss = ReadingsVal ($fcname, "fc1_SunSet", "00:00"); # Sonnenuntergang morgen
($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss) = __sunRSbyCoordinates ( { fc0_sr => $fc0_sr, # mehr Genauigkeit wenn latitude/longitude Koordinaten gesetzt
fc0_ss => $fc0_ss,
fc1_sr => $fc1_sr,
fc1_ss => $fc1_ss,
t => $t
}
);
$data{$type}{$name}{current}{sunriseToday} = $date.' '.$fc0_sr.':00'; $data{$type}{$name}{current}{sunriseToday} = $date.' '.$fc0_sr.':00';
$data{$type}{$name}{current}{sunriseTodayTs} = timestringToTimestamp ($date.' '.$fc0_sr.':00'); $data{$type}{$name}{current}{sunriseTodayTs} = timestringToTimestamp ($date.' '.$fc0_sr.':00');
@ -5522,7 +5517,7 @@ sub _transferWeatherValues {
$data{$type}{$name}{current}{sunsetToday} = $date.' '.$fc0_ss.':00'; $data{$type}{$name}{current}{sunsetToday} = $date.' '.$fc0_ss.':00';
$data{$type}{$name}{current}{sunsetTodayTs} = timestringToTimestamp ($date.' '.$fc0_ss.':00'); $data{$type}{$name}{current}{sunsetTodayTs} = timestringToTimestamp ($date.' '.$fc0_ss.':00');
debugLog ($paref, "collectData", "sunrise/sunset today: $fc0_sr / $fc0_ss, sunrise/sunset tomorrow: $fc1_sr / $fc1_ss"); debugLog ($paref, 'collectData', "sunrise/sunset today: $fc0_sr / $fc0_ss, sunrise/sunset tomorrow: $fc1_sr / $fc1_ss");
storeReading ('Today_SunRise', $fc0_sr); storeReading ('Today_SunRise', $fc0_sr);
storeReading ('Today_SunSet', $fc0_ss); storeReading ('Today_SunSet', $fc0_ss);
@ -5535,7 +5530,7 @@ sub _transferWeatherValues {
my $fc1_ss_round = sprintf "%02d", (split ":", $fc1_ss)[0]; my $fc1_ss_round = sprintf "%02d", (split ":", $fc1_ss)[0];
for my $num (0..46) { for my $num (0..46) {
my ($fd,$fh) = _calcDayHourMove ($chour, $num); my ($fd, $fh) = _calcDayHourMove ($chour, $num);
last if($fd > 1); last if($fd > 1);
my $fh1 = $fh+1; my $fh1 = $fh+1;
@ -5559,7 +5554,7 @@ sub _transferWeatherValues {
my $txt = ReadingsVal($fcname, "fc${fd}_${fh2}_wwd", ''); my $txt = ReadingsVal($fcname, "fc${fd}_${fh2}_wwd", '');
debugLog ($paref, "collectData", "wid: fc${fd}_${fh1}_ww, val: $wid, txt: $txt, cc: $neff, rp: $r101, temp: $temp"); debugLog ($paref, 'collectData', "wid: fc${fd}_${fh1}_ww, val: $wid, txt: $txt, cc: $neff, rp: $r101, temp: $temp");
$time_str = "NextHour".sprintf "%02d", $num; $time_str = "NextHour".sprintf "%02d", $num;
$data{$type}{$name}{nexthours}{$time_str}{weatherid} = $wid; $data{$type}{$name}{nexthours}{$time_str}{weatherid} = $wid;
@ -5608,25 +5603,31 @@ return;
################################################################ ################################################################
# Sonnenauf- und untergang bei gesetzten global # Sonnenauf- und untergang bei gesetzten global
# latitude/longitude Koordinaten berechnen # latitude/longitude Koordinaten berechnen, sonst aus DWD
# Device extrahieren
################################################################ ################################################################
sub __sunRSbyCoordinates { sub __sunRS {
my $paref = shift; my $paref = shift;
my $fc0_sr = $paref->{fc0_sr}; my $t = $paref->{t}; # aktuelle Zeit
my $fc0_ss = $paref->{fc0_ss}; my $fcname = $paref->{fcname};
my $fc1_sr = $paref->{fc1_sr};
my $fc1_ss = $paref->{fc1_ss}; my ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss);
my $t = $paref->{t}; # aktuelle Zeit
my ($cset, $lat, $lon) = locCoordinates(); my ($cset, $lat, $lon) = locCoordinates();
return ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss) if(!$t || !$cset); # keine global latitude/longitude gesetzt if ($cset) {
my $alt = 'HORIZON=-0.833'; # default from https://metacpan.org/release/JFORGET/DateTime-Event-Sunrise-0.0505/view/lib/DateTime/Event/Sunrise.pm
my $alt = 'HORIZON=-0.833'; # default from https://metacpan.org/release/JFORGET/DateTime-Event-Sunrise-0.0505/view/lib/DateTime/Event/Sunrise.pm $fc0_sr = substr (sunrise_abs_dat ($t, $alt), 0, 5); # SunRise heute
$fc0_sr = substr (sunrise_abs_dat ($t, $alt), 0, 5); # SunRise heute $fc0_ss = substr (sunset_abs_dat ($t, $alt), 0, 5); # SunSet heute
$fc0_ss = substr (sunset_abs_dat ($t, $alt), 0, 5); # SunSet heute $fc1_sr = substr (sunrise_abs_dat ($t + 86400, $alt), 0, 5); # SunRise morgen
$fc1_sr = substr (sunrise_abs_dat ($t + 86400, $alt), 0, 5); # SunRise morgen $fc1_ss = substr (sunset_abs_dat ($t + 86400, $alt), 0, 5); # SunSet morgen
$fc1_ss = substr (sunset_abs_dat ($t + 86400, $alt), 0, 5); # SunSet morgen }
else { # Daten aus DWD Device holen
$fc0_sr = ReadingsVal ($fcname, 'fc0_SunRise', '23:59');
$fc0_ss = ReadingsVal ($fcname, 'fc0_SunSet', '00:00');
$fc1_sr = ReadingsVal ($fcname, 'fc1_SunRise', '23:59');
$fc1_ss = ReadingsVal ($fcname, 'fc1_SunSet', '00:00');
}
return ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss); return ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss);
} }
@ -6485,6 +6486,7 @@ sub _batSocTarget {
__batSaveSocKeyFigures ($paref) if($batcharge >= $maxsoc); __batSaveSocKeyFigures ($paref) if($batcharge >= $maxsoc);
delete $paref->{careCycle}; delete $paref->{careCycle};
my $chargereq = 0; # Ladeanforedrung wenn SoC unter Minimum SoC gefallen ist
my $target = $lowSoc; my $target = $lowSoc;
my $yday = strftime "%d", localtime($t - 86400); # Vortag (range 01 to 31) my $yday = strftime "%d", localtime($t - 86400); # Vortag (range 01 to 31)
my $batymaxsoc = HistoryVal ($hash, $yday, 99, 'batmaxsoc', 0); # gespeicherter max. SOC des Vortages my $batymaxsoc = HistoryVal ($hash, $yday, 99, 'batmaxsoc', 0); # gespeicherter max. SOC des Vortages
@ -6551,7 +6553,7 @@ sub _batSocTarget {
debugLog ($paref, 'batteryManagement', "SoC calc Step4 - note remaining days >$days2care< until care SoC -> Target: $target %"); debugLog ($paref, 'batteryManagement', "SoC calc Step4 - note remaining days >$days2care< until care SoC -> Target: $target %");
} }
else { else {
debugLog ($paref, 'batteryManagement', "SoC calc Step4 - calculation & activation of the care SoC postponed until after sunset "); debugLog ($paref, 'batteryManagement', "SoC calc Step4 - calculation & activation of the care SoC postponed until after sunset");
} }
## auf 5er Schritte anpassen (40,45,50,...) ## auf 5er Schritte anpassen (40,45,50,...)
@ -6561,7 +6563,16 @@ sub _batSocTarget {
my $add = $rmn <= 2.5 ? 0 : 5; my $add = $rmn <= 2.5 ? 0 : 5;
$target = ($flo * 5) + $add; $target = ($flo * 5) + $add;
debugLog ($paref, 'batteryManagement', "SoC calc Step5 - (final step) rounding the SoC to steps of 5 -> Target: $target %"); debugLog ($paref, 'batteryManagement', "SoC calc Step5 - rounding the SoC to steps of 5 -> Target: $target %");
## Zwangsladeanforderung
##########################
if ($batcharge < $target) {
$chargereq = 1;
}
debugLog ($paref, 'batteryManagement', "SoC calc Step6 - (final step) forced charging request: ".
($chargereq ? 'yes (battery charge is below minimum SoC)' : 'no (sufficient battery charge)'));
## pvHistory/Readings schreiben ## pvHistory/Readings schreiben
################################# #################################
@ -6572,6 +6583,7 @@ sub _batSocTarget {
delete $paref->{histname}; delete $paref->{histname};
storeReading ('Battery_OptimumTargetSoC', $target.' %'); storeReading ('Battery_OptimumTargetSoC', $target.' %');
storeReading ('Battery_ChargeRequest', $chargereq);
return; return;
} }
@ -16604,6 +16616,55 @@ to ensure that the system configuration is correct.
</li> </li>
<br> <br>
<a id="SolarForecast-attr-ctrlBatSocManagement"></a>
<li><b>ctrlBatSocManagement lowSoc=&lt;Value&gt; upSoC=&lt;Value&gt; [maxSoC=&lt;Value&gt;] [careCycle=&lt;Value&gt;] </b><br>
If a battery device (currentBatteryDev) is installed, this attribute activates the battery SoC management. <br>
The <b>Battery_OptimumTargetSoC</b> reading contains the optimum minimum SoC calculated by the module. <br>
The <b>Battery_ChargeRequest</b> reading is set to '1' if the current SoC has fallen below the minimum SoC. <br>
In this case, the battery should be forcibly charged, possibly with mains power. <br>
The readings can be used to control the SoC (State of Charge) and to control the charging current used for the
battery. <br>
The module itself does not control the battery. <br><br>
<ul>
<table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>lowSoc</b> </td><td>lower minimum SoC, the battery is not discharged lower than this value (> 0) </td></tr>
<tr><td> <b>upSoC</b> </td><td>upper minimum SoC, the usual value of the optimum SoC is between 'lowSoC' </td></tr>
<tr><td> </td><td>and this value. </td></tr>
<tr><td> <b>maxSoC</b> </td><td>Maximum minimum SoC, SoC value that must be reached at least every 'careCycle' days </td></tr>
<tr><td> </td><td>in order to balance the charge in the storage network. </td></tr>
<tr><td> </td><td>The specification is optional (&lt;= 100, default: 95) </td></tr>
<tr><td> <b>careCycle</b> </td><td>Maximum interval in days that may occur between two states of charge </td></tr>
<tr><td> </td><td>of at least 'maxSoC'. The specification is optional (default: 20) </td></tr>
</table>
</ul>
<br>
All values are whole numbers in %. The following applies: 'lowSoc' &lt; 'upSoC' &lt; 'maxSoC'. <br>
The optimum SoC is determined according to the following scheme: <br><br>
<table>
<colgroup> <col width="2%"> <col width="98%"> </colgroup>
<tr><td> 1. </td><td>Starting from 'lowSoc', the minimum SoC is increased by 5% on the following day but not higher than </td></tr>
<tr><td> </td><td>'upSoC', if 'maxSoC' has not been reached on the current day. </td></tr>
<tr><td> 2. </td><td>If 'maxSoC' is reached (again) on the current day, the minimum SoC is reduced by 5%, but not lower than 'lowSoc'. </td></tr>
<tr><td> 3. </td><td>Minimum SoC is reduced so that the predicted PV energy of the current or following day </td></tr>
<tr><td> </td><td>can be absorbed by the battery. Minimum SoC is not reduced lower than 'lowSoc'. </td></tr>
<tr><td> 4. </td><td>The module records the last point in time at the 'maxSoC' level in order to ensure a charge to 'maxSoC' </td></tr>
<tr><td> </td><td>at least every 'careCycle' days. For this purpose, the optimized SoC is changed depending on the remaining days </td></tr>
<tr><td> </td><td>until the next 'careCycle' point in such a way that 'maxSoC' is mathematically achieved by a daily 5% SoC increase </td></tr>
<tr><td> </td><td>at the 'careCycle' time point. If 'maxSoC' is reached in the meantime, the 'careCycle' period starts again. </td></tr>
</table>
<br>
<ul>
<b>Example: </b> <br>
attr &lt;name&gt; ctrlBatSocManagement lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 <br>
</ul>
</li>
<br>
<a id="SolarForecast-attr-ctrlConsRecommendReadings"></a> <a id="SolarForecast-attr-ctrlConsRecommendReadings"></a>
<li><b>ctrlConsRecommendReadings </b><br> <li><b>ctrlConsRecommendReadings </b><br>
Readings of the form <b>consumerXX_ConsumptionRecommended</b> are created for the selected consumers (number). <br> Readings of the form <b>consumerXX_ConsumptionRecommended</b> are created for the selected consumers (number). <br>
@ -18590,11 +18651,14 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<a id="SolarForecast-attr-ctrlBatSocManagement"></a> <a id="SolarForecast-attr-ctrlBatSocManagement"></a>
<li><b>ctrlBatSocManagement lowSoc=&lt;Wert&gt; upSoC=&lt;Wert&gt; [maxSoC=&lt;Wert&gt;] [careCycle=&lt;Wert&gt;] </b><br> <li><b>ctrlBatSocManagement lowSoc=&lt;Wert&gt; upSoC=&lt;Wert&gt; [maxSoC=&lt;Wert&gt;] [careCycle=&lt;Wert&gt;] </b><br>
Sofern ein Batterie Device (currentBatteryDev) installiert ist, aktiviert dieses Attribut das Batterie Sofern ein Batterie Device (currentBatteryDev) installiert ist, aktiviert dieses Attribut das Batterie
SoC-Management. SoC-Management. <br>
Dadurch wird das Reading <b>Battery_OptimumTargetSoC</b> erstellt. <br> Das Reading <b>Battery_OptimumTargetSoC</b> enthält den vom Modul berechneten optimalen Mindest-SoC. <br>
Dieses Reading kann zur Steuerung des SoC (State of Charge) im Batterie Device verwendet werden. <br> Das Reading <b>Battery_ChargeRequest</b> wird auf '1' gesetzt, wenn der aktuelle SoC unter den Mindest-SoC gefallen
ist. <br>
Anzugeben sind: <br><br> In diesem Fall sollte die Batterie, unter Umständen mit Netzstrom, zwangsgeladen werden. <br>
Die Readings können zur Steuerung des SoC (State of Charge) sowie zur Steuerung des verwendeten Ladestroms
der Batterie verwendet werden. <br>
Durch das Modul selbst findet keine Steuerung der Batterie statt. <br><br>
<ul> <ul>
<table> <table>
@ -18606,7 +18670,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> </td><td>werden muß um den Ladungsausgleich im Speicherverbund auszuführen. </td></tr> <tr><td> </td><td>werden muß um den Ladungsausgleich im Speicherverbund auszuführen. </td></tr>
<tr><td> </td><td>Die Angabe ist optional (&lt;= 100, default: 95) </td></tr> <tr><td> </td><td>Die Angabe ist optional (&lt;= 100, default: 95) </td></tr>
<tr><td> <b>careCycle</b> </td><td>maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' </td></tr> <tr><td> <b>careCycle</b> </td><td>maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' </td></tr>
<tr><td> </td><td>auftreten darf. Die Angabe ist optional (default: 30) </td></tr> <tr><td> </td><td>auftreten darf. Die Angabe ist optional (default: 20) </td></tr>
</table> </table>
</ul> </ul>
<br> <br>
@ -18623,7 +18687,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> </td><td>von der Batterie aufgenommen werden kann. Mindest-SoC wird nicht tiefer als 'lowSoc' verringert. </td></tr> <tr><td> </td><td>von der Batterie aufgenommen werden kann. Mindest-SoC wird nicht tiefer als 'lowSoc' verringert. </td></tr>
<tr><td> 4. </td><td>Das Modul erfasst den letzten Zeitpunkt am 'maxSoC'-Level, um eine Ladung auf 'maxSoC' mindestens alle 'careCycle' </td></tr> <tr><td> 4. </td><td>Das Modul erfasst den letzten Zeitpunkt am 'maxSoC'-Level, um eine Ladung auf 'maxSoC' mindestens alle 'careCycle' </td></tr>
<tr><td> </td><td>Tage zu realisieren. Zu diesem Zweck wird der optimierte SoC in Abhängigkeit der Resttage bis zum nächsten </td></tr> <tr><td> </td><td>Tage zu realisieren. Zu diesem Zweck wird der optimierte SoC in Abhängigkeit der Resttage bis zum nächsten </td></tr>
<tr><td> </td><td>'careCycle' Zeitpunkt derart verändert, dass durch eine tägliche 5% SoC-Steigerung 'maxSoC' am 'careCycle' Punkt </td></tr> <tr><td> </td><td>'careCycle' Zeitpunkt derart verändert, dass durch eine tägliche 5% SoC-Steigerung 'maxSoC' am 'careCycle' Zeitpunkt </td></tr>
<tr><td> </td><td>rechnerisch erreicht wird. Wird zwischenzeitlich 'maxSoC' erreicht, beginnt der 'careCycle' Zeitraum erneut. </td></tr> <tr><td> </td><td>rechnerisch erreicht wird. Wird zwischenzeitlich 'maxSoC' erreicht, beginnt der 'careCycle' Zeitraum erneut. </td></tr>
</table> </table>
<br> <br>