mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-28 11:01:59 +00:00
76_Solarforcast: contrib 1.6.0
git-svn-id: https://svn.fhem.de/fhem/trunk@28299 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
9b2eec7aa5
commit
3383d7bbb4
@ -122,6 +122,8 @@ BEGIN {
|
|||||||
readingFnAttributes
|
readingFnAttributes
|
||||||
setKeyValue
|
setKeyValue
|
||||||
sortTopicNum
|
sortTopicNum
|
||||||
|
sunrise_abs_dat
|
||||||
|
sunset_abs_dat
|
||||||
FW_cmd
|
FW_cmd
|
||||||
FW_directNotify
|
FW_directNotify
|
||||||
FW_ME
|
FW_ME
|
||||||
@ -153,9 +155,10 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern
|
# Versions History intern
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
"1.6.0" => "18.12.2023 store daily batmaxsoc in pvHistory, new attr ctrlBatSocManagement, reading Battery_OptimumTargetSoC ".
|
"1.6.0" => "20.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 ",
|
||||||
"1.5.1" => "07.12.2023 function _getftui can now process arguments (compatibility to new ftui widgets), plant check ".
|
"1.5.1" => "07.12.2023 function _getftui can now process arguments (compatibility to new ftui widgets), plant check ".
|
||||||
"reviews SolarForecast widget files ",
|
"reviews SolarForecast widget files ",
|
||||||
"1.5.0" => "05.12.2023 new getter ftuiFramefiles ",
|
"1.5.0" => "05.12.2023 new getter ftuiFramefiles ",
|
||||||
@ -4930,8 +4933,8 @@ sub centralTask {
|
|||||||
my $type = $hash->{TYPE};
|
my $type = $hash->{TYPE};
|
||||||
my $cst = [gettimeofday]; # Zyklus-Startzeit
|
my $cst = [gettimeofday]; # Zyklus-Startzeit
|
||||||
|
|
||||||
RemoveInternalTimer($hash, "FHEM::SolarForecast::centralTask");
|
RemoveInternalTimer ($hash, 'FHEM::SolarForecast::centralTask');
|
||||||
RemoveInternalTimer($hash, "FHEM::SolarForecast::singleUpdateState");
|
RemoveInternalTimer ($hash, 'FHEM::SolarForecast::singleUpdateState');
|
||||||
|
|
||||||
### nicht mehr benötigte Readings/Daten löschen - Bereich kann später wieder raus !!
|
### nicht mehr benötigte Readings/Daten löschen - Bereich kann später wieder raus !!
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
@ -5500,28 +5503,36 @@ sub _transferWeatherValues {
|
|||||||
|
|
||||||
my ($time_str);
|
my ($time_str);
|
||||||
|
|
||||||
my $fc0_SunRise = ReadingsVal ($fcname, "fc0_SunRise", "23:59"); # Sonnenaufgang heute
|
my $fc0_sr = ReadingsVal ($fcname, "fc0_SunRise", "23:59"); # Sonnenaufgang heute
|
||||||
my $fc0_SunSet = ReadingsVal ($fcname, "fc0_SunSet", "00:00"); # Sonnenuntergang heute
|
my $fc0_ss = ReadingsVal ($fcname, "fc0_SunSet", "00:00"); # Sonnenuntergang heute
|
||||||
my $fc1_SunRise = ReadingsVal ($fcname, "fc1_SunRise", "23:59"); # Sonnenaufgang morgen
|
my $fc1_sr = ReadingsVal ($fcname, "fc1_SunRise", "23:59"); # Sonnenaufgang morgen
|
||||||
my $fc1_SunSet = ReadingsVal ($fcname, "fc1_SunSet", "00:00"); # Sonnenuntergang 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}{sunriseTodayTs} = timestringToTimestamp ($date.' '.$fc0_sr.':00');
|
||||||
|
|
||||||
$data{$type}{$name}{current}{sunriseToday} = $date.' '.$fc0_SunRise.':00';
|
$data{$type}{$name}{current}{sunsetToday} = $date.' '.$fc0_ss.':00';
|
||||||
$data{$type}{$name}{current}{sunriseTodayTs} = timestringToTimestamp ($date.' '.$fc0_SunRise.':00');
|
$data{$type}{$name}{current}{sunsetTodayTs} = timestringToTimestamp ($date.' '.$fc0_ss.':00');
|
||||||
|
|
||||||
$data{$type}{$name}{current}{sunsetToday} = $date.' '.$fc0_SunSet.':00';
|
debugLog ($paref, "collectData", "sunrise/sunset today: $fc0_sr / $fc0_ss, sunrise/sunset tomorrow: $fc1_sr / $fc1_ss");
|
||||||
$data{$type}{$name}{current}{sunsetTodayTs} = timestringToTimestamp ($date.' '.$fc0_SunSet.':00');
|
|
||||||
|
|
||||||
debugLog ($paref, "collectData", "sunrise/sunset today: $fc0_SunRise / $fc0_SunSet, sunrise/sunset tomorrow: $fc1_SunRise / $fc1_SunSet");
|
storeReading ('Today_SunRise', $fc0_sr);
|
||||||
|
storeReading ('Today_SunSet', $fc0_ss);
|
||||||
|
storeReading ('Tomorrow_SunRise', $fc1_sr);
|
||||||
|
storeReading ('Tomorrow_SunSet', $fc1_ss);
|
||||||
|
|
||||||
storeReading ('Today_SunRise', $fc0_SunRise);
|
my $fc0_sr_round = sprintf "%02d", (split ":", $fc0_sr)[0];
|
||||||
storeReading ('Today_SunSet', $fc0_SunSet);
|
my $fc0_ss_round = sprintf "%02d", (split ":", $fc0_ss)[0];
|
||||||
storeReading ('Tomorrow_SunRise', $fc1_SunRise);
|
my $fc1_sr_round = sprintf "%02d", (split ":", $fc1_sr)[0];
|
||||||
storeReading ('Tomorrow_SunSet', $fc1_SunSet);
|
my $fc1_ss_round = sprintf "%02d", (split ":", $fc1_ss)[0];
|
||||||
|
|
||||||
my $fc0_SunRise_round = sprintf "%02d", (split ":", $fc0_SunRise)[0];
|
|
||||||
my $fc0_SunSet_round = sprintf "%02d", (split ":", $fc0_SunSet)[0];
|
|
||||||
my $fc1_SunRise_round = sprintf "%02d", (split ":", $fc1_SunRise)[0];
|
|
||||||
my $fc1_SunSet_round = sprintf "%02d", (split ":", $fc1_SunSet)[0];
|
|
||||||
|
|
||||||
for my $num (0..46) {
|
for my $num (0..46) {
|
||||||
my ($fd,$fh) = _calcDayHourMove ($chour, $num);
|
my ($fd,$fh) = _calcDayHourMove ($chour, $num);
|
||||||
@ -5537,11 +5548,11 @@ sub _transferWeatherValues {
|
|||||||
my $don = 1; # es ist default "Tag"
|
my $don = 1; # es ist default "Tag"
|
||||||
my $fhstr = sprintf "%02d", $fh; # hier kann Tag/Nacht-Grenze verstellt werden
|
my $fhstr = sprintf "%02d", $fh; # hier kann Tag/Nacht-Grenze verstellt werden
|
||||||
|
|
||||||
if($fd == 0 && ($fhstr lt $fc0_SunRise_round || $fhstr gt $fc0_SunSet_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang heute
|
if($fd == 0 && ($fhstr lt $fc0_sr_round || $fhstr gt $fc0_ss_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang heute
|
||||||
$wid += 100; # "1" der WeatherID voranstellen wenn Nacht
|
$wid += 100; # "1" der WeatherID voranstellen wenn Nacht
|
||||||
$don = 0;
|
$don = 0;
|
||||||
}
|
}
|
||||||
elsif ($fd == 1 && ($fhstr lt $fc1_SunRise_round || $fhstr gt $fc1_SunSet_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang morgen
|
elsif ($fd == 1 && ($fhstr lt $fc1_sr_round || $fhstr gt $fc1_ss_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang morgen
|
||||||
$wid += 100; # "1" der WeatherID voranstellen wenn Nacht
|
$wid += 100; # "1" der WeatherID voranstellen wenn Nacht
|
||||||
$don = 0;
|
$don = 0;
|
||||||
}
|
}
|
||||||
@ -5595,6 +5606,30 @@ sub _transferWeatherValues {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Sonnenauf- und untergang bei gesetzten global
|
||||||
|
# latitude/longitude Koordinaten berechnen
|
||||||
|
################################################################
|
||||||
|
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
|
||||||
|
|
||||||
|
my ($cset, $lat, $lon) = locCoordinates();
|
||||||
|
|
||||||
|
return ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss) if(!$t || !$cset); # keine global latitude/longitude gesetzt
|
||||||
|
|
||||||
|
$fc0_sr = substr (sunrise_abs_dat ($t, 'REAL'), 0, 5); # SunRise heute
|
||||||
|
$fc0_ss = substr (sunset_abs_dat ($t, 'REAL'), 0, 5); # SunSet heute
|
||||||
|
$fc1_sr = substr (sunrise_abs_dat ($t + 86400, 'REAL'), 0, 5); # SunRise morgen
|
||||||
|
$fc1_ss = substr (sunset_abs_dat ($t + 86400, 'REAL'), 0, 5); # SunSet morgen
|
||||||
|
|
||||||
|
return ($fc0_sr, $fc0_ss, $fc1_sr, $fc1_ss);
|
||||||
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Strahlungsvorhersage Werte aus solcastapi-Hash
|
# Strahlungsvorhersage Werte aus solcastapi-Hash
|
||||||
# übertragen und PV Vorhersage berechnen / in Nexthours
|
# übertragen und PV Vorhersage berechnen / in Nexthours
|
||||||
@ -6462,18 +6497,34 @@ sub _batSocTarget {
|
|||||||
|
|
||||||
## Aufladewahrscheinlichkeit beachten
|
## Aufladewahrscheinlichkeit beachten
|
||||||
#######################################
|
#######################################
|
||||||
my $pvfctm = ReadingsNum ($name, 'Tomorrow_PVforecast', 0); # PV Prognose morgen
|
my $pvfctm = ReadingsNum ($name, 'Tomorrow_PVforecast', 0); # PV Prognose morgen
|
||||||
my $pvfctd = ReadingsNum ($name, 'RestOfDayPVforecast', 0); # PV Prognose Rest heute
|
my $pvfctd = ReadingsNum ($name, 'RestOfDayPVforecast', 0); # PV Prognose Rest heute
|
||||||
|
my $csopt = ReadingsNum ($name, 'Battery_OptimumTargetSoC', $lowSoc); # aktuelles SoC Optimum
|
||||||
my $pvexpect = $pvfctm > $pvfctd ? $pvfctm : $pvfctd;
|
my $pvexpect = $pvfctm > $pvfctd ? $pvfctm : $pvfctd;
|
||||||
|
|
||||||
my $batinstcap = CurrentVal ($hash, 'batinstcap', 0); # installierte Batteriekapazität Wh
|
my $batinstcap = CurrentVal ($hash, 'batinstcap', 0); # installierte Batteriekapazität Wh
|
||||||
my $needcharge = $batinstcap - ($batinstcap / 100 * $batcharge); # vorläufige benötigte Ladeenergie (Wh) bis 100% SOC
|
my $needcharge = $batinstcap - ($batinstcap / 100 * $batcharge); # vorläufige benötigte Ladeenergie (Wh) bis 100% SOC
|
||||||
my $cancharge = $pvexpect > $needcharge ? $pvexpect : $needcharge; # resultierende benötigte Ladeenergie (Wh)
|
my $cancharge = $pvexpect > $needcharge ? $needcharge : $pvexpect; # resultierende benötigte Ladeenergie (Wh)
|
||||||
my $cantarget = 100 - ($cancharge / ($batinstcap / 100)); # berechneter möglicher Min SOC nach Berücksichtigung Ladewahrscheinlichkeit
|
my $cantarget = 100 - ($cancharge / ($batinstcap / 100)); # berechneter möglicher Min SOC nach Berücksichtigung Ladewahrscheinlichkeit
|
||||||
|
|
||||||
$target = $cantarget < $target ? $cantarget : $target; # Abgleich möglicher Min SOC gg. berechneten Min SOC
|
my $newtarget = $cantarget < $target ? $cantarget : $target; # Abgleich möglicher Min SOC gg. berechneten Min SOC
|
||||||
|
my $logadd = '';
|
||||||
|
my $sunset = CurrentVal ($hash, 'sunsetTodayTs', $t);
|
||||||
|
|
||||||
debugLog ($paref, 'batteryManagement', "SoC calc Step2 - note charging probability -> Target: $target %");
|
if ($newtarget > $csopt && $t > $sunset) { # Erhöhung des SoC erst ab Sonnenuntergang anwenden
|
||||||
|
$target = $newtarget;
|
||||||
|
$logadd = "(new target > $csopt % and Sunset has passed)";
|
||||||
|
}
|
||||||
|
elsif ($newtarget < $csopt) { # Targetminderung sofort umsetzen -> Freiplatz für Ladeprognose
|
||||||
|
$target = $newtarget;
|
||||||
|
$logadd = "(new target < $csopt)";
|
||||||
|
}
|
||||||
|
else { # bisheriges OPtimum bleibt vorerst
|
||||||
|
$target = $csopt;
|
||||||
|
$logadd = "(new target $newtarget % is only activated after sunset)";
|
||||||
|
}
|
||||||
|
|
||||||
|
debugLog ($paref, 'batteryManagement', "SoC calc Step2 - note charging probability -> Target: $target % ".$logadd);
|
||||||
|
|
||||||
## low/up-Grenzen beachten
|
## low/up-Grenzen beachten
|
||||||
############################
|
############################
|
||||||
@ -6485,17 +6536,22 @@ sub _batSocTarget {
|
|||||||
|
|
||||||
## Pflege-SoC (Soll SoC $maxSoCdef bei $batSocChgDay % Steigerung p. Tag)
|
## Pflege-SoC (Soll SoC $maxSoCdef bei $batSocChgDay % Steigerung p. Tag)
|
||||||
###########################################################################
|
###########################################################################
|
||||||
my $ntsmsc = CircularVal ($hash, 99, 'nextTsMaxSocChge', $t);
|
if ($t > $sunset) { # Pflege-SoC erst ab Sonnenuntergang berechnen/anwenden
|
||||||
my $days2care = ceil (($ntsmsc - $t) / 86400); # verbleibende Tage bis der Batterie Pflege-SoC (default 95%) erreicht sein soll
|
my $ntsmsc = CircularVal ($hash, 99, 'nextTsMaxSocChge', $t);
|
||||||
|
my $days2care = ceil (($ntsmsc - $t) / 86400); # verbleibende Tage bis der Batterie Pflege-SoC (default 95%) erreicht sein soll
|
||||||
$paref->{days2care} = $days2care;
|
|
||||||
__batSaveSocKeyFigures ($paref);
|
$paref->{days2care} = $days2care;
|
||||||
delete $paref->{days2care};
|
__batSaveSocKeyFigures ($paref);
|
||||||
|
delete $paref->{days2care};
|
||||||
my $careSoc = $maxsoc - ($days2care * $batSocChgDay); # Pflege-SoC um rechtzeitig den $maxsoc zu erreichen bei 5% Steigerung pro Tag
|
|
||||||
$target = $careSoc < $target ? $target : $careSoc; # resultierender Target-SoC unter Berücksichtigung $caresoc
|
my $careSoc = $maxsoc - ($days2care * $batSocChgDay); # Pflege-SoC um rechtzeitig den $maxsoc zu erreichen bei 5% Steigerung pro Tag
|
||||||
|
$target = $careSoc < $target ? $target : $careSoc; # resultierender Target-SoC unter Berücksichtigung $caresoc
|
||||||
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 {
|
||||||
|
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,...)
|
||||||
#############################################
|
#############################################
|
||||||
@ -6504,7 +6560,7 @@ 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 - rounding the SoC to steps of 5 -> Target: $target %");
|
debugLog ($paref, 'batteryManagement', "SoC calc Step5 - (final step) rounding the SoC to steps of 5 -> Target: $target %");
|
||||||
|
|
||||||
## pvHistory/Readings schreiben
|
## pvHistory/Readings schreiben
|
||||||
#################################
|
#################################
|
||||||
@ -11656,7 +11712,7 @@ sub __calcNewFactor {
|
|||||||
$factor = sprintf "%.2f", ($pvre / $pvfc);
|
$factor = sprintf "%.2f", ($pvre / $pvfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
$factor = 1.00 if(1 * $factor == 0);
|
$factor = 1.00 if(1 * $factor == 0); # 0.00-Werte ignorieren (Schleifengefahr)
|
||||||
|
|
||||||
return ($factor, $dnum);
|
return ($factor, $dnum);
|
||||||
}
|
}
|
||||||
@ -13124,10 +13180,11 @@ sub checkPlantConfig {
|
|||||||
|
|
||||||
## Allgemeine Settings
|
## Allgemeine Settings
|
||||||
########################
|
########################
|
||||||
my $eocr = AttrVal ($name, 'event-on-change-reading', '');
|
my $eocr = AttrVal ($name, 'event-on-change-reading', '');
|
||||||
my $aiprep = isPrepared4AI ($hash, 'full');
|
my $aiprep = isPrepared4AI ($hash, 'full');
|
||||||
my $aiusemsg = CurrentVal ($hash, 'aicanuse', '');
|
my $aiusemsg = CurrentVal ($hash, 'aicanuse', '');
|
||||||
my $einstds = "";
|
my ($cset, $lat, $lon) = locCoordinates();
|
||||||
|
my $einstds = "";
|
||||||
|
|
||||||
if (!$eocr || $eocr ne '.*') {
|
if (!$eocr || $eocr ne '.*') {
|
||||||
$einstds = 'to .*' if($eocr ne '.*');
|
$einstds = 'to .*' if($eocr ne '.*');
|
||||||
@ -13143,6 +13200,20 @@ sub checkPlantConfig {
|
|||||||
$result->{'Common Settings'}{note} .= qq{If the local attribute "ctrlLanguage" or the global attribute "language" is changed to "DE" most of the outputs are in German.<br>};
|
$result->{'Common Settings'}{note} .= qq{If the local attribute "ctrlLanguage" or the global attribute "language" is changed to "DE" most of the outputs are in German.<br>};
|
||||||
$result->{'Common Settings'}{info} = 1;
|
$result->{'Common Settings'}{info} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$lat) {
|
||||||
|
$result->{'Common Settings'}{state} = $warn;
|
||||||
|
$result->{'Common Settings'}{result} .= qq{Attribute latitude in global device is not set. <br>};
|
||||||
|
$result->{'Common Settings'}{note} .= qq{Set the coordinates of your installation in the latitude attribute of the global device.<br>};
|
||||||
|
$result->{'Common Settings'}{warn} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$lon) {
|
||||||
|
$result->{'Common Settings'}{state} = $warn;
|
||||||
|
$result->{'Common Settings'}{result} .= qq{Attribute longitude in global device is not set. <br>};
|
||||||
|
$result->{'Common Settings'}{note} .= qq{Set the coordinates of your installation in the longitude attribute of the global device.<br>};
|
||||||
|
$result->{'Common Settings'}{warn} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$aiprep) {
|
if (!$aiprep) {
|
||||||
$result->{'Common Settings'}{state} = $info;
|
$result->{'Common Settings'}{state} = $info;
|
||||||
@ -13176,8 +13247,6 @@ sub checkPlantConfig {
|
|||||||
## allg. Settings bei Nutzung Forecast.Solar API
|
## allg. Settings bei Nutzung Forecast.Solar API
|
||||||
#################################################
|
#################################################
|
||||||
if (isForecastSolarUsed ($hash)) {
|
if (isForecastSolarUsed ($hash)) {
|
||||||
my ($cset, $lat, $lon) = locCoordinates();
|
|
||||||
|
|
||||||
if (!$pcf || $pcf !~ /on/xs) {
|
if (!$pcf || $pcf !~ /on/xs) {
|
||||||
$result->{'Common Settings'}{state} = $info;
|
$result->{'Common Settings'}{state} = $info;
|
||||||
$result->{'Common Settings'}{result} .= qq{pvCorrectionFactor_Auto is set to "$pcf" <br>};
|
$result->{'Common Settings'}{result} .= qq{pvCorrectionFactor_Auto is set to "$pcf" <br>};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user