2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-25 16:05:19 +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 ac0ce53998
commit 6e2dd35571

View File

@ -155,7 +155,7 @@ BEGIN {
# Versions History intern
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 ".
"minor internal changes, isAddSwitchOffCond: change hysteresis algo, ctrlDebug: new entry batteryManagement ".
"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 $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 $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 @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'}{initdaybatouttot};
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);
createAssociatedWith ($hash);
@ -2318,7 +2320,7 @@ sub _setreset { ## no critic "not used"
readingsDelete ($hash, 'Current_PowerBatIn');
readingsDelete ($hash, 'Current_PowerBatOut');
readingsDelete ($hash, 'Current_BatCharge');
readingsDelete ($hash, 'Battery_OptimumTargetSoC');
deleteReadingspec ($hash, 'Battery_.*');
undef @{$data{$type}{$name}{current}{socslidereg}};
delete $data{$type}{$name}{circular}{'99'}{lastTsMaxSocRchd};
delete $data{$type}{$name}{circular}{'99'}{nextTsMaxSocChge};
@ -4318,8 +4320,11 @@ sub Attr {
}
}
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') {
@ -5497,24 +5502,14 @@ sub _transferWeatherValues {
my $err = checkdwdattr ($name, $fcname, \@dweattrmust);
$paref->{state} = $err if($err);
debugLog ($paref, 'collectData', "collect Weather data - device: $fcname =>");
my $time_str;
my $type = $paref->{type};
debugLog ($paref, "collectData", "collect Weather data - device: $fcname =>");
my ($time_str);
my $fc0_sr = ReadingsVal ($fcname, "fc0_SunRise", "23:59"); # Sonnenaufgang heute
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
}
);
$paref->{fcname} = $fcname;
my ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss) = __sunRS ($paref); # Sonnenauf- und untergang
delete $paref->{fcname};
$data{$type}{$name}{current}{sunriseToday} = $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}{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_SunSet', $fc0_ss);
@ -5559,7 +5554,7 @@ sub _transferWeatherValues {
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;
$data{$type}{$name}{nexthours}{$time_str}{weatherid} = $wid;
@ -5608,25 +5603,31 @@ return;
################################################################
# 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 $fc0_sr = $paref->{fc0_sr};
my $fc0_ss = $paref->{fc0_ss};
my $fc1_sr = $paref->{fc1_sr};
my $fc1_ss = $paref->{fc1_ss};
my $t = $paref->{t}; # aktuelle Zeit
my $fcname = $paref->{fcname};
my ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss);
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
$fc0_sr = substr (sunrise_abs_dat ($t, $alt), 0, 5); # SunRise 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_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);
}
@ -6485,6 +6486,7 @@ sub _batSocTarget {
__batSaveSocKeyFigures ($paref) if($batcharge >= $maxsoc);
delete $paref->{careCycle};
my $chargereq = 0; # Ladeanforedrung wenn SoC unter Minimum SoC gefallen ist
my $target = $lowSoc;
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
@ -6561,7 +6563,16 @@ sub _batSocTarget {
my $add = $rmn <= 2.5 ? 0 : 5;
$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
#################################
@ -6572,6 +6583,7 @@ sub _batSocTarget {
delete $paref->{histname};
storeReading ('Battery_OptimumTargetSoC', $target.' %');
storeReading ('Battery_ChargeRequest', $chargereq);
return;
}
@ -16604,6 +16616,55 @@ to ensure that the system configuration is correct.
</li>
<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>
<li><b>ctrlConsRecommendReadings </b><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>
<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
SoC-Management.
Dadurch wird das Reading <b>Battery_OptimumTargetSoC</b> erstellt. <br>
Dieses Reading kann zur Steuerung des SoC (State of Charge) im Batterie Device verwendet werden. <br>
Anzugeben sind: <br><br>
SoC-Management. <br>
Das Reading <b>Battery_OptimumTargetSoC</b> enthält den vom Modul berechneten optimalen Mindest-SoC. <br>
Das Reading <b>Battery_ChargeRequest</b> wird auf '1' gesetzt, wenn der aktuelle SoC unter den Mindest-SoC gefallen
ist. <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>
<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>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> </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>
</ul>
<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> 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>'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>
</table>
<br>