76_SolarForecast: contrib V1.58.6
git-svn-id: https://svn.fhem.de/fhem/trunk@30341 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
@@ -160,8 +160,9 @@ BEGIN {
|
||||
|
||||
# Versions History intern
|
||||
my %vNotesIntern = (
|
||||
"1.58.6" => "25.09.2025 __batChargeMgmt code changed, new sub ___batChargeSaveResults, remove reading Battery_ChargeRecommended_XX ".
|
||||
"_calcReadingsTomorrowPVFc: bugfix generating readings of tomorrow ",
|
||||
"1.58.6" => "01.10.2025 __batChargeMgmt code changed, new sub ___batChargeSaveResults, remove reading Battery_ChargeRecommended_XX ".
|
||||
"_calcReadingsTomorrowPVFc: bugfix generating readings of tomorrow ".
|
||||
"__batChargeOptTargetPower: complete rework, Attr ctrlBatSocManagementXX new key 'loadStrategy' ",
|
||||
"1.58.5" => "24.09.2025 __batChargeOptTargetPower: fix if battery load control is deactivated ",
|
||||
"1.58.4" => "23.09.2025 __batChargeOptTargetPower: user a better surplus value, excess based on average removed & some other code optimization ",
|
||||
"1.58.3" => "17.09.2025 __batChargeOptTargetPower: minor code change, consider bpinmax & lcintime ",
|
||||
@@ -1566,10 +1567,15 @@ my %hfspvh = (
|
||||
$hfspvh{'batprogsoc'.$bn}{validkey} = undef;
|
||||
$hfspvh{'batprogsoc'.$bn}{fpar} = undef;
|
||||
|
||||
$hfspvh{'lcintimebat'.$bn}{fn} = \&_storeVal; # Ladesteurung der Batterie In Time, d.h. war sie aktiv? (1 - Ja, 0 - Nein)
|
||||
$hfspvh{'lcintimebat'.$bn}{fn} = \&_storeVal; # Ladesteuerung der Batterie In Time, d.h. war sie aktiv? (1 - Ja, 0 - Nein)
|
||||
$hfspvh{'lcintimebat'.$bn}{storname} = 'lcintimebat'.$bn;
|
||||
$hfspvh{'lcintimebat'.$bn}{validkey} = undef;
|
||||
$hfspvh{'lcintimebat'.$bn}{fpar} = undef;
|
||||
|
||||
$hfspvh{'strategybat'.$bn}{fn} = \&_storeVal; # Ladestrategie der Batterie
|
||||
$hfspvh{'strategybat'.$bn}{storname} = 'strategybat'.$bn;
|
||||
$hfspvh{'strategybat'.$bn}{validkey} = undef;
|
||||
$hfspvh{'strategybat'.$bn}{fpar} = undef;
|
||||
|
||||
$hfspvh{'batmaxsoc'.$bn}{fn} = \&_storeVal; # max. erreichter SOC des Tages
|
||||
$hfspvh{'batmaxsoc'.$bn}{storname} = 'batmaxsoc'.$bn;
|
||||
@@ -7519,6 +7525,7 @@ sub _attrBatSocManagement { ## no critic "not used"
|
||||
careCycle => { comp => '\d+', must => 0, act => 0 },
|
||||
loadAbort => { comp => '(?:100|[1-9]?[0-9]):\d+(?::(?:100|[1-9]?[0-9]))?', must => 0, act => 0 },
|
||||
safetyMargin => { comp => '(?:100|[1-9]?\d)(?::(?:100|[1-9]?\d))?', must => 0, act => 0 },
|
||||
loadStrategy => { comp => '(loadRelease|optPower)', must => 0, act => 0 },
|
||||
};
|
||||
|
||||
my ($a, $h) = parseParams ($aVal);
|
||||
@@ -11532,14 +11539,15 @@ sub __parseAttrBatSoc {
|
||||
($urMargin, $otpMargin) = split ':', $ph->{safetyMargin} if(defined $ph->{safetyMargin});
|
||||
|
||||
my $parsed = {
|
||||
lowSoc => $ph->{lowSoc},
|
||||
upSoc => $ph->{upSoC},
|
||||
maxSoc => $ph->{maxSoC} // MAXSOCDEF, # optional (default: MAXSOCDEF)
|
||||
careCycle => $ph->{careCycle} // CARECYCLEDEF, # Ladungszyklus (Maintenance) für maxSoC in Tagen
|
||||
lcslot => $ph->{lcSlot},
|
||||
loadAbort => $ph->{loadAbort},
|
||||
urMargin => $urMargin,
|
||||
otpMargin => $otpMargin,
|
||||
lowSoc => $ph->{lowSoc},
|
||||
upSoc => $ph->{upSoC},
|
||||
maxSoc => $ph->{maxSoC} // MAXSOCDEF, # optional (default: MAXSOCDEF)
|
||||
careCycle => $ph->{careCycle} // CARECYCLEDEF, # Ladungszyklus (Maintenance) für maxSoC in Tagen
|
||||
lcslot => $ph->{lcSlot},
|
||||
loadAbort => $ph->{loadAbort},
|
||||
loadStrategy => $ph->{loadStrategy},
|
||||
urMargin => $urMargin,
|
||||
otpMargin => $otpMargin,
|
||||
};
|
||||
|
||||
return $parsed;
|
||||
@@ -11603,7 +11611,8 @@ sub _batChargeMgmt {
|
||||
my $hsurp = {}; # Hashreferenz Überschuß
|
||||
my $hsoc = {}; # Hashreferenz
|
||||
my $values = {}; # Hashreferenz
|
||||
|
||||
my $progsoc;
|
||||
|
||||
## Inverter Limits ermitteln
|
||||
##############################
|
||||
for my $in (1..MAXINVERTER) {
|
||||
@@ -11647,22 +11656,25 @@ sub _batChargeMgmt {
|
||||
my $batoptsoc = ReadingsNum ($name, 'Battery_OptimumTargetSoC_'.$bn, 0); # aktueller optimierter SoC
|
||||
my $confcss = CurrentVal ($name, 'tdConFcTillSunset', 0); # Verbrauchsprognose bis Sonnenuntergang
|
||||
my $csoc = BatteryVal ($name, $bn, 'bcharge', 0); # aktuelle Ladung in %
|
||||
my $csocwh = BatteryVal ($name, $bn, 'bchargewh', 0); # aktuelle Ladung in Wh
|
||||
my $bpinmax = BatteryVal ($name, $bn, 'bpinmax', INFINITE); # max. mögliche Ladeleistung W
|
||||
my $bpoutmax = BatteryVal ($name, $bn, 'bpoutmax', INFINITE); # max. mögliche Entladeleistung W
|
||||
my $bpowerin = BatteryVal ($name, $bn, 'bpowerin', INFINITE); # aktuelle Ladeleistung W
|
||||
my $cgbt = AttrVal ($name, 'ctrlBatSocManagement'.$bn, undef);
|
||||
my $sf = __batCapShareFactor ($hash, $bn); # Anteilsfaktor der Batterie XX Kapazität an Gesamtkapazität
|
||||
my $strategy = 'loadRelease'; # 'loadRelease' oder 'optPower'
|
||||
my $lowSoc = 0;
|
||||
my $loadAbort = '';
|
||||
my ($lcslot, $urMargin, $otpMargin);
|
||||
|
||||
if ($cgbt) {
|
||||
my $parsed = __parseAttrBatSoc ($name, $cgbt);
|
||||
$lowSoc = $parsed->{lowSoc} // 0;
|
||||
$lcslot = $parsed->{lcslot};
|
||||
$loadAbort = $parsed->{loadAbort};
|
||||
$urMargin = $parsed->{urMargin};
|
||||
$otpMargin = $parsed->{otpMargin};
|
||||
my $parsed = __parseAttrBatSoc ($name, $cgbt);
|
||||
$lowSoc = $parsed->{lowSoc} // 0;
|
||||
$lcslot = $parsed->{lcslot};
|
||||
$loadAbort = $parsed->{loadAbort};
|
||||
$urMargin = $parsed->{urMargin};
|
||||
$otpMargin = $parsed->{otpMargin};
|
||||
$strategy = $parsed->{loadStrategy} // $strategy;
|
||||
}
|
||||
|
||||
my $margin = defined $urMargin ? $urMargin : SFTYMARGIN_50; # Sicherheitszuschlag (%)
|
||||
@@ -11717,6 +11729,8 @@ sub _batChargeMgmt {
|
||||
my $nhr = sprintf "%02d", $num;
|
||||
my $hod = NexthoursVal ($name, 'NextHour'.$nhr, 'hourofday', undef);
|
||||
my $nhstt = NexthoursVal ($name, 'NextHour'.$nhr, 'starttime', undef);
|
||||
my $stt = (split /[-:]/, $nhstt)[2];
|
||||
$stt =~ s/\s/\//;
|
||||
|
||||
next if(!defined ($hod) || !defined ($nhstt));
|
||||
|
||||
@@ -11725,8 +11739,8 @@ sub _batChargeMgmt {
|
||||
my $pvfc = NexthoursVal ($name, 'NextHour'.$nhr, 'pvfc', 0);
|
||||
|
||||
if ($fd == 2 && $fh == 0) {
|
||||
$tompvfc = CurrentVal ($name, 'dayAfterTomorrowPVfc', 0); # PV Prognose übernächster Tag
|
||||
$tomconfc = CurrentVal ($name, 'dayAfterTomorrowConfc', 0); # Verbrauchsprognose übernächster Tag
|
||||
$tompvfc = CurrentVal ($name, 'dayAfterTomorrowPVfc', 0); # PV Prognose übernächster Tag
|
||||
$tomconfc = CurrentVal ($name, 'dayAfterTomorrowConfc', 0); # Verbrauchsprognose übernächster Tag
|
||||
}
|
||||
|
||||
## Zeitfenster für aktives Lademanagement anwenden
|
||||
@@ -11779,48 +11793,49 @@ sub _batChargeMgmt {
|
||||
if ( !$cgbt ) {$crel = 1} # Ladefreigabe wenn kein BatSoc-Management
|
||||
if ( !$lcintime ) {$crel = 1} # Ladefreigabe wenn nicht innerhalb Zeitslot für Ladesteuerung
|
||||
if ( $labortCond ) {$crel = 0} # keine Ladefreigabe bei genereller Abbruchbedingung
|
||||
|
||||
|
||||
# Steuerhash für optimimierte Ladeleistung erstellen
|
||||
######################################################
|
||||
my $surplswh = max (0, $surpls);
|
||||
|
||||
if ($today) { # nur Heute
|
||||
$hsurp->{$hod}{hod} = $hod;
|
||||
$hsurp->{$hod}{nhr} = $nhr;
|
||||
$hsurp->{$hod}{surpls} = $lcintime ? $surplswh.'.'.$hod : 0; # Überschuß in Wh der Stunde mit Sortierhilfe
|
||||
$hsurp->{$hod}{$bn}{spday} = $spday; # (Rest)PV-Überschuß am laufenden Tag
|
||||
$hsurp->{$hod}{$bn}{initsocwh} = $socwh;
|
||||
$hsurp->{$hod}{$bn}{batinstcap} = $batinstcap;
|
||||
$hsurp->{$hod}{$bn}{bpinmax} = $bpinmax; # max. mögliche Ladeleistung
|
||||
$hsurp->{$hod}{$bn}{otpMargin} = $otpMargin; # Sicherheitszuschlag für Berechnungen
|
||||
$hsurp->{$hod}{$bn}{lcintime} = $lcintime; # Ladesteuerung "In Time" oder "nicht In Time"
|
||||
if ($strategy eq 'optPower' || $strategy eq 'loadRelease' && $today) { # bei loadRelease' nur den aktuellen Tag betrachten
|
||||
$hsurp->{$fd}{$hod}{nhr} = $nhr;
|
||||
$hsurp->{$fd}{$hod}{speff} = $surpls; # effektiver PV Überschuß bzw. effektiver Verbrauch wenn < 0
|
||||
$hsurp->{$fd}{$hod}{surplswh} = $surplswh.'.'.$hod; # absoluter Überschuß in Wh der Stunde mit Sortierhilfe
|
||||
$hsurp->{$fd}{$hod}{$bn}{spday} = $spday; # (Rest)PV-Überschuß am laufenden Tag
|
||||
$hsurp->{$fd}{$hod}{$bn}{initsocwh} = $socwh;
|
||||
$hsurp->{$fd}{$hod}{$bn}{batinstcap} = $batinstcap; # installierte Batteriekapazität (Wh)
|
||||
$hsurp->{$fd}{$hod}{$bn}{bpinmax} = $bpinmax; # max. mögliche Ladeleistung
|
||||
$hsurp->{$fd}{$hod}{$bn}{bpoutmax} = $bpoutmax; # max. mögliche Entladeleistung
|
||||
$hsurp->{$fd}{$hod}{$bn}{lowSocwh} = $lowSocwh; # eingestellter lowSoC in Wh
|
||||
$hsurp->{$fd}{$hod}{$bn}{csocwh} = $csocwh; # aktueller SoC in Wh
|
||||
$hsurp->{$fd}{$hod}{$bn}{otpMargin} = $otpMargin; # Sicherheitszuschlag für Berechnungen
|
||||
$hsurp->{$fd}{$hod}{$bn}{lcintime} = $lcintime; # Ladesteuerung "In Time" oder "nicht In Time"
|
||||
$hsurp->{$fd}{$hod}{$bn}{stt} = $stt; # Day/Time für Debuglog
|
||||
$hsurp->{$fd}{$hod}{$bn}{strategy} = $strategy; # Ladestrategie
|
||||
}
|
||||
|
||||
## SOC-Prognose
|
||||
#################
|
||||
my $fceff = $surpls; # effektiver PV Überschuß bzw. effektiver Verbrauch wenn < 0
|
||||
## SOC-Prognose LR
|
||||
####################
|
||||
my $speff = $surpls; # effektiver PV Überschuß bzw. effektiver Verbrauch wenn < 0
|
||||
|
||||
$fceff = $fceff > 0 ? ($fceff >= $bpinmax ? $bpinmax : $fceff) :
|
||||
$fceff < 0 ? ($fceff <= $bpoutmax * -1 ? $bpoutmax * -1 : $fceff) :
|
||||
$fceff;
|
||||
$speff = $speff > 0 ? ($speff >= $bpinmax ? $bpinmax : $speff) :
|
||||
$speff < 0 ? ($speff <= $bpoutmax * -1 ? $bpoutmax * -1 : $speff) :
|
||||
$speff;
|
||||
|
||||
$socwh += $crel ? ($fceff > 0 ? $fceff * STOREFFDEF : $fceff / STOREFFDEF) :
|
||||
($fceff > 0 ? 0 : $fceff / STOREFFDEF); # PV Überschuß (d.h. Aufladung) nur einbeziehen wenn Ladefreigabe
|
||||
$socwh += $crel ? ($speff > 0 ? $speff * STOREFFDEF : $speff / STOREFFDEF) :
|
||||
($speff > 0 ? 0 : $speff / STOREFFDEF); # PV Überschuß (d.h. Aufladung) nur einbeziehen wenn Ladefreigabe
|
||||
|
||||
$socwh = $socwh < $lowSocwh ? $lowSocwh :
|
||||
$socwh < $batoptsocwh ? $batoptsocwh : # SoC Prognose in Wh
|
||||
$socwh > $batinstcap ? $batinstcap :
|
||||
$socwh;
|
||||
|
||||
$socwh = sprintf "%.0f", $socwh;
|
||||
my $progsoc = sprintf "%.1f", (100 * $socwh / $batinstcap); # Prognose SoC in %
|
||||
|
||||
$socwh = sprintf "%.0f", $socwh;
|
||||
$progsoc = sprintf "%.1f", (100 * $socwh / $batinstcap); # Prognose SoC in %
|
||||
|
||||
## Debuglog LR
|
||||
################
|
||||
my $stt = (split /[-:]/, $nhstt)[2];
|
||||
$stt =~ s/\s/\//;
|
||||
|
||||
my $msg = "CurrSoc: $csoc %, SoCfc: $socwh Wh, whneed: $whneed, pvfc: $pvfc, rodpvfc: $rodpvfc, confcss: $confcss, SurpDay: $spday Wh, CurrPV: $pvCu W, CurrCons: $curcon W, Limit: $inplim W, inTime: ".($cgbt ? $lcintime : '-');
|
||||
|
||||
if ($num) {
|
||||
@@ -11831,67 +11846,98 @@ sub _batChargeMgmt {
|
||||
}
|
||||
}
|
||||
|
||||
debugLog ($paref, 'batteryManagement', "Bat $bn ChargeLR $stt -> $crel ($msg)");
|
||||
debugLog ($paref, 'batteryManagement', "Bat $bn ChargeLR $stt - lc: $crel, $msg");
|
||||
|
||||
## Fortschreibung
|
||||
###################
|
||||
$whneed = $batinstcap - $socwh;
|
||||
|
||||
## Speicherung und Readings erstellen
|
||||
#######################################
|
||||
## Speicherung und Readings erstellen LR
|
||||
##########################################
|
||||
$values = { hsoc => $hsoc,
|
||||
loop => 'LR',
|
||||
num => $num,
|
||||
crel => $crel,
|
||||
bn => $bn,
|
||||
labortCond => $labortCond,
|
||||
loadAbort => $loadAbort,
|
||||
nhr => $nhr,
|
||||
progsoc => $progsoc,
|
||||
lcintime => $lcintime,
|
||||
cgbt => $cgbt,
|
||||
socwh => $socwh,
|
||||
today => $today,
|
||||
hod => $hod,
|
||||
loopid => 'LR',
|
||||
strategy => $strategy,
|
||||
crel => $crel,
|
||||
labortCond => $labortCond,
|
||||
loadAbort => $loadAbort,
|
||||
cgbt => $cgbt,
|
||||
lcintime => $lcintime,
|
||||
};
|
||||
|
||||
___batChargeSaveResults ($paref, $values);
|
||||
|
||||
$values = {};
|
||||
}
|
||||
}
|
||||
|
||||
# leistungsoptimierte Beladungssteuerung
|
||||
##########################################
|
||||
$paref->{hsurp} = $hsurp;
|
||||
my ($hopt, $otp) = __batChargeOptTargetPower ($paref);
|
||||
delete $paref->{hsurp};
|
||||
|
||||
## Debuglog OTP
|
||||
#################
|
||||
if ($paref->{debug} =~ /batteryManagement/) {
|
||||
Log3 ($name, 1, "$name DEBUG> ChargeOTP - The limit for grid feed-in is $feedinlim W");
|
||||
Log3 ($name, 1, "$name DEBUG> ChargeOTP - NOTE: The hours listed below are the estimated number of hours remaining on the current day with at least the respective PV surplus.");
|
||||
|
||||
for my $k (sort { $a <=> $b } keys %{$hopt}) {
|
||||
my @batteries = grep { !/^(?:hod|surpls|nhr)$/xs } keys %{$hsurp->{24}};
|
||||
for my $bat (sort @batteries) {
|
||||
my $sphrs = defined $hopt->{$k}{$bat}{sphrs} ?
|
||||
'('.($hopt->{$k}{$bat}{sphrs} ? $hopt->{$k}{$bat}{sphrs} : 1).' hrs)' :
|
||||
'';
|
||||
|
||||
my $ssocwh = $hopt->{$k}{$bat}{runwh} // '-';
|
||||
my $otpMargin = $hopt->{$k}{$bat}{otpMargin};
|
||||
my $margin = defined $otpMargin ? $otpMargin : SFTYMARGIN_20;
|
||||
my $spls = int $hopt->{$k}{surpls};
|
||||
my $needmin = max (BatteryVal ($name, $bat, 'bpinreduced', 0), $hopt->{$k}{$bat}{pneedmin} // 0);
|
||||
# leistungsoptimierte (optPower) Beladungssteuerung
|
||||
#####################################################
|
||||
for my $lfd (0..max (0, keys %{$hsurp})) {
|
||||
$paref->{hsurp} = $hsurp->{$lfd};
|
||||
my ($hopt, $otp) = __batChargeOptTargetPower ($paref);
|
||||
delete $paref->{hsurp};
|
||||
|
||||
## Debuglog OTP
|
||||
#################
|
||||
if ($paref->{debug} =~ /batteryManagement/ && !$lfd) {
|
||||
Log3 ($name, 1, "$name DEBUG> ChargeOTP - The limit for grid feed-in is $feedinlim W");
|
||||
}
|
||||
|
||||
## Speicherung und Readings erstellen OTP
|
||||
###########################################
|
||||
for my $shod (sort { $a <=> $b } keys %{$hopt}) {
|
||||
my $nhr = $hopt->{$shod}{nhr};
|
||||
my @batteries = grep { !/^(?:fd|speff|surplswh|nhr)$/xs } keys %{$hopt->{24}};
|
||||
|
||||
for my $bat (sort @batteries) {
|
||||
my $ssocwh = $hopt->{$shod}{$bat}{runwh} // '-';
|
||||
my $fcendwh = $hopt->{$shod}{$bat}{fcendwh} // 0;
|
||||
$progsoc = sprintf "%.1f", (100 * $fcendwh / $hopt->{$shod}{$bat}{batinstcap}); # Prognose SoC in %
|
||||
|
||||
## Speicherung und Readings erstellen OTP
|
||||
##########################################
|
||||
$values = { hsoc => $hsoc,
|
||||
otp => $otp,
|
||||
bn => $bat,
|
||||
nhr => $nhr,
|
||||
progsoc => $progsoc,
|
||||
socwh => $fcendwh,
|
||||
hod => $shod,
|
||||
loopid => 'OTP',
|
||||
strategy => $hopt->{$shod}{$bat}{strategy},
|
||||
};
|
||||
|
||||
___batChargeSaveResults ($paref, $values);
|
||||
|
||||
if ($hopt->{$k}{nhr} eq '00') { # Target für aktuelle Stunde
|
||||
$needmin = $otp->{$bat}{target} // 0;
|
||||
## Debuglog OTP
|
||||
#################
|
||||
if ($paref->{debug} =~ /batteryManagement/) {
|
||||
my $lcintime = $hopt->{$shod}{$bat}{lcintime};
|
||||
my $spls = int $hopt->{$shod}{surplswh};
|
||||
my $pneedmin = $hopt->{$shod}{$bat}{pneedmin};
|
||||
my $ttt = $hopt->{$shod}{$bat}{stt};
|
||||
|
||||
if ($nhr eq '00') {
|
||||
$pneedmin = $otp->{$bat}{target} // 0;
|
||||
my $achievable = $hopt->{$shod}{$bat}{achievable};
|
||||
my $otpMargin = $hopt->{$shod}{$bat}{otpMargin};
|
||||
my $margin = defined $otpMargin ? $otpMargin : SFTYMARGIN_20;
|
||||
Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP - used safety margin: $margin %");
|
||||
Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP - is the charging goal likely to be achieved? - $achievable");
|
||||
}
|
||||
|
||||
Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP $ttt - hod: $shod / $nhr, lc: $lcintime, SoC S/E: $ssocwh / $fcendwh Wh, Surplus: $spls Wh, OTP: $pneedmin W");
|
||||
}
|
||||
|
||||
Log3 ($name, 1, "$name DEBUG> Bat $bat ChargeOTP - hod: $k, Start SoC: $ssocwh Wh, Surplus: $spls Wh $sphrs, OTP: $needmin W, safety: $margin %");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# prognostizierten SOC über alle Batterien speichern
|
||||
######################################################
|
||||
@@ -11941,102 +11987,142 @@ return;
|
||||
sub __batChargeOptTargetPower {
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
my $hsurp = $paref->{hsurp} // return; # Hashref Überschußhash
|
||||
my $hsurp = $paref->{hsurp}; # Hashref Überschußhash
|
||||
|
||||
my $fipl = CurrentVal ($name, 'feedinPowerLimit', INFINITE);
|
||||
my @sorted = sort { $hsurp->{$a}{surpls} <=> $hsurp->{$b}{surpls} } keys %{$hsurp};
|
||||
my $sphrs = scalar grep { int( $hsurp->{$_}{surpls} ) >= 1 } @sorted; # Stunden mit Überschuß >= 1
|
||||
my @batteries = grep { !/^(?:hod|surpls|nhr)$/xs } keys %{$hsurp->{24}};
|
||||
my $fipl = CurrentVal ($name, 'feedinPowerLimit', INFINITE);
|
||||
my @sortedhods = sort { $hsurp->{$a}{surplswh} <=> $hsurp->{$b}{surplswh} } keys %{$hsurp}; # Stunden aufsteigend nach PV-Überschuß sortiert
|
||||
my @batteries = grep { !/^(?:fd|speff|surplswh|nhr)$/xs } keys %{$hsurp->{24}};
|
||||
my $otp;
|
||||
|
||||
for my $shod (@sorted) {
|
||||
my $spls = int $hsurp->{$shod}{surpls};
|
||||
my $newshod = sprintf "%02d", (int $shod + 1);
|
||||
for my $hod (sort { $a <=> $b } keys %{$hsurp}) {
|
||||
my $spls = int $hsurp->{$hod}{surplswh};
|
||||
my $newshod = sprintf "%02d", (int $hod + 1);
|
||||
my $nhr = $hsurp->{$hod}{nhr};
|
||||
|
||||
for my $sbn (sort @batteries) { # jede Batterie
|
||||
my $bpinmax = $hsurp->{$shod}{$sbn}{bpinmax}; # Bat max. mögliche Ladelesitung
|
||||
|
||||
if (!$hsurp->{$shod}{$sbn}{lcintime}) { # Ladesteuerung nicht "In Time"
|
||||
$hsurp->{$shod}{$sbn}{pneedmin} = $bpinmax;
|
||||
my @remaining_hods = grep { int $_ >= int $hod } @sortedhods;
|
||||
|
||||
for my $sbn (sort { $a <=> $b } @batteries) { # jede Batterie
|
||||
my $bpinmax = $hsurp->{$hod}{$sbn}{bpinmax}; # Bat max. mögliche Ladelesitung
|
||||
my $sbatinstcap = $hsurp->{$hod}{$sbn}{batinstcap}; # Kapa dieser Batterie
|
||||
my $lowSocwh = $hsurp->{$hod}{$sbn}{lowSocwh}; # eingestellter lowSoc in Wh
|
||||
my $csocwh = $hsurp->{$hod}{$sbn}{csocwh}; # aktueller SoC in Wh
|
||||
my $bpinreduced = BatteryVal ($name, $sbn, 'bpinreduced', 0); # Standardwert wenn z.B. kein Überschuß oder Zwangsladung vom Grid
|
||||
|
||||
my $runwh = defined $hsurp->{$hod}{$sbn}{fcnextwh} ? # Auswahl des zu verwendenden Prognose-SOC (Wh)
|
||||
$hsurp->{$hod}{$sbn}{fcnextwh} :
|
||||
( $nhr eq '00' ?
|
||||
$csocwh :
|
||||
$hsurp->{$hod}{$sbn}{initsocwh}
|
||||
);
|
||||
|
||||
$runwh = min ($runwh, $sbatinstcap);
|
||||
$hsurp->{$hod}{$sbn}{runwh} = sprintf "%.0f", $runwh;
|
||||
|
||||
if (!$spls || !$hsurp->{$hod}{$sbn}{lcintime}) { # Ladesteuerung nicht "In Time"
|
||||
$hsurp->{$hod}{$sbn}{achievable} = 'undetermined';
|
||||
$hsurp->{$hod}{$sbn}{pneedmin} = $bpinmax;
|
||||
$hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", $runwh;
|
||||
|
||||
if ($hsurp->{$shod}{nhr} eq '00') {
|
||||
$otp->{$sbn}{target} = $bpinmax;
|
||||
storeReading ('Battery_ChargeOptTargetPower_'.$sbn, $bpinmax.' W');
|
||||
if ($nhr eq '00') {
|
||||
$otp->{$sbn}{target} = $csocwh <= $lowSocwh ? $bpinreduced : $bpinmax;
|
||||
}
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
my $bpinreduced = BatteryVal ($name, $sbn, 'bpinreduced', 0); # Standardwert wenn z.B. kein Überschuß oder Zwangsladung vom Grid
|
||||
my $crgwh = BatteryVal ($name, $sbn, 'bchargewh', 0); # aktueller Ladezustand Batterie
|
||||
my $runwh = defined $hsurp->{$shod}{$sbn}{fcnextwh} ? # Auswahl des zu verwendenden Prognose-SOC (Wh)
|
||||
$hsurp->{$shod}{$sbn}{fcnextwh} :
|
||||
( $hsurp->{$shod}{nhr} eq '00' ?
|
||||
$crgwh :
|
||||
$hsurp->{$shod}{$sbn}{initsocwh}
|
||||
);
|
||||
}
|
||||
|
||||
my $otpMargin = $hsurp->{$shod}{$sbn}{otpMargin};
|
||||
my $margin = defined $otpMargin ? $otpMargin : SFTYMARGIN_20;
|
||||
my $otpMargin = $hsurp->{$hod}{$sbn}{otpMargin};
|
||||
my $margin = defined $otpMargin ? $otpMargin : SFTYMARGIN_20;
|
||||
my $runwhneed = $sbatinstcap - $runwh;
|
||||
my $fref = ___batFindMinPhWh ($hsurp, \@remaining_hods, $runwhneed);
|
||||
my $needraw = min ($fref->{ph}, $spls); # Ladeleistung auf Surplus begrenzen
|
||||
|
||||
$needraw *= 1 + ($margin / 100); # 1. Sicherheitsaufschlag
|
||||
$needraw = sprintf "%.0f", $needraw;
|
||||
my $pneedmin = max ($needraw, $bpinreduced); # Mindestladeleistung bpinreduced sicherstellen
|
||||
|
||||
if (!$spls) { # auf kleine Sollladeleistung setzen wenn kein Überschuß
|
||||
$hsurp->{$shod}{$sbn}{pneedmin} = $bpinreduced;
|
||||
|
||||
if ($hsurp->{$shod}{nhr} eq '00') {
|
||||
$otp->{$sbn}{target} = $bpinreduced;
|
||||
storeReading ('Battery_ChargeOptTargetPower_'.$sbn, $bpinreduced.' W');
|
||||
}
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
my $sbatinstcap = $hsurp->{$shod}{$sbn}{batinstcap}; # Kapa dieser Batterie
|
||||
$runwh = min ($runwh, $sbatinstcap);
|
||||
my $runwhneed = $sbatinstcap - $runwh;
|
||||
my $needraw = $sphrs ? $runwhneed / $sphrs : $runwhneed; # Ladeleistung initial
|
||||
$needraw *= 1 + ($margin / 100); # Sicherheitsaufschlag
|
||||
|
||||
$needraw = max (0, $needraw);
|
||||
$hsurp->{$shod}{$sbn}{runwh} = sprintf "%.0f", $runwh;
|
||||
$hsurp->{$shod}{$sbn}{sphrs} = $sphrs; # Reststunden mit diesem Überschuß
|
||||
my $pneedmin = sprintf "%.0f", $spls > $needraw ? # Mindestladeleistung bzw. Energie bei 1h (Wh)
|
||||
$needraw ? $needraw : $bpinreduced :
|
||||
$spls;
|
||||
$hsurp->{$shod}{$sbn}{pneedmin} = min ($pneedmin, $hsurp->{$shod}{$sbn}{bpinmax}); # Begrenzung auf max. mögliche Batterieleistung
|
||||
|
||||
if (defined $hsurp->{$newshod}) {
|
||||
$hsurp->{$newshod}{$sbn}{fcnextwh} = min ($sbatinstcap, $runwh + $hsurp->{$shod}{$sbn}{pneedmin});
|
||||
}
|
||||
|
||||
if ($hsurp->{$shod}{nhr} eq '00') {
|
||||
my $target = max ($bpinreduced, $hsurp->{$shod}{$sbn}{pneedmin});
|
||||
|
||||
if (NexthoursVal ($name, 'NextHour00', 'DoN', 0)) {
|
||||
$target *= 1 + ($margin / 100); # 2. Sicherheitsaufschlag
|
||||
}
|
||||
$hsurp->{$hod}{$sbn}{achievable} = 'goal: '.(sprintf "%.0f", $runwhneed).' Wh -> '.($fref->{achievable} ? 'yes' : 'no');
|
||||
$hsurp->{$hod}{$sbn}{pneedmin} = min ($pneedmin, $hsurp->{$hod}{$sbn}{bpinmax}); # Begrenzung auf max. mögliche Batterieleistung
|
||||
|
||||
if ($nhr eq '00') {
|
||||
my $target = max ($bpinreduced, $hsurp->{$hod}{$sbn}{pneedmin});
|
||||
$target *= 1 + ($margin / 100); # 2. Sicherheitsaufschlag
|
||||
|
||||
my $gfeedin = CurrentVal ($name, 'gridfeedin', 0); # aktuelle Netzeinspeisung
|
||||
my $bpin = CurrentVal ($name, 'batpowerinsum', 0); # aktuelle Batterie Ladeleistung (Summe über alle Batterien)
|
||||
my $inc = 0;
|
||||
|
||||
if ( !$bpin && $gfeedin > $fipl ) {$inc = $gfeedin - $fipl} # Ladefreigabe wenn akt. keine Bat-Ladung UND akt. Einspeisung > Einspeiselimit der Anlage
|
||||
if ( $bpin && ($gfeedin - $bpin) > $fipl ) {$inc = $bpin + (($gfeedin - $bpin) - $fipl)} # Ladefreigabe wenn akt. Bat-Ladung UND Eispeisung - Bat-Ladung > Einspeiselimit der Anlage
|
||||
|
||||
|
||||
if ( !$bpin && $gfeedin > $fipl ) {$inc = $gfeedin - $fipl} # Ladeleistung wenn akt. keine Bat-Ladung UND akt. Einspeisung > Einspeiselimit der Anlage
|
||||
if ( $bpin && ($gfeedin - $bpin) > $fipl ) {$inc = $bpin + (($gfeedin - $bpin) - $fipl)} # Ladeleistung wenn akt. Bat-Ladung UND Eispeisung - Bat-Ladung > Einspeiselimit der Anlage
|
||||
|
||||
$target = sprintf "%.0f", max ($target, $inc); # Einspeiselimit berücksichtigen
|
||||
$target = min ($bpinmax, $target); # 2. Begrenzung auf max. mögliche Batterieleistung
|
||||
$target = min (($csocwh <= $lowSocwh ? $bpinreduced : $bpinmax), $target); # 2. Begrenzung auf max. mögliche Batterieleistung bzw. bpinreduced bei Unterschreitung lowSoc
|
||||
$otp->{$sbn}{target} = $target;
|
||||
|
||||
storeReading ('Battery_ChargeOptTargetPower_'.$sbn, $target.' W');
|
||||
}
|
||||
}
|
||||
|
||||
$hsurp->{$hod}{$sbn}{fcendwh} = sprintf "%.0f", min ($sbatinstcap, $runwh + ($nhr eq '00' ? # Endwert Prognose aktuelle Stunde
|
||||
$otp->{$sbn}{target} :
|
||||
$hsurp->{$hod}{$sbn}{pneedmin}
|
||||
));
|
||||
|
||||
$hsurp->{$newshod}{$sbn}{fcnextwh} = $hsurp->{$hod}{$sbn}{fcendwh}; # Startwert kommende Stunde
|
||||
}
|
||||
|
||||
$sphrs-- if($spls); # Reststunden mit Überschuß
|
||||
}
|
||||
|
||||
return ($hsurp, $otp);
|
||||
}
|
||||
|
||||
###############################################################################################
|
||||
# Errechnet minimal benötigte konstante Ladeleistung: $ph Wh via Binärsuche Iteration
|
||||
#
|
||||
# - Wenn die Summe aller surplswh geringer ist als der Bedarf, wird Ereq automatisch auf
|
||||
# diesen Maximalwert gesetzt und liefert so die tatsächlich erreichbare Energie.
|
||||
# - gewichtete Stundenkapazität @hods enthält die Stunden-Keys sortiert von der niedrigsten
|
||||
# bis zur höchsten Leistung. In jeder Binärsuche-Iteration addiert das Skript
|
||||
# min(ph, surplswh) für jede Stunde, wodurch die konstant gewählte Leistung ph gemäß der
|
||||
# verfügbaren Kapazität gewichtet wird.
|
||||
# - Rückgabe Nach X Iterationen steht $high als kleinstmöglicher Wert für ph bereit. Er
|
||||
# garantiert entweder das Erreichen von Ereq Wh oder – falls das Ziel unerreichbar war –
|
||||
# die vollständige Ausnutzung der vorhandenen Kapazität.
|
||||
###############################################################################################
|
||||
sub ___batFindMinPhWh {
|
||||
my ($hsurp, $aref, $runwhneed) = @_;
|
||||
my @hods = @$aref;
|
||||
|
||||
my $Ereq = $runwhneed; # 1. Benötigte Energie (Wh) bestimmen
|
||||
my $achievable = 1;
|
||||
my $total = 0; # 2. Gesamtkapazität aller Stunden mit PV-Überschuß ermitteln
|
||||
$total += $hsurp->{$_}{surplswh} for @hods;
|
||||
|
||||
if ($total < $Ereq) {
|
||||
$achievable = 0;
|
||||
#$Ereq = $total; # 3. Wenn Ziel nicht erreichbar: Ereq auf Maximum setzen
|
||||
}
|
||||
|
||||
my $low = 0; # 4. Binärsuche für konstante Ladeleistung ph (Wh/h)
|
||||
my $high = max map { $hsurp->{$_}{surplswh} } @hods;
|
||||
my $eps = 0.5; # minimale Genauigkeit in Wh (1e-3)
|
||||
my $max_iter = 100; # Zwangsabbruch nach X Durchläufen
|
||||
my $loop = 0;
|
||||
|
||||
while (($high - $low) > $eps) {
|
||||
last if ++$loop > $max_iter;
|
||||
|
||||
my $mid = ($low + $high) / 2;
|
||||
my $charged = 0;
|
||||
|
||||
for my $hod (@hods) {
|
||||
my $cap = $hsurp->{$hod}{surplswh};
|
||||
$charged += $mid < $cap ? $mid : $cap;
|
||||
}
|
||||
|
||||
$charged >= $Ereq ? ($high = $mid) : ($low = $mid);
|
||||
}
|
||||
|
||||
$high = max (0, $high);
|
||||
|
||||
return { ph => (sprintf "%.0f", $high), iterations => $loop, blur => (sprintf "%.4f", ($high - $low)), achievable => $achievable };
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Speicherung Ergebnisse aus Batterie Lademanagement
|
||||
################################################################
|
||||
@@ -12046,14 +12132,16 @@ sub ___batChargeSaveResults {
|
||||
|
||||
my $name = $paref->{name};
|
||||
my $hsoc = $values->{hsoc}; # Referenz SoC-Hash
|
||||
my $otp = $values->{otp}; # Referenz OTP-Hash
|
||||
my $bn = $values->{bn}; # Batterie Nummer
|
||||
my $num = $values->{num}; # Nexthours Schleife (0..MAXNEXTHOURS)
|
||||
my $nhr = $values->{nhr}; # zweistellige lfd. Nexthour
|
||||
my $progsoc = $values->{progsoc}; # Prognose-SoC in %
|
||||
my $socwh = $values->{socwh}; # Prognose-SoC in Wh
|
||||
my $today = $values->{today}; # Statusbit aktueller Tag
|
||||
my $hod = $values->{hod}; # Stunde des Tages
|
||||
my $loop = $values->{loop}; # in welcher Loop gestartet?
|
||||
my $loopid = $values->{loopid}; # in welcher Loop ist sub aufgerufen?
|
||||
my $strategy = $values->{strategy}; # welche Lade-Strategie wird verwendet
|
||||
|
||||
my $crel = $values->{crel}; # nur in Schleife 'loadRelease' mitgeben
|
||||
my $labortCond = $values->{labortCond}; # nur in Schleife 'loadRelease' mitgeben
|
||||
my $loadAbort = $values->{loadAbort}; # nur in Schleife 'loadRelease' mitgeben
|
||||
@@ -12062,36 +12150,50 @@ sub ___batChargeSaveResults {
|
||||
|
||||
## in Schleife 'loadRelease' setzen
|
||||
#####################################
|
||||
if ($loop eq 'LR') { # nur in Schleife 'loadRelease' setzen
|
||||
if ($loopid eq 'LR') { # nur in Schleife 'loadRelease' setzen
|
||||
$data{$name}{nexthours}{'NextHour'.$nhr}{'rcdchargebat'.$bn} = $crel;
|
||||
$data{$name}{nexthours}{'NextHour'.$nhr}{'lcintimebat'.$bn} = $lcintime if($cgbt); # nur einmal bei 'loadRelease' setzen -> Ladesteuerung "In Time", "nicht In Time" oder nicht verwendet
|
||||
$data{$name}{nexthours}{'NextHour'.$nhr}{'strategybat'.$bn} = $strategy;
|
||||
|
||||
if (!$num) {
|
||||
if ($nhr eq '00') {
|
||||
storeReading ('Battery_ChargeUnrestricted_'.$bn, $crel);
|
||||
storeReading ('Battery_ChargeAbort_'.$bn, $labortCond) if ($loadAbort); # Ladeabbruchbedingung
|
||||
}
|
||||
|
||||
if ($today && $hod) {
|
||||
writeToHistory ( { paref => $paref, key => 'lcintimebat'.$bn, val => $lcintime, hour => $hod } ) if($cgbt); # nur einmal bei 'loadRelease' setzen
|
||||
writeToHistory ( { paref => $paref, key => 'lcintimebat'.$bn, val => $lcintime, hour => $hod } ) if($cgbt);
|
||||
writeToHistory ( { paref => $paref, key => 'strategybat'.$bn, val => $strategy, hour => $hod } );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($today && $hod) {
|
||||
writeToHistory ( { paref => $paref, key => 'batprogsoc'.$bn, val => $progsoc, hour => $hod } );
|
||||
## in Schleife 'optPower' setzen
|
||||
##################################
|
||||
if ($loopid eq 'OTP') {
|
||||
if ($nhr eq '00') { # Target für aktuelle Stunde
|
||||
my $needmin = $otp->{$bn}{target} // 0;
|
||||
storeReading ('Battery_ChargeOptTargetPower_'.$bn, $needmin.' W');
|
||||
}
|
||||
}
|
||||
|
||||
__createNextHoursSFCReadings ( {name => $name,
|
||||
nhr => $nhr,
|
||||
bn => $bn,
|
||||
progsoc => $progsoc
|
||||
}
|
||||
); # Readings NextHourXX_Bat_XX_ChargeForecast erstellen
|
||||
## abhängig von Strategie in entsprechender Schleife setzen
|
||||
#############################################################
|
||||
if (($loopid eq 'LR' && $strategy eq 'loadRelease') || ($loopid eq 'OTP' && $strategy eq 'optPower')) {
|
||||
if ($today && $hod) {
|
||||
writeToHistory ( { paref => $paref, key => 'batprogsoc'.$bn, val => $progsoc, hour => $hod } );
|
||||
}
|
||||
|
||||
__createNextHoursSFCReadings ( {name => $name,
|
||||
nhr => $nhr,
|
||||
bn => $bn,
|
||||
progsoc => $progsoc
|
||||
}
|
||||
); # Readings NextHourXX_Bat_XX_ChargeForecast erstellen
|
||||
|
||||
$data{$name}{nexthours}{'NextHour'.$nhr}{'soc'.$bn} = $progsoc;
|
||||
$data{$name}{nexthours}{'NextHour'.$nhr}{'soc'.$bn} = $progsoc;
|
||||
|
||||
$hsoc->{$nhr}{socprogwhsum} += $socwh; # Hilfshash Aufsummierung SoC-Prognose (Wh) über alle Batterien
|
||||
}
|
||||
|
||||
$hsoc->{$nhr}{socprogwhsum} += $socwh; # Hilfshash Aufsummierung SoC-Prognose (Wh) über alle Batterien
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12211,13 +12313,12 @@ sub _createSummaries {
|
||||
$tdConFcTillSunset -= ($confc / 60) * $diflasth;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$tomorrowSum->{PV} += $pvfc if(int($nhday) == int($tmoday));
|
||||
|
||||
if (int($nhday) == int($datmoday)) {
|
||||
$daftertomSum->{PV} += $pvfc;
|
||||
$daftertomSum->{Consumption} += $confc;
|
||||
}
|
||||
elsif ($nhday eq $tmoday) {
|
||||
$tomorrowSum->{PV} += $pvfc;
|
||||
}
|
||||
elsif ($nhday eq $datmoday) {
|
||||
$daftertomSum->{PV} += $pvfc;
|
||||
$daftertomSum->{Consumption} += $confc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17535,6 +17636,7 @@ sub _beamFillupBatValues {
|
||||
|
||||
$hh->{$day_str}{$time_str}{'rcdchargebat'.$bn} = $rcdc;
|
||||
$hh->{$day_str}{$time_str}{'lcintimebat'.$bn} = NexthoursVal ($name, $idx, 'lcintimebat'.$bn, undef);
|
||||
$hh->{$day_str}{$time_str}{'strategybat'.$bn} = NexthoursVal ($name, $idx, 'strategybat'.$bn, undef);
|
||||
$hh->{$day_str}{$time_str}{'soc'.$bn} = NexthoursVal ($name, $idx, 'soc'.$bn, undef);
|
||||
}
|
||||
}
|
||||
@@ -17557,6 +17659,7 @@ sub _beamFillupBatValues {
|
||||
#####################################
|
||||
$hfcg->{$kdx}{'rcdchargebat'.$bn} = $hh->{$ds}{$ts}{'rcdchargebat'.$bn} if(defined $hh->{$ds}{$ts}{'rcdchargebat'.$bn});
|
||||
$hfcg->{$kdx}{'lcintimebat'.$bn} = $hh->{$ds}{$ts}{'lcintimebat'.$bn} if(defined $hh->{$ds}{$ts}{'lcintimebat'.$bn});
|
||||
$hfcg->{$kdx}{'strategybat'.$bn} = $hh->{$ds}{$ts}{'strategybat'.$bn} if(defined $hh->{$ds}{$ts}{'strategybat'.$bn});
|
||||
$hfcg->{$kdx}{'soc'.$bn} = $hh->{$ds}{$ts}{'soc'.$bn} if(defined $hh->{$ds}{$ts}{'soc'.$bn});
|
||||
|
||||
## Auffüllen mit History Werten (Achtung: Stundenverschieber relativ zu Nexthours)
|
||||
@@ -17564,10 +17667,12 @@ sub _beamFillupBatValues {
|
||||
if (!defined $hh->{$ds}{$ts}{'rcdchargebat'.$bn}) {
|
||||
my $histsoc = HistoryVal ($hash, $ds, (sprintf "%02d", $ts+1), 'batsoc'.$bn, undef);
|
||||
my $lcintime = HistoryVal ($hash, $ds, (sprintf "%02d", $ts+1), 'lcintimebat'.$bn, undef);
|
||||
my $strategy = HistoryVal ($hash, $ds, (sprintf "%02d", $ts+1), 'strategybat'.$bn, undef);
|
||||
|
||||
if (defined $histsoc) {
|
||||
$hfcg->{$kdx}{'rcdchargebat'.$bn} = 'hist';
|
||||
$hfcg->{$kdx}{'lcintimebat'.$bn} = $lcintime;
|
||||
$hfcg->{$kdx}{'strategybat'.$bn} = $strategy;
|
||||
$hfcg->{$kdx}{'soc'.$bn} = $histsoc;
|
||||
}
|
||||
}
|
||||
@@ -18161,6 +18266,11 @@ sub __batteryOnBeam {
|
||||
$time_str = (split ":", $time_str)[0]; # Forum: https://forum.fhem.de/index.php?msg=1332721
|
||||
my $soc = $hfcg->{$i}{'soc'.$bn};
|
||||
my $lcintime = $hfcg->{$i}{'lcintimebat'.$bn}; # Lademanagement für Batterie XX ist aktiviert
|
||||
my $strategy = $hfcg->{$i}{'strategybat'.$bn} // '-'; # Ladestrategie
|
||||
|
||||
my $stysymbol = $strategy eq 'loadRelease' ? 'ldreleas' :
|
||||
$strategy eq 'optPower' ? 'optchpow' :
|
||||
'norate';
|
||||
|
||||
my ($bpower, $currsoc);
|
||||
|
||||
@@ -18178,7 +18288,7 @@ sub __batteryOnBeam {
|
||||
flag => $hfcg->{$i}{'rcdchargebat'.$bn},
|
||||
msg1 => $balias,
|
||||
msg2 => $lcintime,
|
||||
msg3 => $htitles{ldreleas}{$lang},
|
||||
msg3 => $htitles{$stysymbol}{$lang},
|
||||
soc => $soc,
|
||||
pcurr => $bpower,
|
||||
lang => $lang
|
||||
@@ -20972,7 +21082,7 @@ sub _listDataPoolPvHist {
|
||||
$prdl .= "pprl${pn}: $pprl";
|
||||
}
|
||||
|
||||
my ($btotin, $batin, $btotout, $batout, $batmsoc, $batssoc, $batprogsoc, $batsoc, $lcintime);
|
||||
my ($btotin, $batin, $btotout, $batout, $batmsoc, $batssoc, $batprogsoc, $batsoc, $lcintime, $lcstrategy);
|
||||
for my $bn (1..MAXBATTERIES) { # + alle Batterien
|
||||
$bn = sprintf "%02d", $bn;
|
||||
my $hbtotin = HistoryVal ($name, $day, $key, 'batintotal'.$bn, '-');
|
||||
@@ -20984,6 +21094,7 @@ sub _listDataPoolPvHist {
|
||||
my $hbatprogsoc = HistoryVal ($name, $day, $key, 'batprogsoc'.$bn, '-');
|
||||
my $hbatsoc = HistoryVal ($name, $day, $key, 'batsoc'.$bn, '-');
|
||||
my $intime = HistoryVal ($name, $day, $key, 'lcintimebat'.$bn, '-');
|
||||
my $strategy = HistoryVal ($name, $day, $key, 'strategybat'.$bn, '-');
|
||||
|
||||
if ($export eq 'csv') {
|
||||
$hexp->{$day}{$key}{"BatteryInTotal${bn}"} = $hbtotin;
|
||||
@@ -20995,6 +21106,7 @@ sub _listDataPoolPvHist {
|
||||
$hexp->{$day}{$key}{"BatteryProgSoc${bn}"} = $hbatprogsoc;
|
||||
$hexp->{$day}{$key}{"BatterySoc${bn}"} = $hbatsoc;
|
||||
$hexp->{$day}{$key}{"BatteryLCinTime${bn}"} = $intime;
|
||||
$hexp->{$day}{$key}{"BatteryStrategy${bn}"} = $strategy;
|
||||
}
|
||||
|
||||
$btotin .= ', ' if($btotin);
|
||||
@@ -21015,6 +21127,8 @@ sub _listDataPoolPvHist {
|
||||
$batsoc .= "batsoc${bn}: $hbatsoc";
|
||||
$lcintime .= ', ' if($lcintime);
|
||||
$lcintime .= "lcintimebat${bn}: $intime";
|
||||
$lcstrategy .= ', ' if($lcstrategy);
|
||||
$lcstrategy .= "strategybat${bn}: $strategy";
|
||||
}
|
||||
|
||||
$ret .= "\n " if($ret);
|
||||
@@ -21047,7 +21161,9 @@ sub _listDataPoolPvHist {
|
||||
$ret .= "\n " if($key ne '99');
|
||||
$ret .= $lcintime if($key ne '99');
|
||||
$ret .= "\n " if($key ne '99');
|
||||
|
||||
$ret .= $lcstrategy if($key ne '99');
|
||||
$ret .= "\n " if($key ne '99');
|
||||
|
||||
$ret .= $batin;
|
||||
$ret .= "\n ";
|
||||
$ret .= $batout;
|
||||
@@ -21448,16 +21564,19 @@ sub _listDataPoolNextHours {
|
||||
my $socprgs = NexthoursVal ($name, $idx, 'socprogwhsum', '-');
|
||||
my $dinrang = NexthoursVal ($name, $idx, 'DaysInRange', '-');
|
||||
|
||||
my ($rcdbat, $socs, $lcintime);
|
||||
my ($rcdbat, $socs, $lcintime, $lcstrategy);
|
||||
for my $bn (1..MAXBATTERIES) { # alle Batterien
|
||||
$bn = sprintf "%02d", $bn;
|
||||
my $rcdcharge = NexthoursVal ($name, $idx, 'rcdchargebat'.$bn, '-');
|
||||
my $intime = NexthoursVal ($name, $idx, 'lcintimebat'.$bn, '-');
|
||||
my $strategy = NexthoursVal ($name, $idx, 'strategybat'.$bn, '-');
|
||||
my $socxx = NexthoursVal ($name, $idx, 'soc'.$bn, '-');
|
||||
$rcdbat .= ', ' if($rcdbat);
|
||||
$rcdbat .= "rcdchargebat${bn}: $rcdcharge";
|
||||
$lcintime .= ', ' if($lcintime);
|
||||
$lcintime .= "lcintimebat${bn}: $intime";
|
||||
$lcstrategy .= ', ' if($lcstrategy);
|
||||
$lcstrategy .= "strategybat${bn}: $strategy";
|
||||
$socs .= ', ' if($socs);
|
||||
$socs .= "soc${bn}: $socxx";
|
||||
}
|
||||
@@ -21479,6 +21598,8 @@ sub _listDataPoolNextHours {
|
||||
$sq .= $rcdbat;
|
||||
$sq .= "\n ";
|
||||
$sq .= $lcintime;
|
||||
$sq .= "\n ";
|
||||
$sq .= $lcstrategy;
|
||||
}
|
||||
|
||||
return $sq;
|
||||
@@ -26283,6 +26404,7 @@ to ensure that the system configuration is correct.
|
||||
<tr><td> <b>today</b> </td><td>has value '1' if start date on current day </td></tr>
|
||||
<tr><td> <b>rcdchargebatXX</b> </td><td>Charging recommendation with full power for battery XX (1 - Yes, 0 - No) </td></tr>
|
||||
<tr><td> <b>lcintimebatXX</b> </td><td>Charge management for battery XX is activated or will be activated (1 - Yes, 0 - No) </td></tr>
|
||||
<tr><td> <b>strategybatXX</b> </td><td>the selected charging strategy </td></tr>
|
||||
<tr><td> <b>rr1c</b> </td><td>Total precipitation during the last hour kg/m2 </td></tr>
|
||||
<tr><td> <b>rrange</b> </td><td>range of total rain </td></tr>
|
||||
<tr><td> <b>socXX</b> </td><td>current (NextHour00) or predicted SoC (%) of battery XX </td></tr>
|
||||
@@ -26334,6 +26456,7 @@ to ensure that the system configuration is correct.
|
||||
<tr><td> <b>feedprice</b> </td><td>Remuneration for the feed-in of one kWh. The currency of the price is defined in the setupMeterDev. </td></tr>
|
||||
<tr><td> <b>hourscsmeXX</b> </td><td>total active hours of the day from ConsumerXX </td></tr>
|
||||
<tr><td> <b>lcintimebatXX</b> </td><td>the charge management for battery XX was activated (1 - Yes, 0 - No) </td></tr>
|
||||
<tr><td> <b>strategybatXX</b> </td><td>the selected charging strategy </td></tr>
|
||||
<tr><td> <b>minutescsmXX</b> </td><td>total active minutes in the hour of ConsumerXX </td></tr>
|
||||
<tr><td> <b>plantderated</b> </td><td>Timestamp of the first curtailment event of the system in this hour, otherwise '0' </td></tr>
|
||||
<tr><td> <b>pprlXX</b> </td><td>Energy generation of producer XX (see attribute setupOtherProducerXX) in the hour (Wh) </td></tr>
|
||||
@@ -26918,7 +27041,7 @@ to ensure that the system configuration is correct.
|
||||
<a id="SolarForecast-attr-ctrlBatSocManagementXX" data-pattern="ctrlBatSocManagement.*"></a>
|
||||
<li><b>ctrlBatSocManagementXX lowSoc=<Value> upSoC=<Value> [maxSoC=<Value>] [careCycle=<Value>]
|
||||
[lcSlot=<hh:mm>-<hh:mm>] [loadAbort=<SoC1>:<MinPwr>:<SoC2>]
|
||||
[safetyMargin=<Value>[:<Value>]] </b> <br><br>
|
||||
[safetyMargin=<Value>[:<Value>]] [loadStrategy=<Value>] </b> <br><br>
|
||||
|
||||
If a battery device (setupBatteryDevXX) is installed, this attribute activates the battery SoC and charge management
|
||||
for this battery device. <br>
|
||||
@@ -26971,6 +27094,11 @@ to ensure that the system configuration is correct.
|
||||
<tr><td> </td><td>surcharge used to calculate the optimized load capacity. Both values are percentages. </td></tr>
|
||||
<tr><td> </td><td>Value: <b>0..100[:0..100]</b> (integers) </td></tr>
|
||||
<tr><td> </td><td> </td></tr>
|
||||
<tr><td> <b>loadStrategy</b> </td><td>The selected charging strategy is taken into account when displaying the battery in bar graph. </td></tr>
|
||||
<tr><td> </td><td>The generation of tax readings is not affected. The specification is optional. </td></tr>
|
||||
<tr><td> </td><td>For more information on selecting a strategy, see german <a href="https://wiki.fhem.de/wiki/SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Welche_Ladestrategie_soll_ich_w%C3%A4hlen?_-_eine_M%C3%B6glichkeit_zur_Best-Practice_Findung_mit_Codebeispiel">Wiki</a>. </td></tr>
|
||||
<tr><td> </td><td>Value: <b>loadRelease or optPower</b>, default: loadRelease </td></tr>
|
||||
<tr><td> </td><td> </td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
<br>
|
||||
@@ -28960,6 +29088,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
<tr><td> <b>today</b> </td><td>hat Wert '1' wenn Startdatum am aktuellen Tag </td></tr>
|
||||
<tr><td> <b>rcdchargebatXX</b> </td><td>Aufladeempfehlung mit voller Leistung für Batterie XX (1 - Ja, 0 - Nein) </td></tr>
|
||||
<tr><td> <b>lcintimebatXX</b> </td><td>Lademanagement für Batterie XX ist aktiviert bzw. wird aktiviert sein (1 - Ja, 0 - Nein) </td></tr>
|
||||
<tr><td> <b>strategybatXX</b> </td><td>die gewählte Ladestrategie </td></tr>
|
||||
<tr><td> <b>rr1c</b> </td><td>Gesamtniederschlag in der letzten Stunde kg/m2 </td></tr>
|
||||
<tr><td> <b>rrange</b> </td><td>Bereich des Gesamtniederschlags </td></tr>
|
||||
<tr><td> <b>socXX</b> </td><td>aktueller (NextHour00) oder prognostizierter SoC (%) der Batterie XX </td></tr>
|
||||
@@ -29012,6 +29141,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
<tr><td> <b>avgcycmntscsmXX</b> </td><td>durchschnittliche Dauer eines Einschaltzyklus des Tages von ConsumerXX in Minuten </td></tr>
|
||||
<tr><td> <b>hourscsmeXX</b> </td><td>Summe Aktivstunden des Tages von ConsumerXX </td></tr>
|
||||
<tr><td> <b>lcintimebatXX</b> </td><td>das Lademanagement für Batterie XX war aktiviert (1 - Ja, 0 - Nein) </td></tr>
|
||||
<tr><td> <b>strategybatXX</b> </td><td>die gewählte Ladestrategie </td></tr>
|
||||
<tr><td> <b>minutescsmXX</b> </td><td>Summe Aktivminuten in der Stunde von ConsumerXX </td></tr>
|
||||
<tr><td> <b>plantderated</b> </td><td>Zeitstempel des ersten Abregelungsvorfalls der Anlage in dieser Stunde, sonst '0' </td></tr>
|
||||
<tr><td> <b>pprlXX</b> </td><td>Energieerzeugung des Produzenten XX (siehe Attribut setupOtherProducerXX) in der Stunde (Wh) </td></tr>
|
||||
@@ -29595,7 +29725,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
<a id="SolarForecast-attr-ctrlBatSocManagementXX" data-pattern="ctrlBatSocManagement.*"></a>
|
||||
<li><b>ctrlBatSocManagementXX lowSoc=<Wert> upSoC=<Wert> [maxSoC=<Wert>] [careCycle=<Wert>]
|
||||
[lcSlot=<hh:mm>-<hh:mm>] [loadAbort=<SoC1>:<MinPwr>:<SoC2>]
|
||||
[safetyMargin=<Wert>[:<Wert>]] </b> <br><br>
|
||||
[safetyMargin=<Wert>[:<Wert>]] [loadStrategy=<Wert>] </b> <br><br>
|
||||
|
||||
Sofern ein Batterie Device (setupBatteryDevXX) installiert ist, aktiviert dieses Attribut das Batterie
|
||||
SoC- und Lade-Management für dieses Batteriegerät. <br>
|
||||
@@ -29649,6 +29779,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
<tr><td> </td><td>Zuschlag bei der Berechnung der optimierten Ladeleistung. Beide Angaben sind Prozentwerte. </td></tr>
|
||||
<tr><td> </td><td>Wert: <b>0..100[:0..100]</b> (Ganzzahlen) </td></tr>
|
||||
<tr><td> </td><td> </td></tr>
|
||||
<tr><td> <b>loadStrategy</b> </td><td>Bei der Anzeige der Batterie in der Balkengrafik wird die gewählte Ladestrategie berücksichtigt.</td></tr>
|
||||
<tr><td> </td><td>Die Generierung der Steuerreadings wird nicht beeinflusst. Die Angabe ist optional. </td></tr>
|
||||
<tr><td> </td><td>Weitere Informationen zur Auswahl der Strategie siehe <a href="https://wiki.fhem.de/wiki/SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Welche_Ladestrategie_soll_ich_w%C3%A4hlen?_-_eine_M%C3%B6glichkeit_zur_Best-Practice_Findung_mit_Codebeispiel">Wiki</a>. </td></tr>
|
||||
<tr><td> </td><td>Wert: <b>loadRelease oder optPower</b>, default: loadRelease </td></tr>
|
||||
<tr><td> </td><td> </td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
Reference in New Issue
Block a user