'.sprintf ("%.0f", $soc);
}
elsif ($blabel eq 'beside') {
$image = '
'.$image;
- $image .= '
'.sprintf ("%.0f", $soc);
+ $image .= '
'.sprintf ("%.0f", $soc);
}
-
+
$image .= '
';
}
@@ -18911,7 +18990,7 @@ sub __batteryOnBeam {
debugLog ($paref, 'graphic', "Battery $bn pos >$i< day: $day_str, time: $time_str, Power ('-' = out): ".(defined $bpower ? $bpower : 'undef').
" W, Rcmd: ".(defined $hfcg->{$i}{'rcdchargebat'.$bn} ? $hfcg->{$i}{'rcdchargebat'.$bn} : 'undef').
- ", SoC: ".(defined $soc ? $soc : 'undef')." %, lcintime: ".(defined $lcintime ? $lcintime : 'undef'));
+ ", SoC: ".(defined $soc ? $soc : 'undef')." %, lcintime: ".(defined $lcintime ? $lcintime : 'undef'));
}
$ret .= "
| " if($ret); # freier Platz am Ende der Icon Zeile
@@ -19093,7 +19172,7 @@ sub _flowGraphic {
if ($vector->{batDischarge2HomeNode}) {
$bat2home_style = "$stna active_normal";
- $bat2home_direction = "M1200,515 L730,590";
+ $bat2home_direction = "M1200,515 L730,590";
}
@@ -19101,7 +19180,7 @@ sub _flowGraphic {
#####################################
my $cnsmr = {}; # Consumer Hilfshash Referenz
my $concurpsum = 0; # Summierung aller Consumerverbräuche
-
+
for my $c (sort{$a<=>$b} keys %{$data{$name}{consumers}}) { # definierte Verbraucher ermitteln
next if(isConsumerNoshow ($hash, $c) =~ /[13]/xs); # auszublendende Consumer nicht berücksichtigen
$cnsmr->{$c}{p} = ConsumerVal ($name, $c, 'currpower', 0);
@@ -19113,15 +19192,15 @@ sub _flowGraphic {
my $consumercount = keys %{$cnsmr};
$flowgconsumer = 0 if(!$consumercount); # Consumer Anzeige ausschalten wenn keine Consumer definiert
my @consumers = sort{$a<=>$b} keys %{$cnsmr};
-
+
my $total_shortalias_length = sum map { my $a = $_->{shortalias} // '';
strlength ($a); # Länge in Zeichen nach Zeichen-Dekodierung
}
values %{$cnsmr};
-
+
## Verbrauch Dummy bestimmen
##############################
- my $cons_dmy = $consptn - $concurpsum;
+ my $cons_dmy = $consptn - $concurpsum;
## Producer / Inverter Koordinaten Steuerhash
###############################################
@@ -19266,11 +19345,11 @@ END0
lang => $lang
}
);
-
+
my $ccicon = (split '@', $cicon)[1];
- $cicon = FW_makeImage ($cicon, '');
- $cicon = __normIconInnerScale ($cicon, $ccicon);
-
+ $cicon = FW_makeImage ($cicon, '');
+ $cicon = __normIconInnerScale ($cicon, $ccicon);
+
$ret .= qq{
};
$ret .= "$calias".$cicon;
$ret .= ' ';
@@ -19312,7 +19391,7 @@ END1
my $chicon = (split '@', $hicon)[1];
$hicon = FW_makeImage ($hicon, '');
$hicon = __normIconInnerScale ($hicon, $chicon);
-
+
$ret .= qq{
}; # translate(X-Koordinate,Y-Koordinate)
$ret .= "$hmtxt".$hicon;
$ret .= ' ';
@@ -19333,7 +19412,7 @@ END1
my $cdicon = (split '@', $dicon)[1];
$dicon = FW_makeImage ($dicon, '');
- $dicon = __normIconInnerScale ($dicon, $cdicon);
+ $dicon = __normIconInnerScale ($dicon, $cdicon);
$ret .= qq{
};
$ret .= "$dumtxt".$dicon;
@@ -19343,12 +19422,12 @@ END1
## Laufketten Node->Home, Node->Grid, Bat->Home
#################################################
my $node2home_style = $node2home ? "$stna active_normal" : "$stna inactive";
- my $node2home_direction = $node2home < 0 ? "M700,580 L700,400" : "M700,400 L700,580";
+ my $node2home_direction = $node2home < 0 ? "M700,580 L700,400" : "M700,400 L700,580";
my $node2gridMetered_style = $node2gridMetered ? "$stna active_normal" : "$stna inactive";
$ret .= << "END2";
-
+
END2
@@ -19475,9 +19554,9 @@ END3
my $consumer_style;
for my $c (@consumers) {
- $cnsmrpower = $cnsmr->{$c}{p};
+ $cnsmrpower = $cnsmr->{$c}{p};
my $cilon = isConsumerLogOn ($hash, $c, $cnsmrpower);
-
+
$consumer_style = $cilon ? "$stna active_normal" : "$stna inactive";
my $chain_color = ""; # Farbe der Laufkette des Consumers
@@ -19577,7 +19656,7 @@ END3
########################
if ($flowgconsumer) {
$cons_left = ($consumer_start * 2) - 50; # -XX -> Start Lage Consumer Beschriftung
-
+
my %offset = (
0b00 => 0, # weder Power noch Time
0b01 => 60, # nur Power
@@ -19589,12 +19668,12 @@ END3
$y_pos = $y_base; # flowgconsPower
my $mask = $flowgconsPower ? 1 : 0;
$y_pos1 = $y_base + $offset{$mask}; # flowgconsTime
-
+
$mask = $flowgconsPower && $flowgconsTime ? 3 :
- $flowgconsTime ? 2 :
+ $flowgconsTime ? 2 :
$flowgconsPower ? 1 :
0;
-
+
$y_pos2 = $y_base + $offset{$mask}; # shortalias
for my $c (@consumers) {
@@ -19610,13 +19689,13 @@ END3
my $lcp = strlength ($cnsmrpower);
my $lct = strlength ($consumerTime);
- my $lcs = strlength ($shortalias);
+ my $lcs = strlength ($shortalias);
# Texte abhängig von ihrer Größe entsprechend auf der x-Achse verschieben
###########################################################################
if ($flowgconsPower) { # Lage Consumer Consumption
my $lcp_cons_left = $cons_left;
-
+
if ($lcp >= 5) {$lcp_cons_left -= 40}
elsif ($lcp == 4) {$lcp_cons_left -= 25}
elsif ($lcp == 3) {$lcp_cons_left -= 5 }
@@ -19625,22 +19704,22 @@ END3
$ret .= qq{$cnsmrpower};
}
-
+
if ($flowgconsTime) { # Lage Consumer Restlaufzeit
my $lct_cons_left = $cons_left;
-
+
if ($lct >= 5) {$lct_cons_left -= 40}
elsif ($lct == 4) {$lct_cons_left -= 25}
elsif ($lct == 3) {$lct_cons_left -= 5 }
elsif ($lct == 2) {$lct_cons_left += 7 }
- elsif ($lct == 1) {$lct_cons_left += 25}
-
+ elsif ($lct == 1) {$lct_cons_left += 25}
+
$ret .= qq{$consumerTime};
}
-
+
if ($shortalias) { # Lage Consumer Kurzalias
my $lcs_cons_left = $cons_left;
-
+
if ($lcs >= 10) {$lcs_cons_left -= 85}
elsif ($lcs == 9) {$lcs_cons_left -= 85}
elsif ($lcs == 8) {$lcs_cons_left -= 70}
@@ -19650,11 +19729,11 @@ END3
elsif ($lcs == 4) {$lcs_cons_left -= 10}
elsif ($lcs == 3) {$lcs_cons_left -= 0 }
elsif ($lcs == 2) {$lcs_cons_left += 7 }
- elsif ($lcs == 1) {$lcs_cons_left += 25}
-
+ elsif ($lcs == 1) {$lcs_cons_left += 25}
+
$ret .= qq{$shortalias};
}
-
+
$cons_left += ($cdist * 2);
}
}
@@ -19812,11 +19891,11 @@ sub __addInputProducerIcon {
lang => $lang
}
);
-
+
my $gcolor = (split '@', $genericon)[1];
$genericon = FW_makeImage ($genericon, '');
$genericon = __normIconInnerScale ($genericon, $gcolor);
-
+
$ret .= qq{};
$ret .= "$genertxt".$genericon;
$ret .= ' ';
@@ -19835,8 +19914,8 @@ sub __addInputProducerIcon {
my $cpicon = (split '@', $picon)[1];
$picon = FW_makeImage ($picon, '');
- $picon = __normIconInnerScale ($picon, $cpicon);
-
+ $picon = __normIconInnerScale ($picon, $cpicon);
+
$ret .= qq{};
$ret .= "$ptxt".$picon;
$ret .= ' ';
@@ -19869,11 +19948,11 @@ sub __addNodeIcon {
lang => $lang
}
);
-
+
my $cnicon = (split '@', $nicon)[1];
$nicon = FW_makeImage ($nicon, '');
$nicon = __normIconInnerScale ($nicon, $cnicon);
-
+
my $ret = qq{}; # translate(X-Koordinate,Y-Koordinate)
$ret .= "$ntxt".$nicon;
$ret .= ' ';
@@ -19941,7 +20020,7 @@ sub __substituteIcon {
$soctxt = "\n".$htitles{socbatfc}{$lang}.": ".$soc." %"; # Text 'SoC Prognose'
my $socicon = batSoc2icon ($soc);
-
+
$ircmd = $ircmd ? $ircmd : '';
$inorcmd = $inorcmd ? $inorcmd : '';
$icharge = $icharge ? $icharge : '';
@@ -19975,7 +20054,7 @@ sub __substituteIcon {
$pretxt = $htitles{onlybatw}{$lang}." $pn: $msg1".($cgbt ? "\n".$htitles{bncharel}{$lang} : '');
}
}
-
+
$pretxt .= "\n".$htitles{lcenable}{$lang}.": ".(defined $msg2 ? ($msg2 == 1 ? $htitles{simplyes}{$lang} : $htitles{simpleno}{$lang}) : '-');
$pretxt .= "\n".$htitles{ldstratg}{$lang}.": ".(defined $msg2 ? $msg3 : '-');
@@ -20015,9 +20094,9 @@ sub __substituteIcon {
$txt = $pretxt.$soctxt; # resultierender Text
}
-
+
if ($color && $color eq 'dyn') {
- $color = val2dynColor ($soc, 0, $flag ? 0 : 0.4);
+ $color = val2dynColor ($soc, 0, $flag ? 0 : 0.4);
}
}
elsif ($ptyp eq 'producer') { # Icon Producer
@@ -20131,25 +20210,25 @@ sub __normIconInnerScale {
$attr_str =~ s/\b(?:width|height)\s*=\s*"[^"]*"//gi; # Entferne bestehende Breiten-/Höhen-Attribute
my ($x, $y, $w, $h) = (0, 0, 100, 100); # Lese viewBox-Werte oder nutze Default (0,0,100,100)
-
+
if ($attr_str =~ /\bviewBox\s*=\s*"([\d.\-]+)\s+([\d.\-]+)\s+([\d.\-]+)\s+([\d.\-]+)"/i) {
- ($x, $y, $w, $h) = ($1, $2, $3, $4);
+ ($x, $y, $w, $h) = ($1, $2, $3, $4);
}
my $scale = sprintf '%.4f', ( $size / ($w > $h ? $w : $h) ); # Berechne Skalierung und Versatz
my $ox = sprintf '%.1f', ( ($size - $w * $scale) / 2 - $x * $scale ); # zentriert den Inhalt in einem Kasten mit Seitenlänge $size
my $oy = sprintf '%.1f', ( ($size - $h * $scale) / 2 - $y * $scale );
-
+
$ox += $pad; # fügt $pad ViewBox-Einheiten Rand links bzw. oben hinzu.
$oy += $pad;
- if ($fill) {
+ if ($fill) {
$inner =~ s/\bfill="[^"]*"/fill="$fill"/gi;
for my $tag (qw(path rect circle ellipse polygon polyline line stroke)) {
$inner =~ s{<$tag(?![^>]*\bfill=)}{<$tag fill="$fill"}gi;
}
}
-
+
$inner = qq{}.$inner.''; # gib Inner-Content zurück, umgeben von der Transform-Gruppe
return $inner;
@@ -20346,7 +20425,7 @@ sub checkdwdattr {
$err .= ", " if($err);
$err .= qq{ERROR - device "$dwddev" -> attribute "forecastResolution" must be set to "1"};
}
-
+
if ($fcd < DWDFCDAYSMIN) {
$warn = qq{WARNING - device "$dwddev" -> attribute "forecastDays" is not set to the minimum value of: }.DWDFCDAYSMIN;
}
@@ -20509,24 +20588,24 @@ sub __readFileMessages {
delete $data{$name}{filemessages};
my $count = 0;
-
+
while (my $line = <$fh>) {
chomp $line;
next if $line =~ /^\s*#/; # Kommentarzeilen überspringen
my ($id, $lang, $msg) = split /\|/, $line, 3;
next if(!isNumeric ($id)); # nur numeric IDs
- next if($lang !~ /^(DE|EN|SV)$/xs); # nur gültige Sprachen
+ next if($lang !~ /^(DE|EN|SV)$/xs); # nur gültige Sprachen
$data{$name}{filemessages}{$id}{$lang} = $msg;
$count++;
}
close $fh;
-
+
Log3 ($name, 4, "$name - Notification System - read local Message File >$messagefile< with $count entries.");
-
-
+
+
$data{$name}{filemessages}{999000}{TS} = time;
$data{$name}{filemessages}{999000}{TSNEXT} = $tsnext;
@@ -20595,7 +20674,7 @@ sub fillupMessageSystem {
$data{$name}{messages}{$midx}{DE} = encode ('utf8', $data{$name}{preparedmessages}{$smi}{DE});
$data{$name}{messages}{$midx}{EN} = encode ('utf8', $data{$name}{preparedmessages}{$smi}{EN});
}
-
+
# Integration File Messages
for my $mfi (sort keys %{$data{$name}{filemessages}}) {
next if($mfi >= IDXLIMIT);
@@ -20767,7 +20846,7 @@ sub aiAddInstance {
for my $idx (sort keys %{$data{$name}{aidectree}{airaw}}) {
next if(!$idx);
-
+
if (!AiRawdataVal ($name, $idx, 'pvrlvd', 1)) {
debugLog ($paref, 'aiProcess', "AI Instance add - AI raw data (pvrlvd) is marked as invalid and is ignored - idx: $idx");
next;
@@ -20775,7 +20854,7 @@ sub aiAddInstance {
my $pvrl = AiRawdataVal ($name, $idx, 'pvrl', undef);
next if(!defined $pvrl);
-
+
my $hod = AiRawdataVal ($name, $idx, 'hod', undef);
next if(!defined $hod);
@@ -20871,7 +20950,7 @@ sub aiAddInstance {
}
delete $data{$name}{aidectree}{aitrained};
-
+
$paref->{cst} = $cst;
$serial = aiTrain ($paref);
delete $paref->{cst};
@@ -20931,11 +21010,11 @@ sub aiTrain {
$entities{$tn} = $enum;
$entities{rn} += scalar $dtree->rule_statements();
}
-
+
$data{$name}{aidectree}{aitrained} = \@ensemble;
$err = writeCacheToFile ($hash, 'aitrained', $aitrained.$name);
delete $data{$name}{aidectree}{aitrained};
-
+
my $rn;
if (!$err) {
$rn = delete $entities{rn};
@@ -21212,7 +21291,7 @@ sub aiAddRawData {
$data{$name}{aidectree}{airaw}{$ridx}{rad1h} = $rad1h if(defined $rad1h && $rad1h > 0);
$data{$name}{aidectree}{airaw}{$ridx}{pvrl} = $pvrl if(defined $pvrl && $pvrl > 0);
$data{$name}{aidectree}{airaw}{$ridx}{pvrlvd} = $pvrlvd;
-
+
$dosave++;
debugLog ($paref, 'aiProcess', "AI raw add - idx: $ridx, day: $pvd, hod: $hod, sunalt: $sunalt, sunaz: $sunaz, rad1h: ".(defined $rad1h ? $rad1h : '-').", pvrl: ".(defined $pvrl ? $pvrl : '-').", con: ".(defined $con ? $con : '-').", wcc: ".(defined $wcc ? $wcc : '-').", rr1c: ".(defined $rr1c ? $rr1c : '-').", temp: ".(defined $temp ? $temp : '-'), 4);
@@ -21758,7 +21837,7 @@ sub _listDataPoolPvHist {
$ret .= "\n " if($key ne '99');
$ret .= $lcstrategy if($key ne '99');
$ret .= "\n " if($key ne '99');
-
+
$ret .= $batin;
$ret .= "\n ";
$ret .= $batout;
@@ -22366,7 +22445,7 @@ sub _listDataPoolAiRawData {
my $h = $data{$name}{aidectree}{airaw};
my $maxcnt = keys %{$h};
-
+
if (!$maxcnt) {
return qq{aiRawData values cache is empty.};
}
@@ -22656,7 +22735,7 @@ sub checkPlantConfig {
else {
if (!$apiu) { # keine Wetter-API -> Wetterdevice
($err, $warnmsg) = checkdwdattr ($name, $fcname, \@dweattrmust);
-
+
if ($warnmsg) {
$result->{'Weather Properties'}{state} = $warn;
$result->{'Weather Properties'}{result} .= $warnmsg.'
';
@@ -22683,7 +22762,7 @@ sub checkPlantConfig {
$result->{'Weather Properties'}{note} .= qq{checked parameters and attributes of device "$fcname":
};
$result->{'Weather Properties'}{note} .= 'forecastProperties -> '.join (',', @dweattrmust).'
';
$result->{'Weather Properties'}{note} .= 'forecastRefresh '.($mosm eq 'MOSMIX_L' ? '-> set attribute to below "6" if possible' : '').'
';
- $result->{'Weather Properties'}{note} .= 'forecastDays
';
+ $result->{'Weather Properties'}{note} .= 'forecastDays
';
}
else {
$result->{'Weather Properties'}{result} .= $hqtxt{fulfd}{$lang}." ($hqtxt{attrib}{$lang}: setupWeatherDev$step)
";
@@ -22844,7 +22923,7 @@ sub checkPlantConfig {
$result->{'Common Settings'}{note} .= qq{If the local attribute "ctrlLanguage" or the global attribute "language" is changed to "DE" most of the outputs are in German.
};
$result->{'Common Settings'}{info} = 1;
}
-
+
if (!$aiprep) {
$result->{'Common Settings'}{state} = $info;
$result->{'Common Settings'}{result} .= qq{AI support for the PV forecast is not used.
};
@@ -22865,7 +22944,7 @@ sub checkPlantConfig {
$result->{'Common Settings'}{note} .= qq{Set the coordinates of your installation in the longitude attribute of the global device.
};
$result->{'Common Settings'}{warn} = 1;
}
-
+
if (!$gdn) {
$result->{'Common Settings'}{state} = $nok;
$result->{'Common Settings'}{result} .= qq{Attribute dnsServer in global device is not set.
};
@@ -23076,12 +23155,12 @@ sub checkPlantConfig {
$result->{'Data Memory'}{note} .= qq{
checked Data Memory:
};
$result->{'Data Memory'}{note} .= qq{pvHistory key 'con'
};
}
-
+
## Plant Control Check
########################
- my $rdcs = CurrentVal ($name, 'reductionState', '');
+ my $rdcs = CurrentVal ($name, 'reductionState', '');
my $fipl = CurrentVal ($name, 'feedinPowerLimit', '');
-
+
if (!$rdcs) {
$result->{'Plant Control'}{state} = $info;
$result->{'Plant Control'}{result} .= qq{It may be useful setting 'plantControl->reductionState'.
};
@@ -23089,7 +23168,7 @@ sub checkPlantConfig {
# $result->{'Plant Control'}{note} .= qq{(see SolCast API)
};
$result->{'Plant Control'}{info} = 1;
}
-
+
if (!$fipl && isBatteryUsed ($name)) {
$result->{'Plant Control'}{state} = $info;
$result->{'Plant Control'}{result} .= qq{It may be useful setting 'plantControl->feedinPowerLimit' if Batteries are installed.
};
@@ -23250,7 +23329,7 @@ sub determSurplus {
$method = $num ? "median:$num" : "median:all";
}
elsif ($surpmeth =~ /average/xs) { # Average Ermittlung, !kann UNDEF sein!
- my $num = (split '_', $surpmeth)[1];
+ my $num = (split '_', $surpmeth)[1];
$surplus = avgArray ($splref, $num);
$method = $num ? "average:$num" : "average:all";
}
@@ -23281,7 +23360,7 @@ sub determSurplus {
$surplus = CurrentVal ($name, 'surplus', 0);
$method = $method." but fallback to 'default'";
}
-
+
$surplus //= 0;
return ($method, $surplus);
@@ -23346,9 +23425,9 @@ sub avgArray {
my $num = shift // SLIDENUMMAX;
return undef if(ref $aref ne 'ARRAY' || scalar @{$aref} < $num);
-
+
my @tail = @{$aref}[-$num .. -1]; # es werden die neuesten num Elemente verwendet
-
+
my $sum = 0;
$sum += $_ for @tail;
@@ -23362,27 +23441,27 @@ return $avg;
# (https://www.ionos.de/digitalguide/online-marketing/web-analyse/median-berechnen/)
#
# $aref = Referenz zum Array
-# $num = Anzahl der neuesten zu verwendenden Array Elemente
+# $num = Anzahl der neuesten zu verwendenden Array Elemente
#
######################################################################################
sub medianArray {
my $aref = shift;
my $num = shift;
- return if(ref $aref ne 'ARRAY' || !scalar @{$aref});
-
+ return if(ref $aref ne 'ARRAY' || !scalar @{$aref});
+
if (defined $num) { # Anzahl der (neuesten) Elemente die verwendet werden sollen
return unless $num =~ /^\d+$/ && $num > 0 && $num <= @$aref;
}
-
- my @tail = defined $num ? @{$aref}[-$num .. -1] : @{$aref};
+
+ my @tail = defined $num ? @{$aref}[-$num .. -1] : @{$aref};
my @sorted = sort { $a <=> $b } @tail; # Numerisch aufsteigend
my $n = scalar @sorted;
my $mid = int ($n/2);
my $median = $n % 2 ? $sorted[$mid] : # ungerade Elemente -> Median Element steht in der Mitte von @sorted
($sorted[$mid - 1] + $sorted[$mid]) / 2; # gerade Elemente -> Median ist der Durchschnitt der beiden mittleren Elemente
-
+
return $median;
}
@@ -23674,25 +23753,25 @@ return;
}
################################################################
-# Ausgabe einer Log-Message nach Zeit erlauben.
+# Ausgabe einer Log-Message nach Zeit erlauben.
# Gibt "wahr" zurück wenn die Message noch nicht oder vor
# längerer Zeit als $delay Sekunden ausgegeben wurde
#
# delay => Sek. bis gleiche Meldung wieder geloggt werden darf
# (default LOGDELAY)
################################################################
-sub askLogtime {
+sub askLogtime {
my $name = shift;
my $err = shift;
my $delay = shift // LOGDELAY;
-
+
return if(!$err);
-
+
my $dolog = 1;
-
+
if ($digestAbsent) {
- Log3 ($name, 1, "$name - ERROR - The Perl module $digestAbsent is missing. Please install it");
- return $dolog;
+ Log3 ($name, 1, "$name - ERROR - The Perl module $digestAbsent is missing. Please install it");
+ return $dolog;
}
my $now = time;
@@ -23701,21 +23780,21 @@ sub askLogtime {
if (my $entry = $data{$name}{log}{$sha1}) {
$entry->{msg} = $err unless defined $entry->{msg} && $entry->{msg} eq $err; # falls der gespeicherte Text aus irgendeinem Grund anders ist, aktualisiere ihn
-
+
if ($entry->{ts} && $entry->{ts} + $delay > $now) {
$dolog = 0; # noch innerhalb der Drosselzeit -> nicht loggen
}
}
- if ($dolog) {
+ if ($dolog) {
$data{$name}{log}{$sha1} = { ts => $now, msg => $err }; # Eintrag aktualisieren / anlegen wenn log erlaubt ist
- }
-
+ }
+
return $dolog;
}
##################################################################
-# Konvertiert Azimut von der Solar-Konvention (+180 .. 0 .. -180)
+# Konvertiert Azimut von der Solar-Konvention (+180 .. 0 .. -180)
# in die astronomische Konvention (0 ... 360°)
##################################################################
sub azSolar2Astro {
@@ -23725,7 +23804,7 @@ return ($azsolar + 180) % 360;
}
###################################################################
-# liefert eine dynamische Farbe abhängig von "$val" und dem
+# liefert eine dynamische Farbe abhängig von "$val" und dem
# Ende-Wert "$end" zurück
# https://www.w3schools.com/colors/colors_picker.asp
# https://wiki.fhem.de/wiki/Color#Skalenfarbe_mit_Color::pahColor
@@ -23752,7 +23831,7 @@ sub val2dynColor {
my $val = shift; # Wert von 0 bis 100
my $satiety = shift; # Sättigung 0.1 (mehr Grau) ..1 (Original)
my $opacity = shift;
-
+
$val = max(0, min(100, $val));
my ($r, $g, $b, $t);
@@ -23762,20 +23841,20 @@ sub val2dynColor {
$r = 255;
$g = int (140 * $t); # 0 → 140
$b = 0;
- }
+ }
else { # Übergang: Orange (#FF8C00) → Dunkelgrün (#00C000)
$t = ($val - 50) / 50;
$r = int (255 * (1 - $t)); # 255 → 0
$g = int (140 + (192 - 140) * $t); # 140 → 192 (z.B. C0)
$b = 0;
}
-
+
($r, $g, $b) = _reduceSaturation ($r, $g, $b, $satiety); # optional Sättigung bei gesetztem satiety
-
+
if ($opacity) { # Alpha-Wert: 1 = voll deckend, 0 = komplett transparent
return sprintf ("#%02X%02X%02X%02X", $r, $g, $b, int ($opacity * 255 + 0.5));
- }
-
+ }
+
return sprintf ("#%02X%02X%02X", $r, $g, $b);
}
@@ -24416,10 +24495,10 @@ return ($swoff, $info, $err);
}
################################################################
-# Funktion liefert "1", wenn sich die Anlage im
+# Funktion liefert "1", wenn sich die Anlage im
# Status 'Abregelung' befindet. (plantControl->reductionState)
-#
-# valCurrent: reductionState -> ::
+#
+# valCurrent: reductionState -> ::
# $info - den Info-Status
# $err - einen Error-Status
#
@@ -24430,11 +24509,11 @@ sub isReductionState {
my $info = q{};
my $rdcstate = 0;
- my $rdcs = CurrentVal ($name, 'reductionState', '');
+ my $rdcs = CurrentVal ($name, 'reductionState', '');
return ($rdcstate, 'reductionState not set', '') if(!$rdcs);
-
+
my ($rdcdev, $rdcrd, $rdcrgx) = split ":", $rdcs; # $rdcdev / $rdcrd -> Device / Reading zur Lieferung des Abregelungsstatus
-
+
my ($err) = isDeviceValid ( { name => $name,
obj => $rdcdev,
method => 'string',
@@ -24893,7 +24972,7 @@ sub isWeatherDevValid {
my $fcname = AttrVal ($hash->{NAME}, $wattr, ''); # Weather Forecast Device/API
return if(!$fcname);
- if (!$defs{$fcname}) { # kein Device -> API genutzt?
+ if (!$defs{$fcname}) { # kein Device -> API genutzt?
if ($fcname =~ /^OpenMeteo/xs) {
$valid = 1;
$apiu = $fcname;
@@ -24952,7 +25031,7 @@ sub isWeatherAgeExceeded {
if (!$fcname) {
return (qq{No DWD device is defined in attribute "setupWeatherDev$step"}, $resh);
}
-
+
if (!$valid) {
return (qq{The DWD device "$fcname" doesn't exist}, $resh);
}
@@ -25083,7 +25162,7 @@ sub lastConsumerSwitchtime {
my ($err, $cname, $dswname) = getCDnames ($hash, $c); # Consumer und Switch Device Name
if ($err) {
- Log3 ($name, 1, qq{$name - ERROR - The last switching time can't be identified due to the device '$dswname' is invalid.
+ Log3 ($name, 1, qq{$name - ERROR - The last switching time can't be identified due to the device '$dswname' is invalid.
Please check device names in consumer "$c" attribute}) if(askLogtime ($name, $err));
return;
}
@@ -25125,7 +25204,7 @@ return $ps;
################################################################
sub strlength {
my $string = shift // return 0;
-
+
my $decoded = decode ('UTF-8', $string);
return length ($decoded);
@@ -25582,16 +25661,16 @@ sub userExit {
$uefn =~ s/^\s+|\s+$//g; # nur Anfang und Ende trimmen
my $result;
- if ($uefn =~ /^\{.*\}$/s) { # unnamed Funktion direkt in ctrlUserExitFn mit {...}
+ if ($uefn =~ /^\{.*\}$/s) { # unnamed Funktion direkt in ctrlUserExitFn mit {...}
my $coderef = eval "sub $uefn;";
-
+
if ($@) {
Log3 ($name, 1, "$name - ERROR compiling userExitFn: $@");
- }
+ }
elsif (ref $coderef eq 'CODE') {
eval { $result = $coderef->() };
Log3 ($name, 1, "$name - ERROR executing userExitFn: $@") if($@);
- }
+ }
else {
Log3 ($name, 1, "$name - no valid function block in ctrlUserExitFn");
}
@@ -25874,38 +25953,9 @@ return $def;
}
###################################################################################################
-# Wert des current-Hash zurückliefern
+# Wert des Current-Speichers auslesen
# Usage:
# CurrentVal ($hash or $name, $key, $def)
-#
-# $key: aiinitstate - Initialisierungsstatus der KI
-# aitrainstate - Traisningsstatus der KI
-# aiaddistate - Add Instanz Status der KI
-# ctrunning - aktueller Ausführungsstatus des Central Task
-# dwdRad1hAge - Alter des Rad1h Wertes als Datumstring
-# dwdRad1hAgeTS - Alter des Rad1h Wertes als Unix Timestamp
-# genslidereg - Schieberegister PV Erzeugung (Array)
-# h4fcslidereg - Schieberegister 4h PV Forecast (Array)
-# surplusslidereg - Schieberegister PV Überschuß (Array)
-# moonPhaseI - aktuelle Mondphase (1 .. 8)
-# batsocslidereg - Schieberegister Batterie SOC (Array)
-# consumption - aktueller Verbrauch (W)
-# consumerdevs - alle registrierten Consumerdevices (Array)
-# consumerCollected - Statusbit Consumer Attr gesammelt und ausgewertet
-# gridconsumption - aktueller Netzbezug
-# temp - aktuelle Außentemperatur
-# surplus - aktueller PV Überschuß
-# tomorrowconsumption - Verbrauch des kommenden Tages
-# allstringspeak - Peakleistung aller Strings nach temperaturabhängiger Korrektur
-# allstringscount - aktuelle Anzahl der Anlagenstrings
-# tomorrowconsumption - erwarteter Gesamtverbrauch am morgigen Tag
-# sunriseToday - Sonnenaufgang heute
-# sunriseTodayTs - Sonnenaufgang heute Unix Timestamp
-# sunsetToday - Sonnenuntergang heute
-# sunsetTodayTs - Sonnenuntergang heute Unix Timestamp
-#
-# $def: Defaultwert
-#
###################################################################################################
sub CurrentVal {
my $name = shift;
@@ -26327,8 +26377,131 @@ sub StatusAPIVal {
return $def;
}
+################################################################
+# Glättung des übergebenen Wertes $newval
+# $chan - ID der Glättungsgruppe
+# SM_new als Key/Value-Liste übergeben
+################################################################
+sub smoothValue {
+ my $paref = shift;
+
+ my $name = $paref->{name};
+ my $chan = $paref->{chan};
+ my $rdg = $paref->{rdg};
+ my $newval = $paref->{newval} // return;
+ my $deadband = $paref->{deadband} // OTPDEADBAND;
+ my $alpha = $paref->{alpha} // OTPALPHA;
+
+ my $hash = $defs{$name};
+ my $vold = ReadingsNum ($name, $rdg, 0);
+ my $changed = 0;
+
+ $data{$name}{current}{smoother}{$chan}{$rdg}{OLD} = $vold;
+ $data{$name}{current}{smoother}{$chan}{$rdg}{NEWVAL} = $newval;
+ $data{$name}{current}{smoother}{$chan}{$rdg}{ALPHA} = $alpha;
+ $data{$name}{current}{smoother}{$chan}{$rdg}{DEADBAND} = $deadband;
+
+ unless ($data{$name}{current}{smoother}{$chan}{$rdg}{OBJ}) {
+ $data{$name}{current}{smoother}{$chan}{$rdg}{OBJ} = FHEM::SolarForecast::Smoother->SM_new ( initial => $vold,
+ deadband => $deadband,
+ alpha => $alpha
+ );
+ }
+
+ my $s = $data{$name}{current}{smoother}{$chan}{$rdg}{OBJ};
+
+ unless (blessed ($s)) {
+ Log3 ($name, 1, "$name - ERROR - Wrong Smoother class: ".ref($s));
+
+ $changed = 1 if($newval != $vold);
+ return ($newval, $changed);
+ }
+
+ my $smoothed = $s->SM_update ($newval);
+ $changed = 1 if($smoothed != $vold);
+
+ $data{$name}{current}{smoother}{$chan}{$rdg}{SMOOTHED} = $smoothed;
+ $data{$name}{current}{smoother}{$chan}{$rdg}{CHANGED} = $changed;
+
+return ($smoothed, $changed);
+}
+
+
+#####################################################################################################################
+# Smoother - Glättungsfilter
+# Kleine Änderungen (<= X) werden ignoriert und nur bei größeren Änderungen
+# auf einen neuen Wert reagiert. Der Übergang kann glatt
+# (anstatt eines plötzlichen Sprungs) erfolgen.
+#
+# deadband: Schwellwert X; Änderungen ≤ X werden nicht als neuer Zielwert übernommen.
+# step-smoothing: Wenn Änderung > X, kann der aktuelle Wert entweder sofort auf den neuen gesetzt werden oder
+# schrittweise (mit Faktor alpha) Richtung Ziel gleiten.
+
+# konfigurierbar: X und Alpha sind Parameter.
+#####################################################################################################################
+
+package FHEM::SolarForecast::Smoother;
+
+sub SM_new {
+ my ($class, %opts) = @_;
+ my $self = {
+ value => $opts{initial} // 0, # aktueller (ausgegebener) Wert
+ deadband => $opts{deadband} // 0.5, # X: minimale Änderungsamplitude (Schwellenwert für Ergebnisanpassung)
+ alpha => defined $opts{alpha} ? $opts{alpha} : 1.0, # 1.0 = sofortiger Sprung; <1 = gleitend
+ };
+
+ bless $self, $class;
+
+return $self;
+}
+
+sub SM_update { # update mit neuem Messwert; gibt den geglätteten Wert zurück
+ my ($self, $newval) = @_;
+ return $self->{value} unless defined $newval;
+
+ my $current = $self->{value};
+ my $diff = $newval - $current;
+ my $abs = $diff >= 0 ? $diff : -$diff;
+
+ if ($abs <= $self->{deadband}) { # innerhalb der deadband: kein Wechsel
+ return $current;
+ }
+
+ if ($self->{alpha} >= 1) { $self->{value} = $newval } # außerhalb deadband: Ziel ist der neue Messwert; gleiten je nach alpha
+ else { $self->{value} = $current + $self->{alpha} * $diff }
+
+return $self->{value};
+}
+
+################################################################################
+# Hilfs-Accessoren
+# Routinen arbeiten auf dem Objekt-Hash (typisches Perl-OO mit blessed Hash):
+# $_[0] ist das Objekt, $_[1] das übergebene Argument.
+#
+#
+# # my $s = $hash->{HELPER}{SMOOTHER}{$chan};
+# unless ($s) {
+# return;
+# }
+# Getter (akt. Wert lesen):
+# my $current = $s->SM_getValue;
+#
+# Setter zur Änderung von Objektwerten:
+# my $dead = 0.5;
+# my $alpha = 1.0;
+# my $value = 222;
+# $s->SM_setDeadband ($dead);
+# $s->SM_setAlpha ($alpha);
+# $s->SM_setValue ($value);
+################################################################################
+sub SM_getValue { $_[0]->{value} } # gibt den aktuellen geglätteten Wert zurück
+sub SM_setValue { $_[0]->{value} = $_[1] } # setzt einen neuen Vergleichswert im Objekt
+sub SM_setDeadband { $_[0]->{deadband} = $_[1] } # setzt den Deadband-Parameter des Objekts
+sub SM_setAlpha { $_[0]->{alpha} = $_[1] } # setzt den Alpha-Parameter des Objekts
+
1;
+
=pod
=item summary Visualization of solar predictions for PV systems and Consumer control
=item summary_DE Visualisierung von solaren Vorhersagen für PV Anlagen und Verbrauchersteuerung
@@ -27512,11 +27685,11 @@ to ensure that the system configuration is correct.
The remaining runtime is not affected by an interrupt!
- The key power specifies the power consumption of the consumer. The key pvshare can be used to specify the desired
+ The key power specifies the power consumption of the consumer. The key pvshare can be used to specify the desired
percentage of PV to cover the power consumption.
Depending on these values, the switching times of the consumer are planned and the cycle of the consumer is started depending on
the sufficient PV surplus at the time of planning.
- If power=0 or pvshare=0 is set, the consumer is switched on as planned, regardless of whether there is sufficient
+ If power=0 or pvshare=0 is set, the consumer is switched on as planned, regardless of whether there is sufficient
PV surplus.
@@ -27697,22 +27870,22 @@ to ensure that the system configuration is correct.
- ctrlBatSocManagementXX lowSoc=<Value> upSoC=<Value> [maxSoC=<Value>] [stepSoC=<Value>] [barrierSoC=<Syntax>]
- [careCycle=<Value>] [lcSlot=<hh:mm>-<hh:mm>] [loadAbort=<SoC1>:<MinPwr>:<SoC2>]
- [safetyMargin=<Value>[:<Value>]] [loadStrategy=<Value>] [loadTarget=<Wert>]
+ ctrlBatSocManagementXX lowSoc=<Value> upSoC=<Value> [maxSoC=<Value>] [stepSoC=<Value>] [barrierSoC=<Syntax>]
+ [careCycle=<Value>] [lcSlot=<hh:mm>-<hh:mm>] [loadAbort=<SoC1>:<MinPwr>:<SoC2>]
+ [safetyMargin=<Value>[:<Value>]] [loadStrategy=<Value>] [loadTarget=<Wert>]
[weightOwnUse=<Wert>]
-
- If a battery device (setupBatteryDevXX) is installed, this attribute activates the battery SoC and charge management
+
+ If a battery device (setupBatteryDevXX) is installed, this attribute activates the battery SoC and charge management
for this battery device.
A set of control readings is generated; the module itself does not interfere with battery control.
The Battery_OptimumTargetSoC_XX reading contains the optimum minimum SoC calculated by the module.
The Battery_ChargeRequest_XX reading is set to '1' if the current SoC has fallen below the minimum SoC.
In this case, the battery should be reloaded, possibly with mains power.
- The reading Battery_ChargeUnrestricted_XX contains the charging release, i.e. whether the battery should be charged at
+ The reading Battery_ChargeUnrestricted_XX contains the charging release, i.e. whether the battery should be charged at
full power without restriction (1), or not at all, or only when the
- feed-in limit (see plantControl->feedinPowerLimit) is exceeded (0).
- If you want to charge the battery continuously throughout the day, Reading
- Battery_ChargeOptTargetPower_XX provides optimized charging power for battery control.
+ feed-in limit (see plantControl->feedinPowerLimit) is exceeded (0).
+ If you want to charge the battery continuously throughout the day, Reading
+ Battery_ChargeOptTargetPower_XX provides optimized charging power for battery control.
The readings can be used to control the SoC (State of Charge) and to control the charging power used for the
battery.
Detailed information on battery SoC and charging management is described in the
@@ -27761,10 +27934,10 @@ to ensure that the system configuration is correct.
| | |
| stepSoC | Optional step size for optimal SoC calculation (Battery_OptimumTargetSoC_XX) in %. |
| | The specification 'stepSoC=0' deactivates the SoC management and sets |
- | | Battery_OptimumTargetSoC_XX to the value 'lowSoC'. |
+ | | Battery_OptimumTargetSoC_XX to the value 'lowSoC'. |
| | Note: The relationship ‘careCycle * stepSoC = 100’ should be observed! |
| | Wert: 0..5, default: 5 |
- | | |
+ | | |
| careCycle | Maximum interval in days between two charge states of at least 'maxSoC' that should not be |
| | exceeded if possible. The specification is optional (default: 20) |
| | Note: The relationship ‘careCycle * stepSoC = 100’ should be observed! |
@@ -27772,25 +27945,28 @@ to ensure that the system configuration is correct.
| lcSlot | A daily time window is defined in which the charging control of the module should be active |
| | for this battery. Outside the time window, the battery charge is released |
| | at full power. The SoC management of the battery is not affected by this. |
- | | Value: <hh:mm>-<hh:mm>, default: all day |
- | | |
+ | | Value: <hh:mm>-<hh:mm>, default: all day |
+ | | |
| loadAbort | Condition for a general charging abort and Unlocking. The abort condition is fulfilled if the |
| | specified SoC1 (%) is reached or exceeded AND the specified charging power |
| | <MinPwr> (W) has been undercut -> Reading Battery_ChargeAbort_XX=1. |
| | If the current SoC falls below the specified SoC2, the Battery_ChargeAbort_XX=0 is set. |
- | | If SoC2 is not specified, SoC2=SoC1. |
- | | |
+ | | If SoC2 is not specified, SoC2=SoC1. |
+ | | |
| loadStrategy | Depending on the selected charging strategy, the battery charge forecast and, if applicable, |
| | the generation of control readings are influenced. The specification is optional. |
- | | For more information on selecting a strategy, see german Wiki. |
- | | Value: loadRelease | optPower | smartPower, default: loadRelease |
- | | |
- | loadTarget | Optional target SoC in % for calculating charge release or optimal charging power. |
- | | The target value is a calculated figure. The actual SoC may be higher or lower than this within |
- | | certain limits, depending on the situation. The higher value from Reading |
- | | Battery_OptimumTargetSoC_XX and 'loadTarget' takes precedence for the calculation. |
- | | Value: 0..100, default: 100 |
- | | |
+ | | For more information on selecting a strategy, see german Wiki. |
+ | | Value: loadRelease | optPower | smartPower, default: loadRelease |
+ | | |
+ | loadTarget | Optional target SoC (%), target time for calculating charge release, and optimal charging power. |
+ | | The specified target SoC must be greater than the value of 'lowSoC'. A higher value in the |
+ | | reading Battery_OptimumTargetSoC_XX takes precedence over the parameter setting. |
+ | | A specified target time is the full hour (1..20) or, as a negative value (-20..-1), the |
+ | | last full hour before sunset minus this value. |
+ | | Syntax: <Target SoC>[:<Target time>] |
+ | | Value range Target SoC: lowSoc..100, default: 100 |
+ | | Value range Target time: -20..20(without leading zero), default: undefined |
+ | | |
| safetyMargin | When calculating the load clearance and optimized load capacity, safety margins are taken |
| | into account in the predicted load requirements. |
| | Deviating from the default, this parameter can be used to specify individual safety margins |
@@ -27811,7 +27987,7 @@ to ensure that the system configuration is correct.
All SoC values are whole numbers in %. The following applies: 'lowSoc' < 'upSoC' < 'maxSoC'.
Example:
- attr <name> ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 lcSlot=11:00-17:30 loadAbort=99:40:90 safetyMargin=30 weightOwnUse=20
+ attr <name> ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 lcSlot=11:00-17:30 loadAbort=99:40:90 safetyMargin=30 weightOwnUse=20 loadTarget=90:-2
@@ -27930,10 +28106,10 @@ to ensure that the system configuration is correct.
| daysUntilBatteryCare_XX | Days until the next battery XX maintenance (reaching the charge 'maxSoC' from attribute ctrlBatSocManagementXX) |
| dummyConsumption | Provides the current household consumption that cannot be attributed to consumers. Also includes power loss components. |
| lastretrieval_time | the last retrieval time of the selected radiation data API |
- | lastretrieval_timestamp | the timestamp of the last retrieval time of the selected radiation data API |
+ | lastretrieval_timestamp | the timestamp of the last retrieval time of the selected radiation data API |
| remainingSurplsHrsMinPwrBat_XX | the remaining number of hours on the current day in which the PV surplus (Wh) is higher than the |
| | calculated hourly integral of the minimum charging power <MinPwr> of battery XX. |
- | | The <MinPwr> is specified in the ctrlBatSocManagementXX->loadAbort attribute. |
+ | | The <MinPwr> is specified in the ctrlBatSocManagementXX->loadAbort attribute. |
| remainingHrsWoChargeRcmdBat_XX | the remaining number of hours without charging recommendation for battery XX on the current day |
| response_message | the last status message of the selected radiation data API |
| runTimeAvgDayConsumer_XX | the average running time (minutes) of consumer "XX" on one day |
@@ -28213,7 +28389,7 @@ to ensure that the system configuration is correct.
Display of any readings, set commands and attributes of the device in the graphic header.
Four values (fields) are displayed per line.
- Values with the units "Wh" or "kWh" are converted according to the setting of the attribute
+ Values with the units "Wh" or "kWh" are converted according to the setting of the attribute
graphicControl->energyUnit.
@@ -28221,7 +28397,7 @@ to ensure that the system configuration is correct.
The input can be entered on multiple lines for a clear structure.
The syntax for inserting elements and defining additional properties is as follows:
-
+
@@ -28245,7 +28421,7 @@ to ensure that the system configuration is correct.
| : | creates a blank space |
| | |
-
+
Example:
@@ -28543,7 +28719,7 @@ to ensure that the system configuration is correct.
| efficiency | Optional specification of the energy storage efficiency in %. This efficiency describes not |
| | only the battery itself, but also the chain of effects, including the inverters involved. |
| | Depending on the type of coupling and other factors, the typical efficiency is between 75 and 90%. |
- | | Value: 0..100 default: 87 |
+ | | Value: 1..100 default: 87 |
| | |
| icon | Icon and/or (only) color of the battery in the bar graph according to the status (optional). |
| | The identifier (e.g. blue), HEX value (e.g. #d9d9d9) or 'dyn' can be specified as the color. |
@@ -28584,13 +28760,13 @@ to ensure that the system configuration is correct.
Example:
attr <name> setupBatteryDev01 BatDummy pin=BatVal:W pout=-pin intotal=BatInTot:Wh outtotal=BatOutTot:Wh cap=BatCap:kWh show=2:bottom icon=measure_battery_50@#262626:@yellow:measure_battery_100@red
- attr <name> setupBatteryDev02 MQTT2_cerboGX_c0619ab34e08_battery
- pin=BatIn:W
+ attr <name> setupBatteryDev02 MQTT2_cerboGX_c0619ab34e08_battery
+ pin=BatIn:W
pout=BatOut:W
pinmax=14402
poutmax=14402
- intotal=BatInTotal:Wh outtotal=BatOutTotal:Wh
- charge=SOC_value cap=InstalledCapacity_Wh:Wh
+ intotal=BatInTotal:Wh outtotal=BatOutTotal:Wh
+ charge=SOC_value cap=InstalledCapacity_Wh:Wh
asynchron=0
show=1
label=below
@@ -29565,7 +29741,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
- reset
Löscht die aus der Drop-Down Liste gewählte Datenquelle, zu der Funktion gehörende Readings oder weitere interne
- Datenstrukturen. Benötigt der gewählte Befehl keine Optionen, wird das Eingabefeld leer gelassen.
+ Datenstrukturen. Benötigt der gewählte Befehl keine Optionen, wird das Eingabefeld leer gelassen.
@@ -30292,7 +30468,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Die verbleibende Laufzeit wird durch einen Interrupt nicht beeinflusst!
- Der Schlüssel power gibt die Leistungsaufnahme des Verbrauchers an. Mit dem Schlüssel pvshare kann der gewünschte
+ Der Schlüssel power gibt die Leistungsaufnahme des Verbrauchers an. Mit dem Schlüssel pvshare kann der gewünschte
prozentuale PV-Anteil zur Deckung der Leistungsaufnahme festgelegt werden.
Abhängig von diesen Werten werden die Schaltzeiten des Verbrauchers geplant und der Zyklus des Verbrauchers in Abhängigkeit
des ausreichenden PV-Überschußes zum Einplanungszeitpunkt gestartet.
@@ -30478,10 +30654,10 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
- ctrlBatSocManagementXX lowSoc=<Wert> upSoC=<Wert> [maxSoC=<Wert>] [stepSoC=<Wert>] [barrierSoC=<Syntax>]
- [careCycle=<Wert>] [lcSlot=<hh:mm>-<hh:mm>] [loadAbort=<SoC1>:<MinPwr>:<SoC2>]
- [safetyMargin=<Wert>[:<Wert>]] [loadStrategy=<Wert>] [loadTarget=<Wert>]
+ [careCycle=<Wert>] [lcSlot=<hh:mm>-<hh:mm>] [loadAbort=<SoC1>:<MinPwr>:<SoC2>]
+ [safetyMargin=<Wert>[:<Wert>]] [loadStrategy=<Wert>] [loadTarget=<Wert>]
[weightOwnUse=<Wert>]
-
+
Sofern ein Batterie Device (setupBatteryDevXX) installiert ist, aktiviert dieses Attribut das Batterie
SoC- und Lade-Management für dieses Batteriegerät.
Es wird ein Satz Steuerreadings erstellt; das Modul greift selbst nicht in die Batteriesteuerung ein.
@@ -30489,14 +30665,14 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Das Reading Battery_ChargeRequest_XX wird auf '1' gesetzt, wenn der aktuelle SoC unter den Mindest-SoC gefallen
ist.
In diesem Fall sollte die Batterie, unter Umständen mit Netzstrom, nachgeladen werden.
- Das Reading Battery_ChargeUnrestricted_XX enthält die Ladefreigabe, d.h. ob die Batterie uneingeschränkt mit voller
- Leistung (1), oder nicht bzw. nur bei Überschreitung des
- Einspeiselimits (siehe plantControl->feedinPowerLimit)
- geladen werden sollte (0). Möchte man die Batterie kontinuierlich über den gesamten Tag aufladen, wird im Reading
- Battery_ChargeOptTargetPower_XX eine optimierte Ladeleistung zur Batteriesteuerung bereitgestellt.
+ Das Reading Battery_ChargeUnrestricted_XX enthält die Ladefreigabe, d.h. ob die Batterie uneingeschränkt mit voller
+ Leistung (1), oder nicht bzw. nur bei Überschreitung des
+ Einspeiselimits (siehe plantControl->feedinPowerLimit)
+ geladen werden sollte (0). Möchte man die Batterie kontinuierlich über den gesamten Tag aufladen, wird im Reading
+ Battery_ChargeOptTargetPower_XX eine optimierte Ladeleistung zur Batteriesteuerung bereitgestellt.
Die Readings können zur Steuerung des SoC (State of Charge) sowie zur Steuerung des verwendeten Ladeleistung
der Batterie verwendet werden.
- Detaillierte Informationen zum Batterie SoC- und Lade-Management sind im
+ Detaillierte Informationen zum Batterie SoC- und Lade-Management sind im
Wiki beschrieben.
@@ -30542,36 +30718,39 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| | |
| stepSoC | Optionale Schrittweite zur optimalen SoC-Berechnung (Battery_OptimumTargetSoC_XX) in %. |
| | Mit der Angabe 'stepSoC=0' wird das SoC-Management deaktiviert und Battery_OptimumTargetSoC_XX |
- | | auf den Wert 'lowSoC' gesetzt. |
+ | | auf den Wert 'lowSoC' gesetzt. |
| | Hinweis: Die Beziehung 'careCycle * stepSoC = 100' sollte eingehalten werden! |
| | Wert: 0..5, default: 5 |
- | | |
+ | | |
| careCycle | maximaler Abstand in Tagen, der zwischen zwei Ladungszuständen von mindestens 'maxSoC' |
| | möglichst nicht überschritten werden soll. Die Angabe ist optional (default: 20) |
| | Hinweis: Die Beziehung 'careCycle * stepSoC = 100' sollte eingehalten werden! |
- | | |
+ | | |
| lcSlot | Es wird ein tägliches Zeitfenster festgelegt, in dem die Ladesteuerung des Moduls für diese |
| | Batterie aktiv sein soll. Außerhalb des Zeitfensters wird die Batterieladung mit voller |
| | Leistung freigegeben. Das SoC-Management der Batterie ist davon nicht betroffen. |
- | | Wert: <hh:mm>-<hh:mm>, default: ganztägig |
- | | |
+ | | Wert: <hh:mm>-<hh:mm>, default: ganztägig |
+ | | |
| loadAbort | Bedingung für einen generellen Ladeabbruch und Wiederfreigabe. Die Abbruchbedingung ist erfüllt, |
| | wenn der angegebene SoC1 (%) erreicht bzw. überschritten ist UND die angegebene |
| | Ladeleistung <MinPwr> (W) unterschritten wurde -> Reading Battery_ChargeAbort_XX=1. |
| | Fällt der aktuelle SoC wieder unter den SoC2, wird Battery_ChargeAbort_XX=0 gesetzt. |
- | | Ist SoC2 nicht angegeben, gilt SoC2=SoC1. |
- | | |
+ | | Ist SoC2 nicht angegeben, gilt SoC2=SoC1. |
+ | | |
| loadStrategy | Abhängig von der gewählten Ladestrategie wird die Prognose der Batterieladung und ggf. die |
| | Generierung der Steuerreadings beeinflusst. Die Angabe ist optional. |
- | | Weitere Informationen zur Auswahl der Strategie siehe Wiki. |
- | | Wert: loadRelease | optPower | smartPower, default: loadRelease |
- | | |
- | loadTarget | Optionaler Ziel-SoC in % für die Berechnung der Ladefreigabe bzw. der optimalen Ladeleistung. |
- | | Der Zielwert ist eine kalkulatorische Rechengröße. Der reale SoC kann situativ in Grenzen |
- | | über- oder unterschritten werden. Der höhere Wert aus Reading Battery_OptimumTargetSoC_XX |
- | | und 'loadTarget' hat für die Berechnung Vorrang. |
- | | Wert: 0..100, default: 100 |
- | | |
+ | | Weitere Informationen zur Auswahl der Strategie siehe Wiki. |
+ | | Wert: loadRelease | optPower | smartPower, default: loadRelease |
+ | | |
+ | loadTarget | Optionaler Ziel-SoC (%), Zielzeit zur Berechnung der Ladefreigabe und optimalen Ladeleistung. |
+ | | Der angegebene Ziel-SoC muß größer als der Wert von 'lowSoC' sein. Ein höherer Wert im Reading |
+ | | Battery_OptimumTargetSoC_XX gegenüber der Parametervorgabe hat Vorrang. |
+ | | Eine angegebene Zielzeit ist die volle Stunde (1..20) oder als negativer Wert (-20..-1) die |
+ | | letzte volle Stunde vor dem Sonnenuntergang abzüglich diesem Wert. |
+ | | Syntax: <Ziel-SoC>[:<Zielzeit>] |
+ | | Wertebereich Ziel-SoC: lowSoc..100, default: 100 |
+ | | Wertebereich Zielzeit: -20..20 (ohne führende Null), default: undefiniert |
+ | | |
| safetyMargin | Bei der Berechnung der Ladefreigabe und optimierten Ladeleistung werden Sicherheitszuschläge |
| | auf den prognostizierten Ladungsbedarf berücksichtigt. |
| | Abweichend vom Default können mit diesem Parameter individuelle Sicherheitszuschläge getrennt |
@@ -30592,7 +30771,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Alle SoC-Werte sind ganze Zahlen in %. Dabei gilt: 'lowSoc' < 'upSoC' < 'maxSoC'.
Beispiel:
- attr <name> ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 lcSlot=11:00-17:30 loadAbort=99:40:90 safetyMargin=30 weightOwnUse=20
+ attr <name> ctrlBatSocManagement01 lowSoc=10 upSoC=50 maxSoC=99 careCycle=25 lcSlot=11:00-17:30 loadAbort=99:40:90 safetyMargin=30 weightOwnUse=20 loadTarget=90:-2
@@ -31002,7 +31181,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Die Eingabe kann für eine übersichtliche Struktur mehrzeilig erfolgen.
Die Syntax um Elemente einzufügen sowie weitere Eigenschaften zu definieren sind:
-
+
@@ -31026,8 +31205,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| : | erzeugt ein Leerfeld |
| | |
-
-
+
+
Beispiel:
@@ -31060,7 +31239,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
-
+
- graphicHeaderOwnspecValForm
@@ -31321,7 +31500,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| efficiency | Optionale Angabe des Wirkungsgrades der Energiespeicherung in %. Dieser Wirkungsgrad beschreibt nicht |
| | nur die Batterie selbst, sondern die Wirkkette inkl. der betroffenen Wechselrichter. |
| | Je nach Koppelart und anderen Faktoren liegt der typische Wirkungsgrad zwischen 75 - 90 %. |
- | | Wert: 0..100 default: 87 |
+ | | Wert: 1..100 default: 87 |
| | |
| icon | Icon und/oder (nur) Farbe der Batterie in der Balkengrafik entsprechend des Status (optional). |
| | Als Farbe kann der Bezeichner (z.B. blue), HEX-Wert (z.B. #d9d9d9) oder 'dyn' angegeben werden. |
@@ -31363,13 +31542,13 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
Beispiel:
attr <name> setupBatteryDev01 BatDummy pin=BatVal:W pout=-pin intotal=BatInTot:Wh outtotal=BatOutTot:Wh cap=BatCap:kWh show=2:bottom icon=measure_battery_50@#262626:@yellow:measure_battery_100@red
- attr <name> setupBatteryDev02 MQTT2_cerboGX_c0619ab34e08_battery
- pin=BatIn:W
+ attr <name> setupBatteryDev02 MQTT2_cerboGX_c0619ab34e08_battery
+ pin=BatIn:W
pout=BatOut:W
pinmax=14402
poutmax=14402
- intotal=BatInTotal:Wh outtotal=BatOutTotal:Wh
- charge=SOC_value cap=InstalledCapacity_Wh:Wh
+ intotal=BatInTotal:Wh outtotal=BatOutTotal:Wh
+ charge=SOC_value cap=InstalledCapacity_Wh:Wh
asynchron=0
show=1
label=below