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:
parent
ac0ce53998
commit
6e2dd35571
@ -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);
|
||||
@ -2315,10 +2317,10 @@ sub _setreset { ## no critic "not used"
|
||||
}
|
||||
|
||||
if ($prop eq 'currentBatterySet') {
|
||||
readingsDelete ($hash, 'Current_PowerBatIn');
|
||||
readingsDelete ($hash, 'Current_PowerBatOut');
|
||||
readingsDelete ($hash, 'Current_BatCharge');
|
||||
readingsDelete ($hash, 'Battery_OptimumTargetSoC');
|
||||
readingsDelete ($hash, 'Current_PowerBatIn');
|
||||
readingsDelete ($hash, 'Current_PowerBatOut');
|
||||
readingsDelete ($hash, 'Current_BatCharge');
|
||||
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') {
|
||||
@ -5494,27 +5499,17 @@ sub _transferWeatherValues {
|
||||
my $fcname = ReadingsVal($name, 'currentWeatherDev', ""); # Weather Forecast Device
|
||||
return if(!$fcname || !$defs{$fcname});
|
||||
|
||||
my $err = checkdwdattr ($name,$fcname,\@dweattrmust);
|
||||
my $err = checkdwdattr ($name, $fcname, \@dweattrmust);
|
||||
$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);
|
||||
|
||||
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);
|
||||
@ -5535,7 +5530,7 @@ sub _transferWeatherValues {
|
||||
my $fc1_ss_round = sprintf "%02d", (split ":", $fc1_ss)[0];
|
||||
|
||||
for my $num (0..46) {
|
||||
my ($fd,$fh) = _calcDayHourMove ($chour, $num);
|
||||
my ($fd, $fh) = _calcDayHourMove ($chour, $num);
|
||||
last if($fd > 1);
|
||||
|
||||
my $fh1 = $fh+1;
|
||||
@ -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 {
|
||||
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
|
||||
sub __sunRS {
|
||||
my $paref = shift;
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
@ -6551,7 +6553,7 @@ sub _batSocTarget {
|
||||
debugLog ($paref, 'batteryManagement', "SoC calc Step4 - note remaining days >$days2care< until care SoC -> Target: $target %");
|
||||
}
|
||||
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,...)
|
||||
@ -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=<Value> upSoC=<Value> [maxSoC=<Value>] [careCycle=<Value>] </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 (<= 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' < 'upSoC' < '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 <name> 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=<Wert> upSoC=<Wert> [maxSoC=<Wert>] [careCycle=<Wert>] </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 (<= 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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user