mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-04 22:19:38 +00:00
76_SolarForecast: Version 1.50.3
git-svn-id: https://svn.fhem.de/fhem/trunk@29849 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
22bba880cf
commit
2e9b26bede
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# 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
|
# Do not insert empty lines here, update check depends on it
|
||||||
|
- feature: 76_SolarForecast: Version 1.50.3
|
||||||
- bufgix: 72_FRITZBOX: set <name> smartHome <deviceID> <tempOffset:value>
|
- bufgix: 72_FRITZBOX: set <name> smartHome <deviceID> <tempOffset:value>
|
||||||
set <name> ring <intNumbers> [duration]
|
set <name> ring <intNumbers> [duration]
|
||||||
STATE 'undefined situation'
|
STATE 'undefined situation'
|
||||||
|
@ -160,6 +160,12 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern
|
# Versions History intern
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
|
"1.50.3" => "12.04.2025 __calcPVestimates: Fix missing limitation for strings if more than one string is assigned to an inverter ".
|
||||||
|
"code change in _attrInverterStrings, _attrStringPeak, checkPlantConfig: improved string check ",
|
||||||
|
"1.50.2" => "11.04.2025 take inverter cap into account if no strings key is set, ctrlSpecialReadings: new option tomorrowConsumptionForecast ".
|
||||||
|
"plant check: print out module version in header, decouple graphicBeamHeightLevelX from each other ",
|
||||||
|
"1.50.1" => "07.04.2025 new pvCorrectionFactor_Auto option 'on_complex_api_ai' to use average of AI + API forecast if AI Hit ".
|
||||||
|
"some code changes ",
|
||||||
"1.50.0" => "05.04.2025 changes V 1.49.1 - 1.49.6 as new major release ",
|
"1.50.0" => "05.04.2025 changes V 1.49.1 - 1.49.6 as new major release ",
|
||||||
"1.49.6" => "05.04.2025 some code changes, _flowGraphic: position of home text element, new attr consumerControl->dummyIcon, _batChargeRecmd: change loading release ".
|
"1.49.6" => "05.04.2025 some code changes, _flowGraphic: position of home text element, new attr consumerControl->dummyIcon, _batChargeRecmd: change loading release ".
|
||||||
"attr consumerAdviceIcon replaced by consumerControl->adviceIcon ".
|
"attr consumerAdviceIcon replaced by consumerControl->adviceIcon ".
|
||||||
@ -426,8 +432,8 @@ use constant {
|
|||||||
AISPREADLOWLIM => 80, # untere Abweichungsgrenze (%) AI 'Spread' von API Prognose
|
AISPREADLOWLIM => 80, # untere Abweichungsgrenze (%) AI 'Spread' von API Prognose
|
||||||
AIACCUPLIM => 150, # obere Abweichungsgrenze (%) AI 'Accurate' von API Prognose
|
AIACCUPLIM => 150, # obere Abweichungsgrenze (%) AI 'Accurate' von API Prognose
|
||||||
AIACCLOWLIM => 50, # untere Abweichungsgrenze (%) AI 'Accurate' von API Prognose
|
AIACCLOWLIM => 50, # untere Abweichungsgrenze (%) AI 'Accurate' von API Prognose
|
||||||
AIACCTRNMIN => 3500, # Mindestanzahl KI Trainingssätze für Verwendung "KI Accurate"
|
AIACCTRNMIN => 3500, # Mindestanzahl KI Regeln für Verwendung "KI Accurate"
|
||||||
AISPREADTRNMIN => 5500, # Mindestanzahl KI Trainingssätze für Verwendung "KI Spreaded"
|
AISPREADTRNMIN => 5500, # Mindestanzahl KI Regeln für Verwendung "KI Spreaded"
|
||||||
|
|
||||||
SOLAPIREPDEF => 3600, # default Abrufintervall SolCast API (s)
|
SOLAPIREPDEF => 3600, # default Abrufintervall SolCast API (s)
|
||||||
FORAPIREPDEF => 900, # default Abrufintervall ForecastSolar API (s)
|
FORAPIREPDEF => 900, # default Abrufintervall ForecastSolar API (s)
|
||||||
@ -456,6 +462,7 @@ use constant {
|
|||||||
HISTHOURDEF => 2, # default Anzeige vorangegangene Stunden
|
HISTHOURDEF => 2, # default Anzeige vorangegangene Stunden
|
||||||
WTHCOLDDEF => 'C7C979', # Wetter Icon Tag default Farbe
|
WTHCOLDDEF => 'C7C979', # Wetter Icon Tag default Farbe
|
||||||
WTHCOLNDEF => 'C7C7C7', # Wetter Icon Nacht default Farbe
|
WTHCOLNDEF => 'C7C7C7', # Wetter Icon Nacht default Farbe
|
||||||
|
BHEIGHTLEVEL => 200, # default Multiplikator zur Festlegung der maximalen Balkenhöhe
|
||||||
B1COLDEF => 'FFAC63', # default Farbe Beam 1
|
B1COLDEF => 'FFAC63', # default Farbe Beam 1
|
||||||
B1FONTCOLDEF => '0D0D0D', # default Schriftfarbe Beam 1
|
B1FONTCOLDEF => '0D0D0D', # default Schriftfarbe Beam 1
|
||||||
B2COLDEF => 'C4C4A7', # default Farbe Beam 2
|
B2COLDEF => 'C4C4A7', # default Farbe Beam 2
|
||||||
@ -1312,6 +1319,7 @@ my %hcsr = (
|
|||||||
todayGridFeedIn => { fnr => 5, fn => \&CircularVal, par => 99, par1 => '', unit => '', def => 0 },
|
todayGridFeedIn => { fnr => 5, fn => \&CircularVal, par => 99, par1 => '', unit => '', def => 0 },
|
||||||
todayGridConsumption => { fnr => 5, fn => \&CircularVal, par => 99, par1 => '', unit => '', def => 0 },
|
todayGridConsumption => { fnr => 5, fn => \&CircularVal, par => 99, par1 => '', unit => '', def => 0 },
|
||||||
todayConsumptionForecast => { fnr => 5, fn => \&HistoryVal, par => '', par1 => 'confc', unit => ' Wh', def => '-' },
|
todayConsumptionForecast => { fnr => 5, fn => \&HistoryVal, par => '', par1 => 'confc', unit => ' Wh', def => '-' },
|
||||||
|
tomorrowConsumptionForecast => { fnr => 5, fn => \&NexthoursVal, par => 'confc', par1 => '', unit => ' Wh', def => '-' },
|
||||||
conForecastTillNextSunrise => { fnr => 5, fn => \&NexthoursVal, par => 'confc', par1 => '', unit => ' Wh', def => 0 },
|
conForecastTillNextSunrise => { fnr => 5, fn => \&NexthoursVal, par => 'confc', par1 => '', unit => ' Wh', def => 0 },
|
||||||
todayBatInSum => { fnr => 5, fn => \&CircularVal, par => 99, par1 => '', unit => ' Wh', def => 0 },
|
todayBatInSum => { fnr => 5, fn => \&CircularVal, par => 99, par1 => '', unit => ' Wh', def => 0 },
|
||||||
todayBatOutSum => { fnr => 5, fn => \&CircularVal, par => 99, par1 => '', unit => ' Wh', def => 0 },
|
todayBatOutSum => { fnr => 5, fn => \&CircularVal, par => 99, par1 => '', unit => ' Wh', def => 0 },
|
||||||
@ -1673,11 +1681,13 @@ sub Set {
|
|||||||
roofIdentPair
|
roofIdentPair
|
||||||
pvHistory
|
pvHistory
|
||||||
);
|
);
|
||||||
my $resets = join ",",@re;
|
|
||||||
|
my $resets = join ",", @re;
|
||||||
|
|
||||||
for my $h (@chours) {
|
for my $h (@chours) {
|
||||||
push @cfs, 'pvCorrectionFactor_'. sprintf("%02d",$h);
|
push @cfs, 'pvCorrectionFactor_'. sprintf("%02d",$h);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cf = join " ", @cfs;
|
$cf = join " ", @cfs;
|
||||||
|
|
||||||
for my $c (sort{$a<=>$b} keys %{$data{$name}{consumers}}) {
|
for my $c (sort{$a<=>$b} keys %{$data{$name}{consumers}}) {
|
||||||
@ -1709,7 +1719,7 @@ sub Set {
|
|||||||
"operationMode:active,inactive ".
|
"operationMode:active,inactive ".
|
||||||
"plantConfiguration:check,save,restore ".
|
"plantConfiguration:check,save,restore ".
|
||||||
"powerTrigger:textField-long ".
|
"powerTrigger:textField-long ".
|
||||||
"pvCorrectionFactor_Auto:noLearning,on_simple".($ipai ? ',on_simple_ai,' : ',')."on_complex".($ipai ? ',on_complex_ai,' : ',')."off ".
|
"pvCorrectionFactor_Auto:noLearning,on_simple".($ipai ? ',on_simple_ai,' : ',')."on_complex".($ipai ? ',on_complex_ai,on_complex_api_ai,' : ',')."off ".
|
||||||
"reset:$resets ".
|
"reset:$resets ".
|
||||||
"setupStringAzimuth ".
|
"setupStringAzimuth ".
|
||||||
"setupStringDeclination ".
|
"setupStringDeclination ".
|
||||||
@ -4225,17 +4235,8 @@ sub __getopenMeteoData {
|
|||||||
my $debug = $paref->{debug};
|
my $debug = $paref->{debug};
|
||||||
my $reqm = $paref->{reqm};
|
my $reqm = $paref->{reqm};
|
||||||
|
|
||||||
my $hash = $defs{$name};
|
|
||||||
my $donearq = StatusAPIVal ($hash, 'OpenMeteo', '?All', 'todayDoneAPIrequests', 0);
|
|
||||||
|
|
||||||
if ($donearq >= OMETMAXREQ) {
|
|
||||||
my $msg = "The limit of maximum OMETMAXREQ daily API requests is reached or already exceeded. Process is exited.";
|
|
||||||
Log3 ($name, 1, "$name - ERROR - $msg");
|
|
||||||
return $msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$force) { # regulärer API Abruf
|
if (!$force) { # regulärer API Abruf
|
||||||
my $lrt = StatusAPIVal ($hash, 'OpenMeteo', '?All', 'lastretrieval_timestamp', 0);
|
my $lrt = StatusAPIVal ($name, 'OpenMeteo', '?All', 'lastretrieval_timestamp', 0);
|
||||||
|
|
||||||
if ($lrt && $t < $lrt + OMETEOREPDEF) {
|
if ($lrt && $t < $lrt + OMETEOREPDEF) {
|
||||||
my $rt = $lrt + OMETEOREPDEF - $t;
|
my $rt = $lrt + OMETEOREPDEF - $t;
|
||||||
@ -4243,6 +4244,14 @@ sub __getopenMeteoData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $donearq = StatusAPIVal ($name, 'OpenMeteo', '?All', 'todayDoneAPIrequests', 0);
|
||||||
|
|
||||||
|
if ($donearq >= OMETMAXREQ) {
|
||||||
|
my $msg = "The limit of maximum ".OMETMAXREQ." daily API requests is reached or already exceeded. Process is exited.";
|
||||||
|
Log3 ($name, 1, "$name - ERROR - $msg");
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
|
||||||
debugLog ($paref, 'apiCall', "Open-Meteo API Call - the daily API requests -> limited to: ".OMETMAXREQ.", done: $donearq");
|
debugLog ($paref, 'apiCall', "Open-Meteo API Call - the daily API requests -> limited to: ".OMETMAXREQ.", done: $donearq");
|
||||||
|
|
||||||
my $submodel = InternalVal ($name, $reqm, 'unknown');
|
my $submodel = InternalVal ($name, $reqm, 'unknown');
|
||||||
@ -4276,7 +4285,7 @@ sub __getopenMeteoGHIreplace {
|
|||||||
my $donearq = StatusAPIVal ($hash, 'OpenMeteo', '?All', 'todayDoneAPIrequests', 0);
|
my $donearq = StatusAPIVal ($hash, 'OpenMeteo', '?All', 'todayDoneAPIrequests', 0);
|
||||||
|
|
||||||
if ($donearq >= OMETMAXREQ) {
|
if ($donearq >= OMETMAXREQ) {
|
||||||
my $msg = "The limit of maximum OMETMAXREQ daily API requests is reached or already exceeded. Process is exited.";
|
my $msg = "The limit of maximum ".OMETMAXREQ." daily API requests is reached or already exceeded. Process is exited.";
|
||||||
Log3 ($name, 1, "$name - ERROR - $msg");
|
Log3 ($name, 1, "$name - ERROR - $msg");
|
||||||
return $msg;
|
return $msg;
|
||||||
}
|
}
|
||||||
@ -4912,16 +4921,15 @@ sub ___setOpenMeteoAPIcallKeyData {
|
|||||||
my $cequ = $paref->{callequivalent};
|
my $cequ = $paref->{callequivalent};
|
||||||
my $t = $paref->{t} // time;
|
my $t = $paref->{t} // time;
|
||||||
|
|
||||||
my $hash = $defs{$name};
|
|
||||||
|
|
||||||
$data{$name}{statusapi}{OpenMeteo}{'?All'}{todayDoneAPIrequests} += $cequ;
|
$data{$name}{statusapi}{OpenMeteo}{'?All'}{todayDoneAPIrequests} += $cequ;
|
||||||
|
|
||||||
my $dar = StatusAPIVal ($hash, 'OpenMeteo', '?All', 'todayDoneAPIrequests', 0);
|
my $dar = StatusAPIVal ($name, 'OpenMeteo', '?All', 'todayDoneAPIrequests', 0);
|
||||||
my $dac = StatusAPIVal ($hash, 'OpenMeteo', '?All', 'todayDoneAPIcalls', 0);
|
my $dac = StatusAPIVal ($name, 'OpenMeteo', '?All', 'todayDoneAPIcalls', 0);
|
||||||
my $asc = CurrentVal ($hash, 'allstringscount', 1);
|
my $asc = CurrentVal ($name, 'allstringscount', 1);
|
||||||
|
|
||||||
my $drr = OMETMAXREQ - $dar;
|
my $drr = OMETMAXREQ - $dar; # verbleibende Requests
|
||||||
$drr = 0 if($drr < 0);
|
$drr = 0 if($drr < 0);
|
||||||
|
my $rac = $drr / ($cequ * $asc); # verbleibende Calls
|
||||||
|
|
||||||
$data{$name}{statusapi}{OpenMeteo}{'?All'}{todayRemainingAPIrequests} = $drr;
|
$data{$name}{statusapi}{OpenMeteo}{'?All'}{todayRemainingAPIrequests} = $drr;
|
||||||
$data{$name}{statusapi}{OpenMeteo}{'?All'}{currentAPIinterval} = OMETEOREPDEF;
|
$data{$name}{statusapi}{OpenMeteo}{'?All'}{currentAPIinterval} = OMETEOREPDEF;
|
||||||
@ -4929,17 +4937,17 @@ sub ___setOpenMeteoAPIcallKeyData {
|
|||||||
## Berechnung des optimalen Request Intervalls
|
## Berechnung des optimalen Request Intervalls
|
||||||
################################################
|
################################################
|
||||||
my $edate = strftime "%Y-%m-%d 23:58:00", localtime($t);
|
my $edate = strftime "%Y-%m-%d 23:58:00", localtime($t);
|
||||||
my $ets = timestringToTimestamp ($edate);
|
my $ets = 3600 + timestringToTimestamp ($edate); # V 1.50.3 1h Sicherheitspuffer -> Intervall vergößern
|
||||||
my $rmdif = $ets - int $t;
|
my $rmdif = $ets - int $t;
|
||||||
|
|
||||||
if ($drr) {
|
if ($rac) {
|
||||||
my $optrep = $rmdif / ($drr / ($cequ * $asc));
|
my $optrep = sprintf "%.0f", ($rmdif / $rac);
|
||||||
$optrep = OMETEOREPDEF if($optrep < OMETEOREPDEF);
|
$optrep = OMETEOREPDEF if($optrep < OMETEOREPDEF);
|
||||||
|
|
||||||
$data{$name}{statusapi}{OpenMeteo}{'?All'}{currentAPIinterval} = $optrep;
|
$data{$name}{statusapi}{OpenMeteo}{'?All'}{currentAPIinterval} = $optrep;
|
||||||
}
|
}
|
||||||
|
|
||||||
debugLog ($paref, "apiProcess|apiCall", "Open-Meteo API Call - remaining API Requests: $drr, Request equivalents p. call: $cequ, new call interval: ".StatusAPIVal ($hash, 'OpenMeteo', '?All', 'currentAPIinterval', OMETEOREPDEF));
|
debugLog ($paref, "apiProcess|apiCall", "Open-Meteo API Call - remaining Requests: $drr, Call equivalent: $cequ, new call interval: ".StatusAPIVal ($name, 'OpenMeteo', '?All', 'currentAPIinterval', OMETEOREPDEF));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -6640,8 +6648,11 @@ sub _attrInverterStrings { ## no critic "not used"
|
|||||||
next if ($k =~ /\?/xs || grep /^$k$/, @istrings);
|
next if ($k =~ /\?/xs || grep /^$k$/, @istrings);
|
||||||
delete $data{$name}{solcastapi}{$k};
|
delete $data{$name}{solcastapi}{$k};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data{$name}{current}{allStringsFullfilled} = 0; # Stringkonfiguration neu prüfen lassen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InternalTimer (gettimeofday() + 0.5, 'FHEM::SolarForecast::centralTask', [$name, 0], 0);
|
||||||
InternalTimer (gettimeofday() + 3, 'FHEM::SolarForecast::writeCacheToFile', [$name, 'plantconfig', $plantcfg.$name], 0); # Anlagenkonfiguration File schreiben
|
InternalTimer (gettimeofday() + 3, 'FHEM::SolarForecast::writeCacheToFile', [$name, 'plantconfig', $plantcfg.$name], 0); # Anlagenkonfiguration File schreiben
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -6687,8 +6698,11 @@ sub _attrStringPeak { ## no critic "not used"
|
|||||||
return qq{The stringname '$strg' is not defined as valid string in attribute 'setupInverterStrings'};
|
return qq{The stringname '$strg' is not defined as valid string in attribute 'setupInverterStrings'};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data{$name}{current}{allStringsFullfilled} = 0; # Stringkonfiguration neu prüfen lassen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InternalTimer (gettimeofday() + 0.5, 'FHEM::SolarForecast::centralTask', [$name, 0], 0);
|
||||||
InternalTimer (gettimeofday() + 3, 'FHEM::SolarForecast::writeCacheToFile', [$name, 'plantconfig', $plantcfg.$name], 0); # Anlagenkonfiguration File schreiben
|
InternalTimer (gettimeofday() + 3, 'FHEM::SolarForecast::writeCacheToFile', [$name, 'plantconfig', $plantcfg.$name], 0); # Anlagenkonfiguration File schreiben
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -9461,8 +9475,11 @@ sub _transferAPIRadiationValues {
|
|||||||
return if(!@strings);
|
return if(!@strings);
|
||||||
|
|
||||||
my $invcapsum = 0;
|
my $invcapsum = 0;
|
||||||
|
my ($acu, $aln) = isAutoCorrUsed ($name);
|
||||||
|
my $dbmsg = '';
|
||||||
|
|
||||||
for my $in (keys %{$data{$name}{inverters}}) {
|
for my $in (keys %{$data{$name}{inverters}}) {
|
||||||
$invcapsum += InverterVal ($hash, $in, 'invertercap', 0); # Limit Leistungssumme aller Inverters
|
$invcapsum += InverterVal ($name, $in, 'invertercap', 0); # Limit Leistungssumme aller Inverters
|
||||||
}
|
}
|
||||||
|
|
||||||
for my $num (0..47) {
|
for my $num (0..47) {
|
||||||
@ -9479,7 +9496,7 @@ sub _transferAPIRadiationValues {
|
|||||||
my $nhtstr = 'NextHour'.sprintf "%02d", $num;
|
my $nhtstr = 'NextHour'.sprintf "%02d", $num;
|
||||||
my ($wtday, $wthour) = $wantdt =~ /(\d{2})\s(\d{2}):/xs;
|
my ($wtday, $wthour) = $wantdt =~ /(\d{2})\s(\d{2}):/xs;
|
||||||
my $hod = sprintf "%02d", int $wthour + 1; # Stunde des Tages
|
my $hod = sprintf "%02d", int $wthour + 1; # Stunde des Tages
|
||||||
my $rad1h = RadiationAPIVal ($hash, '?All', $wantdt, 'Rad1h', undef);
|
my $rad1h = RadiationAPIVal ($name, '?All', $wantdt, 'Rad1h', undef);
|
||||||
|
|
||||||
$paref->{wantdt} = $wantdt;
|
$paref->{wantdt} = $wantdt;
|
||||||
$paref->{wantts} = $wantts;
|
$paref->{wantts} = $wantts;
|
||||||
@ -9498,13 +9515,13 @@ sub _transferAPIRadiationValues {
|
|||||||
my ($sunalt, $sunaz);
|
my ($sunalt, $sunaz);
|
||||||
|
|
||||||
if ($fd == 0) { # V 1.49.4 für den aktuellen Tag
|
if ($fd == 0) { # V 1.49.4 für den aktuellen Tag
|
||||||
$sunalt = HistoryVal ($hash, $wtday, $hod, 'sunalt', undef);
|
$sunalt = HistoryVal ($name, $wtday, $hod, 'sunalt', undef);
|
||||||
$sunaz = HistoryVal ($hash, $wtday, $hod, 'sunaz', undef);
|
$sunaz = HistoryVal ($name, $wtday, $hod, 'sunaz', undef);
|
||||||
|
|
||||||
if (!defined $sunalt || !defined $sunaz) {
|
if (!defined $sunalt || !defined $sunaz) {
|
||||||
__calcSunPosition ($paref);
|
__calcSunPosition ($paref);
|
||||||
$sunalt = HistoryVal ($hash, $wtday, $hod, 'sunalt', undef);
|
$sunalt = HistoryVal ($name, $wtday, $hod, 'sunalt', undef);
|
||||||
$sunaz = HistoryVal ($hash, $wtday, $hod, 'sunaz', undef);
|
$sunaz = HistoryVal ($name, $wtday, $hod, 'sunaz', undef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9514,16 +9531,14 @@ sub _transferAPIRadiationValues {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
__calcSunPosition ($paref);
|
__calcSunPosition ($paref);
|
||||||
$sunalt = NexthoursVal ($hash, $nhtstr, 'sunalt', 0);
|
$sunalt = NexthoursVal ($name, $nhtstr, 'sunalt', 0);
|
||||||
$sunaz = NexthoursVal ($hash, $nhtstr, 'sunaz', 0);
|
$sunaz = NexthoursVal ($name, $nhtstr, 'sunaz', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$paref->{sabin} = sunalt2bin ($sunalt);
|
$paref->{sabin} = sunalt2bin ($sunalt);
|
||||||
my $pvest = __calcPVestimates ($paref);
|
my $pvapifc = __calcPVestimates ($paref); # API Wert ermitteln
|
||||||
my ($msg, $pvaifc) = aiGetResult ($paref); # KI Entscheidungen abfragen
|
my ($msg, $pvaifc) = aiGetResult ($paref); # KI Entscheidungen abfragen
|
||||||
|
|
||||||
$data{$name}{nexthours}{$nhtstr}{pvapifc} = $pvest; # durch API gelieferte PV Forecast
|
|
||||||
|
|
||||||
delete $paref->{fd};
|
delete $paref->{fd};
|
||||||
delete $paref->{fh1};
|
delete $paref->{fh1};
|
||||||
delete $paref->{num};
|
delete $paref->{num};
|
||||||
@ -9544,26 +9559,42 @@ sub _transferAPIRadiationValues {
|
|||||||
debugLog ($paref, "radiationProcess", "PV AI forecast start time $wantdt limited to $invcapsum Wh due to inverter capacity summary");
|
debugLog ($paref, "radiationProcess", "PV AI forecast start time $wantdt limited to $invcapsum Wh due to inverter capacity summary");
|
||||||
}
|
}
|
||||||
|
|
||||||
my $airn = CircularVal ($hash, 99, 'aiRulesNumber', 0) / CurrentVal ($name, 'aiTreesPV', AINUMTREES);
|
my $airn = CircularVal ($name, 99, 'aiRulesNumber', 0) / CurrentVal ($name, 'aiTreesPV', AINUMTREES);
|
||||||
my $aivar = 100;
|
my $aivar = 0;
|
||||||
$aivar = sprintf "%.0f", (100 * $pvaifc / $pvest) if($pvest); # Übereinstimmungsgrad KI Forecast zu API Forecast in %
|
$aivar = sprintf "%.0f", (100 * $pvaifc / $pvapifc) if($pvapifc); # Übereinstimmungsgrad KI Forecast zu API Forecast in %
|
||||||
|
|
||||||
if ($msg eq 'accurate') { # KI liefert 'accurate' Treffer -> verwenden
|
if ($msg eq 'accurate') { # KI liefert 'accurate' Treffer -> verwenden
|
||||||
if ($airn >= AIACCTRNMIN || ($aivar >= AIACCLOWLIM && $aivar <= AIACCUPLIM)) {
|
if ($airn >= AIACCTRNMIN || ($aivar >= AIACCLOWLIM && $aivar <= AIACCUPLIM)) {
|
||||||
$data{$name}{nexthours}{$nhtstr}{aihit} = 1;
|
$data{$name}{nexthours}{$nhtstr}{aihit} = 1;
|
||||||
$pvfc = $pvaifc;
|
|
||||||
$useai = 1;
|
$useai = 1;
|
||||||
|
|
||||||
debugLog ($paref, 'aiData', qq{AI Hit - accurate result used -> aiRulesNum: $airn, variance: $aivar, hod: $hod, Rad1h: $rad1h, pvfc: $pvfc Wh});
|
if ($acu =~ /api_ai/xs) {
|
||||||
|
$pvfc = $pvapifc ? (sprintf "%.0f", ($pvaifc + $pvapifc) / 2) : $pvaifc; # Durchschnitt AI und API verwenden
|
||||||
|
$dbmsg = 'average of accurate AI & API result used';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$pvfc = $pvaifc;
|
||||||
|
$dbmsg = 'accurate result used';
|
||||||
|
}
|
||||||
|
|
||||||
|
debugLog ($paref, 'aiData', qq{AI Hit - $dbmsg -> aiRulesNum: $airn, variance: $aivar, hod: $hod, Rad1h: $rad1h, pvfc: $pvfc Wh});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif ($msg eq 'spreaded') { # Abweichung AI von Standardvorhersage begrenzen
|
elsif ($msg eq 'spreaded') { # Abweichung AI von Standardvorhersage begrenzen
|
||||||
if ($airn >= AISPREADTRNMIN || ($aivar >= AISPREADLOWLIM && $aivar <= AISPREADUPLIM)) {
|
if ($airn >= AISPREADTRNMIN || ($aivar >= AISPREADLOWLIM && $aivar <= AISPREADUPLIM)) {
|
||||||
$data{$name}{nexthours}{$nhtstr}{aihit} = 1;
|
$data{$name}{nexthours}{$nhtstr}{aihit} = 1;
|
||||||
$pvfc = $pvaifc;
|
|
||||||
$useai = 1;
|
$useai = 1;
|
||||||
|
|
||||||
debugLog ($paref, 'aiData', qq{AI Hit - spreaded result used -> aiRulesNum: $airn, hod: $hod, Rad1h: $rad1h, pvfc: $pvfc Wh});
|
if ($acu =~ /api_ai/xs) {
|
||||||
|
$pvfc = $pvapifc ? (sprintf "%.0f", ($pvaifc + $pvapifc) / 2) : $pvaifc; # Durchschnitt AI und API verwenden
|
||||||
|
$dbmsg = 'average of spreaded AI & API result used';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$pvfc = $pvaifc;
|
||||||
|
$dbmsg = 'spreaded result used';
|
||||||
|
}
|
||||||
|
|
||||||
|
debugLog ($paref, 'aiData', qq{AI Hit - $dbmsg -> aiRulesNum: $airn, hod: $hod, Rad1h: $rad1h, pvfc: $pvfc Wh});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9577,18 +9608,19 @@ sub _transferAPIRadiationValues {
|
|||||||
else {
|
else {
|
||||||
delete $data{$name}{nexthours}{$nhtstr}{pvaifc};
|
delete $data{$name}{nexthours}{$nhtstr}{pvaifc};
|
||||||
$data{$name}{nexthours}{$nhtstr}{aihit} = 0;
|
$data{$name}{nexthours}{$nhtstr}{aihit} = 0;
|
||||||
$pvfc = $pvest;
|
$pvfc = $pvapifc;
|
||||||
|
|
||||||
debugLog ($paref, 'aiData', "use PV from API (no AI or AI result tolerance overflow) -> hod: $hod, Rad1h: ".(defined $rad1h ? $rad1h : '-').", pvfc: $pvfc Wh");
|
debugLog ($paref, 'aiData', "use PV from API (no AI or AI result tolerance overflow) -> hod: $hod, Rad1h: ".(defined $rad1h ? $rad1h : '-').", pvfc: $pvfc Wh");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data{$name}{nexthours}{$nhtstr}{pvapifc} = $pvapifc; # durch API gelieferte PV Forecast
|
||||||
$data{$name}{nexthours}{$nhtstr}{pvfc} = $pvfc; # resultierende PV Forecast zuweisen
|
$data{$name}{nexthours}{$nhtstr}{pvfc} = $pvfc; # resultierende PV Forecast zuweisen
|
||||||
|
|
||||||
if ($num < 23 && $fh < 24) { # Ringspeicher PV forecast Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
|
if ($num < 23 && $fh < 24) { # Ringspeicher PV forecast Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
|
||||||
$data{$name}{circular}{sprintf "%02d",$fh1}{pvapifc} = NexthoursVal ($hash, $nhtstr, 'pvapifc', undef);
|
$data{$name}{circular}{sprintf "%02d",$fh1}{pvapifc} = NexthoursVal ($name, $nhtstr, 'pvapifc', undef);
|
||||||
$data{$name}{circular}{sprintf "%02d",$fh1}{pvfc} = $pvfc;
|
$data{$name}{circular}{sprintf "%02d",$fh1}{pvfc} = $pvfc;
|
||||||
$data{$name}{circular}{sprintf "%02d",$fh1}{pvaifc} = NexthoursVal ($hash, $nhtstr, 'pvaifc', undef);
|
$data{$name}{circular}{sprintf "%02d",$fh1}{pvaifc} = NexthoursVal ($name, $nhtstr, 'pvaifc', undef);
|
||||||
$data{$name}{circular}{sprintf "%02d",$fh1}{aihit} = NexthoursVal ($hash, $nhtstr, 'aihit', 0);
|
$data{$name}{circular}{sprintf "%02d",$fh1}{aihit} = NexthoursVal ($name, $nhtstr, 'aihit', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($fd == 0 && int $pvfc > 0) { # Vorhersagedaten des aktuellen Tages zum manuellen Vergleich in Reading speichern
|
if ($fd == 0 && int $pvfc > 0) { # Vorhersagedaten des aktuellen Tages zum manuellen Vergleich in Reading speichern
|
||||||
@ -9668,11 +9700,10 @@ sub __calcPVestimates {
|
|||||||
my $num = $paref->{num};
|
my $num = $paref->{num};
|
||||||
my $debug = $paref->{debug};
|
my $debug = $paref->{debug};
|
||||||
|
|
||||||
my $hash = $defs{$name};
|
|
||||||
my $reld = $fd == 0 ? "today" : $fd == 1 ? "tomorrow" : "unknown";
|
my $reld = $fd == 0 ? "today" : $fd == 1 ? "tomorrow" : "unknown";
|
||||||
my $rr1c = NexthoursVal ($hash, "NextHour".sprintf ("%02d",$num), "rr1c", 0); # Gesamtniederschlag während der letzten Stunde kg/m2
|
my $rr1c = NexthoursVal ($name, "NextHour".sprintf ("%02d",$num), "rr1c", 0); # Gesamtniederschlag während der letzten Stunde kg/m2
|
||||||
my $wcc = NexthoursVal ($hash, "NextHour".sprintf ("%02d",$num), "wcc", 0); # effektive Wolkendecke nächste Stunde X
|
my $wcc = NexthoursVal ($name, "NextHour".sprintf ("%02d",$num), "wcc", 0); # effektive Wolkendecke nächste Stunde X
|
||||||
my $temp = NexthoursVal ($hash, "NextHour".sprintf ("%02d",$num), "temp", TEMPBASEDEF); # vorhergesagte Temperatur Stunde X
|
my $temp = NexthoursVal ($name, "NextHour".sprintf ("%02d",$num), "temp", TEMPBASEDEF); # vorhergesagte Temperatur Stunde X
|
||||||
my ($acu, $aln) = isAutoCorrUsed ($name);
|
my ($acu, $aln) = isAutoCorrUsed ($name);
|
||||||
|
|
||||||
$paref->{wcc} = $wcc;
|
$paref->{wcc} = $wcc;
|
||||||
@ -9682,10 +9713,10 @@ sub __calcPVestimates {
|
|||||||
my ($lh,$sq,$peakloss, $modtemp);
|
my ($lh,$sq,$peakloss, $modtemp);
|
||||||
my $pvsum = 0;
|
my $pvsum = 0;
|
||||||
my $peaksum = 0;
|
my $peaksum = 0;
|
||||||
my $invcapsum = 0;
|
my %sum;
|
||||||
|
|
||||||
for my $string (sort keys %{$data{$name}{strings}}) {
|
for my $string (sort keys %{$data{$name}{strings}}) {
|
||||||
my $peak = StringVal ($hash, $string, 'peak', 0); # String Peak (kWp)
|
my $peak = StringVal ($name, $string, 'peak', 0); # String Peak (kWp)
|
||||||
|
|
||||||
if ($acu =~ /on_complex/xs) {
|
if ($acu =~ /on_complex/xs) {
|
||||||
$paref->{peak} = $peak;
|
$paref->{peak} = $peak;
|
||||||
@ -9701,14 +9732,16 @@ sub __calcPVestimates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$peak *= 1000;
|
$peak *= 1000;
|
||||||
my $pvest = RadiationAPIVal ($hash, $string, $wantdt, 'pv_estimate50', 0);
|
my $pvest = RadiationAPIVal ($name, $string, $wantdt, 'pv_estimate50', 0);
|
||||||
my $pv = sprintf "%.1f", ($pvest * $hc); # Korrekturfaktor anwenden
|
my $pv = sprintf "%.1f", ($pvest * $hc); # Korrekturfaktor anwenden
|
||||||
|
|
||||||
for my $in (keys %{$data{$name}{inverters}}) {
|
for my $in (keys %{$data{$name}{inverters}}) {
|
||||||
my $istrings = InverterVal ($hash, $in, 'istrings', ''); # dem Inverter zugeordnete Strings
|
my $istrings = InverterVal ($name, $in, 'istrings', 'all'); # dem Inverter zugeordnete Strings
|
||||||
next if(!grep /^$string$/, (split ',', $istrings));
|
|
||||||
|
|
||||||
$invcapsum += InverterVal ($hash, $in, 'invertercap', 0); # Max. Leistung des Inverters
|
if ($istrings eq 'all' || grep /^$string$/, (split ',', $istrings)) {
|
||||||
|
$sum{$in}{pvinvsum} += $pv;
|
||||||
|
$sum{$in}{string} = defined $sum{$in}{string} ? $sum{$in}{string}.','.$string : $string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($debug =~ /radiationProcess/xs) {
|
if ($debug =~ /radiationProcess/xs) {
|
||||||
@ -9733,19 +9766,24 @@ sub __calcPVestimates {
|
|||||||
Log3 ($name, 1, "$name DEBUG> PV API estimate for $reld Hour ".sprintf ("%02d", $hod)." string $string ->\n$sq");
|
Log3 ($name, 1, "$name DEBUG> PV API estimate for $reld Hour ".sprintf ("%02d", $hod)." string $string ->\n$sq");
|
||||||
}
|
}
|
||||||
|
|
||||||
$pvsum += $pv;
|
|
||||||
$peaksum += $peak;
|
$peaksum += $peak;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for my $ins (keys %sum) {
|
||||||
|
my $cap = InverterVal ($name, $ins, 'invertercap', 0); # Max. Leistung des Inverters
|
||||||
|
my $pvinvsum = $sum{$ins}{pvinvsum};
|
||||||
|
|
||||||
|
if ($pvinvsum > $cap) {
|
||||||
|
$pvinvsum = $cap; # betreffende Strings auf WR Kapazität begrenzen
|
||||||
|
|
||||||
|
debugLog ($paref, "radiationProcess", "String(s) ".$sum{$ins}{string}." in total limited to $cap Wh due to inverter $ins capacity");
|
||||||
|
}
|
||||||
|
|
||||||
|
$pvsum += $pvinvsum;
|
||||||
|
}
|
||||||
|
|
||||||
$data{$name}{current}{allstringspeak} = $peaksum; # temperaturbedingte Korrektur der installierten Peakleistung in W
|
$data{$name}{current}{allstringspeak} = $peaksum; # temperaturbedingte Korrektur der installierten Peakleistung in W
|
||||||
$pvsum = $peaksum if($peaksum && $pvsum > $peaksum); # Vorhersage nicht größer als die Summe aller PV-Strings Peak
|
$pvsum = $peaksum if($peaksum && $pvsum > $peaksum); # Vorhersage nicht größer als die Summe aller PV-Strings Peak
|
||||||
|
|
||||||
if ($invcapsum && $pvsum > $invcapsum) {
|
|
||||||
$pvsum = $invcapsum; # PV Vorhersage auf WR Kapazität begrenzen
|
|
||||||
|
|
||||||
debugLog ($paref, "radiationProcess", "PV forecast start time $wantdt limited to $invcapsum Wh due to inverter capacity summary");
|
|
||||||
}
|
|
||||||
|
|
||||||
$pvsum = sprintf "%.0f", $pvsum;
|
$pvsum = sprintf "%.0f", $pvsum;
|
||||||
|
|
||||||
if ($debug =~ /radiationProcess/xs) {
|
if ($debug =~ /radiationProcess/xs) {
|
||||||
@ -9759,6 +9797,7 @@ sub __calcPVestimates {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$sq = q{};
|
$sq = q{};
|
||||||
|
|
||||||
for my $idx (sort keys %{$lh}) {
|
for my $idx (sort keys %{$lh}) {
|
||||||
$sq .= $idx." => ".$lh->{$idx}."\n";
|
$sq .= $idx." => ".$lh->{$idx}."\n";
|
||||||
}
|
}
|
||||||
@ -10753,7 +10792,6 @@ sub _batChargeRecmd {
|
|||||||
|
|
||||||
my $socwh = sprintf "%.0f", ($batinstcap * $csoc / 100); # aktueller SoC in Wh
|
my $socwh = sprintf "%.0f", ($batinstcap * $csoc / 100); # aktueller SoC in Wh
|
||||||
my $whneed = $batinstcap - $socwh;
|
my $whneed = $batinstcap - $socwh;
|
||||||
my $sfmargin = $whneed * 0.25; # Sicherheitszuschlag: X% der benötigten Ladeenergie (Wh)
|
|
||||||
|
|
||||||
## Auswertung für jede kommende Stunde
|
## Auswertung für jede kommende Stunde
|
||||||
########################################
|
########################################
|
||||||
@ -10799,12 +10837,12 @@ sub _batChargeRecmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$spday = 0 if($spday < 0); # PV Überschuß Prognose bis Sonnenuntergang
|
$spday = 0 if($spday < 0); # PV Überschuß Prognose bis Sonnenuntergang
|
||||||
|
my $sfmargin = $whneed * 0.5; # Sicherheitszuschlag: X% der benötigten Ladeenergie (Wh)
|
||||||
|
|
||||||
## Ladefreigabe
|
## Ladefreigabe
|
||||||
#################
|
#################
|
||||||
if ( $whneed + $sfmargin >= $spday ) {$crel = 1} # Ladefreigabe wenn benötigte Ladeenergie >= Restüberschuß des Tages zzgl. Sicherheitsaufschlag
|
if ( $whneed + $sfmargin >= $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 ( !$num && ($pvCu - $curcon) >= $inplim ) {$crel = 1} # Ladefreigabe wenn akt. PV Leistung - Abschläge >= WR-Leistungsbegrenzung
|
||||||
# if ( !$num && ($pvCu - $curcon) >= $feedinlim ) {$crel = 1} # Ladefreigabe wenn akt. PV Leistung - Abschläge >= Einspeiselimit der Anlage
|
|
||||||
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 > $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 ( $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} # immer Ladefreigabe wenn kein BatSoc-Management
|
if ( !$cgbt ) {$crel = 1} # immer Ladefreigabe wenn kein BatSoc-Management
|
||||||
@ -13510,6 +13548,7 @@ sub _genSpecialReadings {
|
|||||||
next if(grep /^$item$/, @csr);
|
next if(grep /^$item$/, @csr);
|
||||||
readingsDelete ($hash, $prpo.'_'.$item);
|
readingsDelete ($hash, $prpo.'_'.$item);
|
||||||
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'todayConsumptionForecast');
|
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'todayConsumptionForecast');
|
||||||
|
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'tomorrowConsumptionForecast');
|
||||||
}
|
}
|
||||||
|
|
||||||
return if(!@csr);
|
return if(!@csr);
|
||||||
@ -13703,10 +13742,10 @@ sub _genSpecialReadings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($kpi eq 'todayConsumptionForecastNh') {
|
if ($kpi eq 'tomorrowConsumptionForecast') {
|
||||||
for my $idx (sort keys %{$data{$name}{nexthours}}) {
|
for my $idx (sort keys %{$data{$name}{nexthours}}) {
|
||||||
my $istoday = NexthoursVal ($hash, $idx, 'today', 0);
|
my $istoday = NexthoursVal ($hash, $idx, 'today', 0);
|
||||||
last if(!$istoday);
|
next if($istoday);
|
||||||
|
|
||||||
my $hod = NexthoursVal ($hash, $idx, 'hourofday', '01');
|
my $hod = NexthoursVal ($hash, $idx, 'hourofday', '01');
|
||||||
my $confc = &{$hcsr{$kpi}{fn}} ($hash, $idx, $hcsr{$kpi}{par}, $def);
|
my $confc = &{$hcsr{$kpi}{fn}} ($hash, $idx, $hcsr{$kpi}{par}, $def);
|
||||||
@ -13876,7 +13915,7 @@ sub entryGraphic {
|
|||||||
beam6cont => AttrVal ($name, 'graphicBeam6Content', ''),
|
beam6cont => AttrVal ($name, 'graphicBeam6Content', ''),
|
||||||
lotype => AttrVal ($name, 'graphicLayoutType', 'double'),
|
lotype => AttrVal ($name, 'graphicLayoutType', 'double'),
|
||||||
kw => AttrVal ($name, 'graphicEnergyUnit', 'Wh'),
|
kw => AttrVal ($name, 'graphicEnergyUnit', 'Wh'),
|
||||||
height => AttrNum ($name, 'graphicBeamHeightLevel1', 200),
|
height => AttrNum ($name, 'graphicBeamHeightLevel1', BHEIGHTLEVEL),
|
||||||
width => $width,
|
width => $width,
|
||||||
fsize => AttrNum ($name, 'graphicSpaceSize', 24),
|
fsize => AttrNum ($name, 'graphicSpaceSize', 24),
|
||||||
layersync => $layersync, # Zeitsynchronisation zwischen Ebene 1 und den folgenden Balkengrafikebenen
|
layersync => $layersync, # Zeitsynchronisation zwischen Ebene 1 und den folgenden Balkengrafikebenen
|
||||||
@ -14012,7 +14051,7 @@ sub entryGraphic {
|
|||||||
$paref->{colorb2} = AttrVal ($name, 'graphicBeam4Color', B4COLDEF);
|
$paref->{colorb2} = AttrVal ($name, 'graphicBeam4Color', B4COLDEF);
|
||||||
$paref->{fcolor1} = AttrVal ($name, 'graphicBeam3FontColor', B3FONTCOLDEF);
|
$paref->{fcolor1} = AttrVal ($name, 'graphicBeam3FontColor', B3FONTCOLDEF);
|
||||||
$paref->{fcolor2} = AttrVal ($name, 'graphicBeam4FontColor', B4FONTCOLDEF);
|
$paref->{fcolor2} = AttrVal ($name, 'graphicBeam4FontColor', B4FONTCOLDEF);
|
||||||
$paref->{height} = AttrVal ($name, 'graphicBeamHeightLevel2', $paref->{height});
|
$paref->{height} = AttrVal ($name, 'graphicBeamHeightLevel2', BHEIGHTLEVEL);
|
||||||
$paref->{weather} = 0;
|
$paref->{weather} = 0;
|
||||||
$paref->{hfcg} = \%hfcg2;
|
$paref->{hfcg} = \%hfcg2;
|
||||||
|
|
||||||
@ -14055,7 +14094,7 @@ sub entryGraphic {
|
|||||||
$paref->{colorb2} = AttrVal ($name, 'graphicBeam6Color', B6COLDEF);
|
$paref->{colorb2} = AttrVal ($name, 'graphicBeam6Color', B6COLDEF);
|
||||||
$paref->{fcolor1} = AttrVal ($name, 'graphicBeam5FontColor', B5FONTCOLDEF);
|
$paref->{fcolor1} = AttrVal ($name, 'graphicBeam5FontColor', B5FONTCOLDEF);
|
||||||
$paref->{fcolor2} = AttrVal ($name, 'graphicBeam6FontColor', B6FONTCOLDEF);
|
$paref->{fcolor2} = AttrVal ($name, 'graphicBeam6FontColor', B6FONTCOLDEF);
|
||||||
$paref->{height} = AttrVal ($name, 'graphicBeamHeightLevel3', $paref->{height});
|
$paref->{height} = AttrVal ($name, 'graphicBeamHeightLevel3', BHEIGHTLEVEL);
|
||||||
$paref->{weather} = 0;
|
$paref->{weather} = 0;
|
||||||
$paref->{hfcg} = \%hfcg3;
|
$paref->{hfcg} = \%hfcg3;
|
||||||
|
|
||||||
@ -14152,7 +14191,7 @@ sub _checkSetupNotComplete {
|
|||||||
my $pv0 = NexthoursVal ($hash, 'NextHour00', 'pvfc', undef); # der erste PV ForeCast Wert
|
my $pv0 = NexthoursVal ($hash, 'NextHour00', 'pvfc', undef); # der erste PV ForeCast Wert
|
||||||
|
|
||||||
my $link = qq{<a href="$::FW_ME$::FW_subdir?detail=$name">$name</a>};
|
my $link = qq{<a href="$::FW_ME$::FW_subdir?detail=$name">$name</a>};
|
||||||
my $height = AttrNum ($name, 'graphicBeamHeightLevel1', 200);
|
my $height = AttrNum ($name, 'graphicBeamHeightLevel1', BHEIGHTLEVEL);
|
||||||
my $lang = getLang ($hash);
|
my $lang = getLang ($hash);
|
||||||
|
|
||||||
my (undef, $disabled, $inactive) = controller ($name);
|
my (undef, $disabled, $inactive) = controller ($name);
|
||||||
@ -15845,7 +15884,7 @@ sub _beamGraphic {
|
|||||||
|
|
||||||
$paref->{barcount} = $ii; # Anzahl Balken zur Begrenzung der nächsten Ebene registrieren
|
$paref->{barcount} = $ii; # Anzahl Balken zur Begrenzung der nächsten Ebene registrieren
|
||||||
|
|
||||||
$height = 200 if(!$height); # Fallback, sollte eigentlich nicht vorkommen, außer der User setzt es auf 0
|
$height = BHEIGHTLEVEL if(!$height); # Fallback, sollte eigentlich nicht vorkommen, außer der User setzt es auf 0
|
||||||
$maxVal = 1 if(!int $maxVal); # maxVal kann gerade bei kleineren maxhours Ausgaben in der Nacht leicht auf 0 fallen
|
$maxVal = 1 if(!int $maxVal); # maxVal kann gerade bei kleineren maxhours Ausgaben in der Nacht leicht auf 0 fallen
|
||||||
$maxCon = 1 if(!$maxCon);
|
$maxCon = 1 if(!$maxCon);
|
||||||
|
|
||||||
@ -19672,6 +19711,7 @@ sub checkPlantConfig {
|
|||||||
my $lang = AttrVal ($name, 'ctrlLanguage', AttrVal ('global', 'language', DEFLANG));
|
my $lang = AttrVal ($name, 'ctrlLanguage', AttrVal ('global', 'language', DEFLANG));
|
||||||
my $pcf = ReadingsVal ($name, 'pvCorrectionFactor_Auto', 'off');
|
my $pcf = ReadingsVal ($name, 'pvCorrectionFactor_Auto', 'off');
|
||||||
my $raname = AttrVal ($name, 'setupRadiationAPI', '');
|
my $raname = AttrVal ($name, 'setupRadiationAPI', '');
|
||||||
|
my $version = $hash->{HELPER}{VERSION} // '-';
|
||||||
my ($acu, $aln) = isAutoCorrUsed ($name);
|
my ($acu, $aln) = isAutoCorrUsed ($name);
|
||||||
|
|
||||||
my $ok = FW_makeImage ('10px-kreis-gruen.png', '');
|
my $ok = FW_makeImage ('10px-kreis-gruen.png', '');
|
||||||
@ -19717,32 +19757,37 @@ sub checkPlantConfig {
|
|||||||
|
|
||||||
if ($data{$name}{strings}{$sn}{peak} >= 500) {
|
if ($data{$name}{strings}{$sn}{peak} >= 500) {
|
||||||
$result->{'String Configuration'}{result} .= qq{The peak value of string "$sn" is very high. };
|
$result->{'String Configuration'}{result} .= qq{The peak value of string "$sn" is very high. };
|
||||||
$result->{'String Configuration'}{result} .= qq{It seems to be given in Wp instead of kWp. <br>};
|
$result->{'String Configuration'}{result} .= qq{Check if you entered peak power in Wp instead of kWp. Ignore the Warning if the entered value is correct. <br>};
|
||||||
$result->{'String Configuration'}{state} = $warn;
|
$result->{'String Configuration'}{state} = $warn;
|
||||||
$result->{'String Configuration'}{warn} = 1;
|
$result->{'String Configuration'}{warn} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSolCastUsed ($hash) && !isVictronKiUsed ($hash)) {
|
if (!isSolCastUsed ($hash) && !isVictronKiUsed ($hash)) {
|
||||||
if ($sp !~ /azimut.*?peak.*?tilt/x) {
|
if ($sp !~ /azimut.*?peak.*?tilt/x) {
|
||||||
|
$result->{'String Configuration'}{result} .= qq{Any of the parameter 'azimut', 'peak' or 'tilt' is missing. <br>};
|
||||||
$result->{'String Configuration'}{state} = $nok;
|
$result->{'String Configuration'}{state} = $nok;
|
||||||
$result->{'String Configuration'}{fault} = 1; # Test Vollständigkeit: z.B. Süddach => dir: S, peak: 5.13, tilt: 45
|
$result->{'String Configuration'}{fault} = 1; # Test Vollständigkeit: z.B. Süddach => dir: S, peak: 5.13, tilt: 45
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif (isVictronKiUsed ($hash)) {
|
elsif (isVictronKiUsed ($hash)) {
|
||||||
if($sp !~ /KI-based\s=>\speak/xs) {
|
if($sp !~ /KI-based\s=>\speak/xs) {
|
||||||
|
$result->{'String Configuration'}{result} .= qq{The parameter 'peak' is missing. <br>};
|
||||||
$result->{'String Configuration'}{state} = $nok;
|
$result->{'String Configuration'}{state} = $nok;
|
||||||
$result->{'String Configuration'}{fault} = 1;
|
$result->{'String Configuration'}{fault} = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { # Strahlungsdevice SolCast-API
|
else { # Strahlungsdevice SolCast-API
|
||||||
if($sp !~ /peak.*?pk/x) {
|
if($sp !~ /peak.*?pk/x) {
|
||||||
|
$result->{'String Configuration'}{result} .= qq{Any of the parameter 'peak' or 'pk' is missing. <br>};
|
||||||
$result->{'String Configuration'}{state} = $nok;
|
$result->{'String Configuration'}{state} = $nok;
|
||||||
$result->{'String Configuration'}{fault} = 1; # Test Vollständigkeit
|
$result->{'String Configuration'}{fault} = 1; # Test Vollständigkeit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$result->{'String Configuration'}{result} = $hqtxt{fulfd}{$lang} if(!$result->{'String Configuration'}{fault} && !$result->{'String Configuration'}{warn});
|
if (!$result->{'String Configuration'}{fault} && !$result->{'String Configuration'}{warn}) {
|
||||||
|
$result->{'String Configuration'}{result} = $hqtxt{fulfd}{$lang};
|
||||||
|
}
|
||||||
|
|
||||||
## Check Attribute DWD Wetterdevice
|
## Check Attribute DWD Wetterdevice
|
||||||
#####################################
|
#####################################
|
||||||
@ -20239,7 +20284,7 @@ sub checkPlantConfig {
|
|||||||
## Ausgabe
|
## Ausgabe
|
||||||
############
|
############
|
||||||
my $out = qq{<html>};
|
my $out = qq{<html>};
|
||||||
$out .= qq{<b>}.$hqtxt{plntck}{$lang}.qq{ - Model: $hash->{MODEL} </b> <br><br>};
|
$out .= qq{<b>}.$hqtxt{plntck}{$lang}.qq{ - Modul Version: $version, Model: $hash->{MODEL} </b> <br><br>};
|
||||||
|
|
||||||
$out .= qq{<table class="roomoverview" style="text-align:left; border:1px solid; padding:5px; border-spacing:5px; margin-left:auto; margin-right:auto;">};
|
$out .= qq{<table class="roomoverview" style="text-align:left; border:1px solid; padding:5px; border-spacing:5px; margin-left:auto; margin-right:auto;">};
|
||||||
$out .= qq{<tr style="font-weight:bold;">};
|
$out .= qq{<tr style="font-weight:bold;">};
|
||||||
@ -21594,6 +21639,7 @@ sub isAutoCorrUsed {
|
|||||||
my $acu = $cauto =~ /on_simple_ai/xs ? 'on_simple_ai' :
|
my $acu = $cauto =~ /on_simple_ai/xs ? 'on_simple_ai' :
|
||||||
$cauto =~ /on_simple/xs ? 'on_simple' :
|
$cauto =~ /on_simple/xs ? 'on_simple' :
|
||||||
$cauto =~ /on_complex_ai/xs ? 'on_complex_ai' :
|
$cauto =~ /on_complex_ai/xs ? 'on_complex_ai' :
|
||||||
|
$cauto =~ /on_complex_api_ai/xs ? 'on_complex_api_ai' :
|
||||||
$cauto =~ /on_complex/xs ? 'on_complex' :
|
$cauto =~ /on_complex/xs ? 'on_complex' :
|
||||||
$cauto =~ /standby/xs ? 'standby' :
|
$cauto =~ /standby/xs ? 'standby' :
|
||||||
$cauto =~ /on/xs ? 'on_simple' :
|
$cauto =~ /on/xs ? 'on_simple' :
|
||||||
@ -23507,6 +23553,11 @@ to ensure that the system configuration is correct.
|
|||||||
After activation, optimal predictions cannot be expected immediately!
|
After activation, optimal predictions cannot be expected immediately!
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
<b>on_complex_api_ai:</b> <br>
|
||||||
|
The method works in the same way as 'on_complex_ai', but the PV forecast value used is calculated by averaging the supplied
|
||||||
|
API value and the AI value.
|
||||||
|
<br><br>
|
||||||
|
|
||||||
Below are some API-specific tips that are merely best practice recommendations.
|
Below are some API-specific tips that are merely best practice recommendations.
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
@ -24617,6 +24668,7 @@ to ensure that the system configuration is correct.
|
|||||||
<tr><td> <b>todayBatInSum</b> </td><td>Total energy charged in all batteries on the current day </td></tr>
|
<tr><td> <b>todayBatInSum</b> </td><td>Total energy charged in all batteries on the current day </td></tr>
|
||||||
<tr><td> <b>todayBatOut_XX</b> </td><td>the energy taken from the battery XX on the current day </td></tr>
|
<tr><td> <b>todayBatOut_XX</b> </td><td>the energy taken from the battery XX on the current day </td></tr>
|
||||||
<tr><td> <b>todayBatOutSum</b> </td><td>Total energy drawn from all batteries on the current day </td></tr>
|
<tr><td> <b>todayBatOutSum</b> </td><td>Total energy drawn from all batteries on the current day </td></tr>
|
||||||
|
<tr><td> <b>tomorrowConsumptionForecast</b></td><td>Consumption forecast per hour of the coming day (01-24) </td></tr>
|
||||||
</table>
|
</table>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
@ -24735,13 +24787,13 @@ to ensure that the system configuration is correct.
|
|||||||
<a id="SolarForecast-attr-graphicBeamXContent" data-pattern="graphicBeam.*Content"></a>
|
<a id="SolarForecast-attr-graphicBeamXContent" data-pattern="graphicBeam.*Content"></a>
|
||||||
<li><b>graphicBeamXContent </b><br>
|
<li><b>graphicBeamXContent </b><br>
|
||||||
Defines the content of the bars to be displayed in the bar charts.
|
Defines the content of the bars to be displayed in the bar charts.
|
||||||
The bar charts are available in two levels. <br>
|
The bar charts are available in several levels. <br>
|
||||||
Level 1 is preset by default.
|
Level 1 is preset by default.
|
||||||
The content is determined by the attributes graphicBeam1Content and graphicBeam2Content. <br>
|
The content is determined by the attributes graphicBeam1Content and graphicBeam2Content. <br>
|
||||||
Level 2 can be activated by setting the attributes graphicBeam3Content and graphicBeam4Content. <br>
|
Level 2 can be activated by setting the attributes graphicBeam3Content and graphicBeam4Content. <br>
|
||||||
The attributes graphicBeam1Content and graphicBeam3Content represent the primary beams, the attributes
|
Level 3 can be activated by setting the attributes graphicBeam5Content and graphicBeam6Content. <br>
|
||||||
graphicBeam2Content and graphicBeam4Content attributes represent the secondary beams of the
|
The attributes with odd numbers (1,3,5) represent the primary bars, the attributes with even numbers the secondary bars
|
||||||
respective level.
|
of the respective level.
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@ -24957,8 +25009,7 @@ to ensure that the system configuration is correct.
|
|||||||
<a id="SolarForecast-attr-graphicLayoutType"></a>
|
<a id="SolarForecast-attr-graphicLayoutType"></a>
|
||||||
<li><b>graphicLayoutType <single | double | diff> </b><br>
|
<li><b>graphicLayoutType <single | double | diff> </b><br>
|
||||||
Layout of the bar graph. <br>
|
Layout of the bar graph. <br>
|
||||||
The content of the bars to be displayed is determined by the <b>graphicBeam1Content</b> or
|
The content of the bars to be displayed is determined by the <b>graphicBeamXContent</b> attributes.
|
||||||
<b>graphicBeam2Content</b> attributes.
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@ -25984,6 +26035,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
|||||||
Nach der Aktivierung sind nicht sofort optimale Vorhersagen zu erwarten!
|
Nach der Aktivierung sind nicht sofort optimale Vorhersagen zu erwarten!
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
<b>on_complex_api_ai:</b> <br>
|
||||||
|
Die Methode arbeitet wie 'on_complex_ai', jedoch wird der verwendete PV-Prognosewert durch eine Durchschnittsberechnung
|
||||||
|
von gelieferten API-Wert und KI-Wert gebildet.
|
||||||
|
<br><br>
|
||||||
|
|
||||||
Nachfolgend einige API-spezifische Hinweise die lediglich Best Practice Empfehlungen darstellen.
|
Nachfolgend einige API-spezifische Hinweise die lediglich Best Practice Empfehlungen darstellen.
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
@ -27095,6 +27151,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
|||||||
<tr><td> <b>todayBatInSum</b> </td><td>Summe der am aktuellen Tag in alle Batterien geladene Energie </td></tr>
|
<tr><td> <b>todayBatInSum</b> </td><td>Summe der am aktuellen Tag in alle Batterien geladene Energie </td></tr>
|
||||||
<tr><td> <b>todayBatOut_XX</b> </td><td>die am aktuellen Tag aus der Batterie XX entnommene Energie </td></tr>
|
<tr><td> <b>todayBatOut_XX</b> </td><td>die am aktuellen Tag aus der Batterie XX entnommene Energie </td></tr>
|
||||||
<tr><td> <b>todayBatOutSum</b> </td><td>Summe der am aktuellen Tag aus allen Batterien entnommene Energie </td></tr>
|
<tr><td> <b>todayBatOutSum</b> </td><td>Summe der am aktuellen Tag aus allen Batterien entnommene Energie </td></tr>
|
||||||
|
<tr><td> <b>tomorrowConsumptionForecast</b></td><td>Verbrauchsprognose pro Stunde des kommenden Tages (01-24) </td></tr>
|
||||||
</table>
|
</table>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
@ -27213,12 +27270,13 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
|||||||
<a id="SolarForecast-attr-graphicBeamXContent" data-pattern="graphicBeam.*Content"></a>
|
<a id="SolarForecast-attr-graphicBeamXContent" data-pattern="graphicBeam.*Content"></a>
|
||||||
<li><b>graphicBeamXContent </b><br>
|
<li><b>graphicBeamXContent </b><br>
|
||||||
Legt den darzustellenden Inhalt der Balken in den Balkendiagrammen fest.
|
Legt den darzustellenden Inhalt der Balken in den Balkendiagrammen fest.
|
||||||
Die Balkendiagramme sind in zwei Ebenen verfügbar. <br>
|
Die Balkendiagramme sind in mehreren Ebenen verfügbar. <br>
|
||||||
Die Ebene 1 ist im Standard voreingestellt.
|
Die Ebene 1 ist im Standard voreingestellt.
|
||||||
Der Inhalt wird durch die Attribute graphicBeam1Content und graphicBeam2Content bestimmt. <br>
|
Der Inhalt wird durch die Attribute graphicBeam1Content und graphicBeam2Content bestimmt. <br>
|
||||||
Die Ebene 2 kann durch Setzen der Attribute graphicBeam3Content und graphicBeam4Content aktiviert werden. <br>
|
Die Ebene 2 kann durch Setzen der Attribute graphicBeam3Content und graphicBeam4Content aktiviert werden. <br>
|
||||||
Die Attribute graphicBeam1Content und graphicBeam3Content stellen die primären Balken, die Attribute
|
Die Ebene 3 kann durch Setzen der Attribute graphicBeam5Content und graphicBeam6Content aktiviert werden. <br>
|
||||||
graphicBeam2Content und graphicBeam4Content die sekundären Balken der jeweiligen Ebene dar.
|
Die Attribute mit ungeraden Ziffern (1,3,5) stellen die primären Balken, die Attribute mit geraden Ziffern die sekundären Balken
|
||||||
|
der jeweiligen Ebene dar.
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@ -27432,8 +27490,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
|||||||
<a id="SolarForecast-attr-graphicLayoutType"></a>
|
<a id="SolarForecast-attr-graphicLayoutType"></a>
|
||||||
<li><b>graphicLayoutType <single | double | diff> </b><br>
|
<li><b>graphicLayoutType <single | double | diff> </b><br>
|
||||||
Layout der Balkengrafik. <br>
|
Layout der Balkengrafik. <br>
|
||||||
Der darzustellende Inhalt der Balken wird durch die Attribute <b>graphicBeam1Content</b> bzw.
|
Der darzustellende Inhalt der Balken wird durch die Attribute <b>graphicBeamXContent</b> bestimmt.
|
||||||
<b>graphicBeam2Content</b> bestimmt.
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user