2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-08 07:24:21 +00:00

76_SolarForecast: contrib 1.37.0

git-svn-id: https://svn.fhem.de/fhem/trunk@29243 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2024-10-15 20:06:39 +00:00
parent 8dccf44c9e
commit c4ff0756ca

View File

@ -156,6 +156,7 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"1.37.0" => "15.10.2024 attr setupInverterDevXX up to 03 inverters with accorded strings, setupInverterDevXX: keys strings and feed ",
"1.36.1" => "14.10.2024 _flowGraphic: consumer distance modified by kask, Coloring of icons corrected when creating 0 ", "1.36.1" => "14.10.2024 _flowGraphic: consumer distance modified by kask, Coloring of icons corrected when creating 0 ",
"1.36.0" => "13.10.2024 new Getter valInverter, valStrings and valProducer, preparation for multiple inverters ". "1.36.0" => "13.10.2024 new Getter valInverter, valStrings and valProducer, preparation for multiple inverters ".
"rename setupInverterDev to setupInverterDev01, new attr affectConsForecastLastDays ". "rename setupInverterDev to setupInverterDev01, new attr affectConsForecastLastDays ".
@ -439,7 +440,7 @@ my $tempbasedef = 25;
my $maxconsumer = 16; # maximale Anzahl der möglichen Consumer (Attribut) my $maxconsumer = 16; # maximale Anzahl der möglichen Consumer (Attribut)
my $maxproducer = 3; # maximale Anzahl der möglichen anderen Produzenten (Attribut) my $maxproducer = 3; # maximale Anzahl der möglichen anderen Produzenten (Attribut)
my $maxinverter = 1; # maximale Anzahl der möglichen Inverter my $maxinverter = 3; # maximale Anzahl der möglichen Inverter
my $epiecMaxCycles = 10; # Anzahl Einschaltzyklen (Consumer) für verbraucherspezifische Energiestück Ermittlung my $epiecMaxCycles = 10; # Anzahl Einschaltzyklen (Consumer) für verbraucherspezifische Energiestück Ermittlung
my @ctypes = qw(dishwasher dryer washingmachine heater charger other my @ctypes = qw(dishwasher dryer washingmachine heater charger other
@ -565,10 +566,10 @@ my @aconfigs = qw( affect70percentRule affectBatteryPreferredCharge affectConsFo
setupRoofTops setupRoofTops
); );
for my $cinit (1..$maxconsumer) { for my $cn (1..$maxconsumer) {
$cinit = sprintf "%02d", $cinit; $cn = sprintf "%02d", $cn;
push @aconfigs, "consumer${cinit}"; # Anlagenkonfiguration: add Consumer Attribute push @aconfigs, "consumer${cn}"; # Anlagenkonfiguration: add Consumer Attribute
push @dd, "consumerSwitching${cinit}"; # ctrlDebug: add specific Consumer push @dd, "consumerSwitching${cn}"; # ctrlDebug: add specific Consumer
} }
for my $in (1..$maxinverter) { for my $in (1..$maxinverter) {
@ -576,9 +577,9 @@ for my $in (1..$maxinverter) {
push @aconfigs, "setupInverterDev${in}"; # Anlagenkonfiguration: add Inverter Attribute push @aconfigs, "setupInverterDev${in}"; # Anlagenkonfiguration: add Inverter Attribute
} }
for my $prn (1..$maxproducer) { for my $pn (1..$maxproducer) {
$prn = sprintf "%02d", $prn; $pn = sprintf "%02d", $pn;
push @aconfigs, "setupOtherProducer${prn}"; # Anlagenkonfiguration: add Producer Attribute push @aconfigs, "setupOtherProducer${pn}"; # Anlagenkonfiguration: add Producer Attribute
} }
my $allwidgets = 'icon|sortable|uzsu|knob|noArg|time|text|slider|multiple|select|bitfield|widgetList|colorpicker'; my $allwidgets = 'icon|sortable|uzsu|knob|noArg|time|text|slider|multiple|select|bitfield|widgetList|colorpicker';
@ -5796,17 +5797,36 @@ sub _attrInverterDev { ## no critic "not used"
my ($err, $indev, $h) = isDeviceValid ( { name => $name, obj => $aVal, method => 'string' } ); my ($err, $indev, $h) = isDeviceValid ( { name => $name, obj => $aVal, method => 'string' } );
return $err if($err); return $err if($err);
if ($in ne '01' && !AttrVal ($name, 'setupInverterDev01', '')) {
return qq{Set the first Inverter device with attribute 'setupInverterDev01'};
}
if (!$h->{pv} || !$h->{etotal}) { if (!$h->{pv} || !$h->{etotal}) {
return qq{The syntax of '$aName' is not correct. Please consider the commandref.}; return qq{The syntax of '$aName' is not valid. Please consider the commandref.};
} }
if ($h->{capacity} && !isNumeric($h->{capacity})) { if ($h->{capacity} && !isNumeric($h->{capacity})) {
return qq{The syntax of key 'capacity' is not correct. Please consider the commandref.}; return qq{The syntax of key 'capacity' is not valid. Please consider the commandref.};
}
if ($h->{feed} && $h->{feed} !~ /^grid$/xs) {
return qq{The value of key 'feed' is not valid. Please consider the commandref.};
}
if ($h->{strings}) {
for my $s (split ',', $h->{strings}) {
if (!grep /^$s$/, keys %{$data{$type}{$name}{strings}}) {
return qq{The string '$s' is not a valid string name defined in attribute 'setupInverterStrings'.};
}
}
} }
$data{$type}{$name}{circular}{99}{attrInvChangedTs} = int time; $data{$type}{$name}{circular}{99}{attrInvChangedTs} = int time;
delete $data{$type}{$name}{inverters}{$in}{invertercap}; delete $data{$type}{$name}{inverters}{$in}{invertercap};
delete $data{$type}{$name}{inverters}{$in}{iicon}; delete $data{$type}{$name}{inverters}{$in}{iicon};
delete $data{$type}{$name}{inverters}{$in}{istrings};
delete $data{$type}{$name}{inverters}{$in}{ifeed};
} }
elsif ($paref->{cmd} eq 'del') { elsif ($paref->{cmd} eq 'del') {
for my $k (keys %{$data{$type}{$name}{inverters}}) { for my $k (keys %{$data{$type}{$name}{inverters}}) {
@ -6910,14 +6930,14 @@ sub centralTask {
readingsDelete ($hash, 'AllPVforecastsToEvent'); readingsDelete ($hash, 'AllPVforecastsToEvent');
_getRoofTopData ($centpars); # Strahlungswerte/Forecast-Werte in solcastapi-Hash erstellen _getRoofTopData ($centpars); # Strahlungswerte/Forecast-Werte in solcastapi-Hash erstellen
_transferInverterValues ($centpars); # WR Werte übertragen
_transferAPIRadiationValues ($centpars); # Raw Erzeugungswerte aus solcastapi-Hash übertragen und Forecast mit/ohne Korrektur erstellen _transferAPIRadiationValues ($centpars); # Raw Erzeugungswerte aus solcastapi-Hash übertragen und Forecast mit/ohne Korrektur erstellen
_calcMaxEstimateToday ($centpars); # heutigen Max PV Estimate & dessen Tageszeit ermitteln _calcMaxEstimateToday ($centpars); # heutigen Max PV Estimate & dessen Tageszeit ermitteln
_transferInverterValues ($centpars); # WR Werte übertragen #_transferInverterValues ($centpars); # WR Werte übertragen
_transferProducerValues ($centpars); # Werte anderer Erzeuger übertragen _transferProducerValues ($centpars); # Werte anderer Erzeuger übertragen
_transferMeterValues ($centpars); # Energy Meter auswerten _transferMeterValues ($centpars); # Energy Meter auswerten
_transferBatteryValues ($centpars); # Batteriewerte einsammeln _transferBatteryValues ($centpars); # Batteriewerte einsammeln
_batSocTarget ($centpars); # Batterie Optimum Ziel SOC berechnen _batSocTarget ($centpars); # Batterie Optimum Ziel SOC berechnen
#_createSummaries ($centpars); # Zusammenfassungen erstellen
_manageConsumerData ($centpars); # Consumer Daten sammeln und Zeiten planen _manageConsumerData ($centpars); # Consumer Daten sammeln und Zeiten planen
_estConsumptionForecast ($centpars); # Verbrauchsprognose erstellen _estConsumptionForecast ($centpars); # Verbrauchsprognose erstellen
_evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren _evaluateThresholds ($centpars); # Schwellenwerte bewerten und signalisieren
@ -7584,7 +7604,7 @@ sub __deletePvCorffReadings {
($pcf) = split " / ", $pcf if($pcf =~ /\s\/\s/xs); ($pcf) = split " / ", $pcf if($pcf =~ /\s\/\s/xs);
if ($pcf !~ /manual/xs) { # manuell gesetzte pcf-Readings nicht löschen if ($pcf !~ /manual/xs) { # manuell gesetzte pcf-Readings nicht löschen
deleteReadingspec ($hash, "pvCorrectionFactor_${n}.*"); readingsDelete ($hash, "pvCorrectionFactor_${n}"); # V 1.37.0
} }
else { else {
readingsSingleUpdate ($hash, "pvCorrectionFactor_${n}", $pcf, 0); readingsSingleUpdate ($hash, "pvCorrectionFactor_${n}", $pcf, 0);
@ -8201,8 +8221,8 @@ sub __calcPVestimates {
my $fd = $paref->{fd}; my $fd = $paref->{fd};
my $num = $paref->{num}; my $num = $paref->{num};
my $debug = $paref->{debug}; my $debug = $paref->{debug};
my $hash = $defs{$name};
my $hash = $defs{$name};
my $reld = $fd == 0 ? "today" : $fd == 1 ? "tomorrow" : "unknown"; my $reld = $fd == 0 ? "today" : $fd == 1 ? "tomorrow" : "unknown";
my $rr1c = NexthoursVal ($hash, "NextHour".sprintf ("%02d",$num), "rr1c", 0); # Gesamtniederschlag während der letzten Stunde kg/m2 my $rr1c = NexthoursVal ($hash, "NextHour".sprintf ("%02d",$num), "rr1c", 0); # Gesamtniederschlag während der letzten Stunde kg/m2
my $wcc = NexthoursVal ($hash, "NextHour".sprintf ("%02d",$num), "wcc", 0); # effektive Wolkendecke nächste Stunde X my $wcc = NexthoursVal ($hash, "NextHour".sprintf ("%02d",$num), "wcc", 0); # effektive Wolkendecke nächste Stunde X
@ -8237,6 +8257,23 @@ sub __calcPVestimates {
my $est = SolCastAPIVal ($hash, $string, $wantdt, 'pv_estimate50', 0); my $est = SolCastAPIVal ($hash, $string, $wantdt, 'pv_estimate50', 0);
my $pv = sprintf "%.1f", ($est * $hc); # Korrekturfaktor anwenden my $pv = sprintf "%.1f", ($est * $hc); # Korrekturfaktor anwenden
my $invcap = 0;
for my $in (keys %{$data{$type}{$name}{inverters}}) {
my $istrings = InverterVal ($hash, $in, 'istrings', ''); # dem Inverter zugeordnete Strings
next if(!grep /^$string$/, (split ',', $istrings));
$invcap = InverterVal ($hash, $in, 'invertercap', 0); # Max. Leistung des Inverters
last;
}
if ($invcap && $pv > $invcap) {
$pv = $invcap; # PV Vorhersage auf WR Kapazität begrenzen
debugLog ($paref, "radiationProcess", "PV forecast start time $wantdt limited to $pv Wh due to inverter capacity");
}
if ($debug =~ /radiationProcess/xs) { if ($debug =~ /radiationProcess/xs) {
$lh = { # Log-Hash zur Ausgabe $lh = { # Log-Hash zur Ausgabe
"String Peak" => $peak. " W", "String Peak" => $peak. " W",
@ -8264,22 +8301,17 @@ sub __calcPVestimates {
} }
$data{$type}{$name}{current}{allstringspeak} = $peaksum; # temperaturbedingte Korrektur der installierten Peakleistung in W $data{$type}{$name}{current}{allstringspeak} = $peaksum; # temperaturbedingte Korrektur der installierten Peakleistung in W
$pvsum = $peaksum if($peaksum && $pvsum > $peaksum); # Vorhersage nicht größer als die Summe aller PV-Strings Peak $pvsum = $peaksum if($peaksum && $pvsum > $peaksum); # Vorhersage nicht größer als die Summe aller PV-Strings Peak
my $invcap = InverterVal ($hash, '01', 'invertercap', 0); # Max. Leistung des Invertrs
if ($invcap && $pvsum > $invcap) {
$pvsum = $invcap; # PV Vorhersage auf WR Kapazität begrenzen
debugLog ($paref, "radiationProcess", "PV forecast start time $wantdt limited to $pvsum Watt due to inverter capacity");
}
my $logao = qq{}; my $logao = qq{};
$paref->{pvsum} = $pvsum; $paref->{pvsum} = $pvsum;
$paref->{peaksum} = $peaksum; $paref->{peaksum} = $peaksum;
($pvsum, $logao) = ___70percentRule ($paref); ($pvsum, $logao) = ___70percentRule ($paref);
delete $paref->{peaksum};
delete $paref->{pvsum};
if ($debug =~ /radiationProcess/xs) { if ($debug =~ /radiationProcess/xs) {
$lh = { # Log-Hash zur Ausgabe $lh = { # Log-Hash zur Ausgabe
"Starttime" => $wantdt, "Starttime" => $wantdt,
@ -8532,19 +8564,23 @@ sub _transferInverterValues {
$warn = ' (WARNING invalid real PV occured - see Logfile)'; $warn = ' (WARNING invalid real PV occured - see Logfile)';
} }
my $feed = $h->{feed} // 'default';
$data{$type}{$name}{inverters}{$in}{igeneration} = $pv; # Hilfshash Wert current generation, Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251 $data{$type}{$name}{inverters}{$in}{igeneration} = $pv; # Hilfshash Wert current generation, Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251
$data{$type}{$name}{inverters}{$in}{ietotal} = $etotal; # aktuellen etotal des WR speichern $data{$type}{$name}{inverters}{$in}{ietotal} = $etotal; # aktuellen etotal des WR speichern
$data{$type}{$name}{inverters}{$in}{iname} = $indev; # Name des Inverterdevices $data{$type}{$name}{inverters}{$in}{iname} = $indev; # Name des Inverterdevices
$data{$type}{$name}{inverters}{$in}{ialias} = AttrVal ($indev, 'alias', $indev); # Alias Inverter $data{$type}{$name}{inverters}{$in}{ialias} = AttrVal ($indev, 'alias', $indev); # Alias Inverter
$data{$type}{$name}{inverters}{$in}{invertercap} = $h->{capacity} if(defined $h->{capacity}); # optionale Angabe max. WR-Leistung $data{$type}{$name}{inverters}{$in}{invertercap} = $h->{capacity} if(defined $h->{capacity}); # optionale Angabe max. WR-Leistung
$data{$type}{$name}{inverters}{$in}{iicon} = $h->{icon} if($h->{icon}); # Icon des Inverters $data{$type}{$name}{inverters}{$in}{iicon} = $h->{icon} if($h->{icon}); # Icon des Inverters
$data{$type}{$name}{inverters}{$in}{istrings} = $h->{strings} if($h->{strings}); # dem Inverter zugeordnete Strings
$data{$type}{$name}{inverters}{$in}{ifeed} = $feed; # Eigenschaften der Energielieferung
$pvsum += $pv; $pvsum += $pv;
$ethishoursum += $ethishour; $ethishoursum += $ethishour;
writeToHistory ( { paref => $paref, key => 'pvrl'.$in, val => $ethishour, hour => $nhour } ); writeToHistory ( { paref => $paref, key => 'pvrl'.$in, val => $ethishour, hour => $nhour } );
debugLog ($paref, "collectData", "collect Inverter $in data - device: $indev =>"); debugLog ($paref, "collectData", "collect Inverter $in data - device: $indev, delivery: $feed =>");
debugLog ($paref, "collectData", "pv: $pv W, etotal: $etotal Wh"); debugLog ($paref, "collectData", "pv: $pv W, etotal: $etotal Wh");
} }
@ -8615,6 +8651,7 @@ sub _transferProducerValues {
$data{$type}{$name}{producers}{$pn}{pname} = $prdev; # Name des Producerdevices $data{$type}{$name}{producers}{$pn}{pname} = $prdev; # Name des Producerdevices
$data{$type}{$name}{producers}{$pn}{palias} = AttrVal ($prdev, 'alias', $prdev); # Alias Producer $data{$type}{$name}{producers}{$pn}{palias} = AttrVal ($prdev, 'alias', $prdev); # Alias Producer
$data{$type}{$name}{producers}{$pn}{picon} = $h->{icon} if($h->{icon}); # Icon des Producers $data{$type}{$name}{producers}{$pn}{picon} = $h->{icon} if($h->{icon}); # Icon des Producers
$data{$type}{$name}{producers}{$pn}{pfeed} = 'default'; # Eigenschaften der Energielieferung
if ($ethishour < 0) { if ($ethishour < 0) {
$ethishour = 0; $ethishour = 0;
@ -9297,30 +9334,34 @@ sub _createSummaries {
my $batout = CurrentVal ($hash, 'powerbatout', 0); # aktuelle Batterieentladung my $batout = CurrentVal ($hash, 'powerbatout', 0); # aktuelle Batterieentladung
my $pvgen = 0; my $pvgen = 0;
my $pv2grid = 0; # PV-Erzeugung zu Grid-only
for my $in (1..$maxinverter) { # Summe alle Inverter for my $in (1..$maxinverter) { # Summe alle Inverter
$in = sprintf "%02d", $in; $in = sprintf "%02d", $in;
$pvgen += InverterVal ($hash, $in, 'igeneration', 0); my $pvi = InverterVal ($hash, $in, 'igeneration', 0);
my $feed = InverterVal ($hash, $in, 'ifeed', '');
$pvgen += $pvi;
$pv2grid += $pvi if($feed eq 'grid');
} }
my $othprod = 0; # Summe Otherproducer my $othprod = 0; # Summe Otherproducer
for my $pn (1..$maxproducer) { # V1.32.0 : Erzeugung sonstiger Producer (01..03) hinzufügen for my $pn (1..$maxproducer) { # Erzeugung sonstiger Producer hinzufügen
$pn = sprintf "%02d", $pn; $pn = sprintf "%02d", $pn;
$othprod += ProducerVal ($hash, $pn, 'pgeneration', 0); $othprod += ProducerVal ($hash, $pn, 'pgeneration', 0);
} }
my $consumption = int ($pvgen + $othprod - $gfeedin + $gcon - $batin + $batout); my $consumption = int ($pvgen - $pv2grid + $othprod - $gfeedin + $gcon - $batin + $batout); # ohne PV2Grid
my $selfconsumption = int ($pvgen - $gfeedin - $batin); my $selfconsumption = int ($pvgen - $pv2grid - $gfeedin - $batin);
$selfconsumption = $selfconsumption < 0 ? 0 : $selfconsumption; $selfconsumption = $selfconsumption < 0 ? 0 : $selfconsumption;
my $surplus = int ($pvgen + $othprod - $consumption); # aktueller Überschuß my $surplus = int ($pvgen - $pv2grid + $othprod - $consumption); # aktueller Überschuß
$surplus = 0 if($surplus < 0); # wegen Vergleich nompower vs. surplus $surplus = 0 if($surplus < 0); # wegen Vergleich nompower vs. surplus
my $selfconsumptionrate = 0; my $selfconsumptionrate = 0;
my $autarkyrate = 0; my $autarkyrate = 0;
my $divi = $selfconsumption + $batout + $gcon; my $divi = $selfconsumption + $batout + $gcon;
$selfconsumptionrate = sprintf "%.0f", $selfconsumption / $pvgen * 100 if($pvgen * 1 > 0); $selfconsumptionrate = sprintf "%.0f", ($selfconsumption / $pvgen * 100) if($pvgen * 1 > 0);
$autarkyrate = sprintf "%.0f", ($selfconsumption + $batout) / $divi * 100 if($divi); # vermeide Illegal division by zero $autarkyrate = sprintf "%.0f", ($selfconsumption + $batout) / $divi * 100 if($divi); # vermeide Illegal division by zero
$data{$type}{$name}{current}{consumption} = $consumption; $data{$type}{$name}{current}{consumption} = $consumption;
@ -11570,6 +11611,8 @@ sub __calcNewFactor {
$data{$type}{$name}{circular}{sprintf("%02d",$h)}{quality}{$crang} = $qual; $data{$type}{$name}{circular}{sprintf("%02d",$h)}{quality}{$crang} = $qual;
} }
$oldfac = sprintf "%.2f", $oldfac;
return ($oldfac, $factor, $dnum); return ($oldfac, $factor, $dnum);
} }
@ -12206,7 +12249,7 @@ sub _checkSetupNotComplete {
########################################################################################## ##########################################################################################
my $is = AttrVal ($name, 'setupInverterStrings', undef); # String Konfig my $strings = AttrVal ($name, 'setupInverterStrings', undef); # String Konfig
my $wedev = AttrVal ($name, 'setupWeatherDev1', undef); # Device Vorhersage Wetterdaten (Bewölkung etc.) my $wedev = AttrVal ($name, 'setupWeatherDev1', undef); # Device Vorhersage Wetterdaten (Bewölkung etc.)
my $radev = AttrVal ($name, 'setupRadiationAPI', undef); # Device Strahlungsdaten Vorhersage my $radev = AttrVal ($name, 'setupRadiationAPI', undef); # Device Strahlungsdaten Vorhersage
my $indev = AttrVal ($name, 'setupInverterDev01', undef); # Inverter Device my $indev = AttrVal ($name, 'setupInverterDev01', undef); # Inverter Device
@ -12249,7 +12292,7 @@ sub _checkSetupNotComplete {
my $chkicon = "<a onClick=$cmdplchk>$img</a>"; my $chkicon = "<a onClick=$cmdplchk>$img</a>";
my $chktitle = $htitles{plchk}{$lang}; my $chktitle = $htitles{plchk}{$lang};
if (!$is || !$wedev || !$radev || !$indev || !$medev || !$peaks || if (!$strings || !$wedev || !$radev || !$indev || !$medev || !$peaks ||
(isSolCastUsed ($hash) ? (!$rip || !$mrt) : isVictronKiUsed ($hash) ? !$vrmcr : (!$maz || !$mdec )) || (isSolCastUsed ($hash) ? (!$rip || !$mrt) : isVictronKiUsed ($hash) ? !$vrmcr : (!$maz || !$mdec )) ||
(isForecastSolarUsed ($hash) ? !$coset : '') || (isForecastSolarUsed ($hash) ? !$coset : '') ||
(isOpenMeteoUsed ($hash) ? !$coset : '') || (isOpenMeteoUsed ($hash) ? !$coset : '') ||
@ -12262,7 +12305,7 @@ sub _checkSetupNotComplete {
if (!$wedev) { ## no critic 'Cascading' if (!$wedev) { ## no critic 'Cascading'
$ret .= $hqtxt{cfd}{$lang}; $ret .= $hqtxt{cfd}{$lang};
} }
elsif (!$is) { elsif (!$strings) {
$ret .= $hqtxt{ist}{$lang}; $ret .= $hqtxt{ist}{$lang};
} }
elsif (!$peaks) { elsif (!$peaks) {
@ -14099,8 +14142,8 @@ sub _flowGraphic {
my $style = 'width:98%; height:'.$flowgsize.'px;'; my $style = 'width:98%; height:'.$flowgsize.'px;';
my $animation = $flowgani ? '@keyframes dash { to { stroke-dashoffset: 0; } }' : ''; # Animation Ja/Nein my $animation = $flowgani ? '@keyframes dash { to { stroke-dashoffset: 0; } }' : ''; # Animation Ja/Nein
my $cgc = ReadingsNum ($name, 'Current_GridConsumption', 0); my $cgc = ReadingsNum ($name, 'Current_GridConsumption', 0);
my $cgfi = ReadingsNum ($name, 'Current_GridFeedIn', 0); my $cgfi = ReadingsNum ($name, 'Current_GridFeedIn', 0); # Summe zum Grid
my $csc = ReadingsNum ($name, 'Current_SelfConsumption', 0); my $cself = ReadingsNum ($name, 'Current_SelfConsumption', 0);
my $cc = CurrentVal ($hash, 'consumption', 0); my $cc = CurrentVal ($hash, 'consumption', 0);
my $batin = ReadingsNum ($name, 'Current_PowerBatIn', undef); my $batin = ReadingsNum ($name, 'Current_PowerBatIn', undef);
my $batout = ReadingsNum ($name, 'Current_PowerBatOut', undef); my $batout = ReadingsNum ($name, 'Current_PowerBatOut', undef);
@ -14114,17 +14157,20 @@ sub _flowGraphic {
################################################################ ################################################################
my $pdcr = {}; # Hashref Producer my $pdcr = {}; # Hashref Producer
my $ppall = 0; # Summe Erzeugung alle nicht PV-Producer my $ppall = 0; # Summe Erzeugung alle nicht PV-Producer
my $pvall = 0; # Summe Erzeugung alle Inverter my $pv2node = 0; # Summe PV-Erzeugung alle Inverter
my $pv2grid = 0;
my $lfn = 0; my $lfn = 0;
for my $pn (1..$maxproducer) { for my $pn (1..$maxproducer) {
$pn = sprintf "%02d", $pn; $pn = sprintf "%02d", $pn;
my $p = ProducerVal ($hash, $pn, 'pgeneration', undef); my $p = ProducerVal ($hash, $pn, 'pgeneration', undef);
my $feed = ProducerVal ($hash, $pn, 'pfeed', 'default');
if (defined $p) { if (defined $p) {
$p = __normDecPlaces ($p); $p = __normDecPlaces ($p);
$pdcr->{$lfn}{p} = $p; # aktuelle Erzeugung nicht PV-Producer $pdcr->{$lfn}{p} = $p; # aktuelle Erzeugung nicht PV-Producer
$pdcr->{$lfn}{pn} = $pn; # Producernummer $pdcr->{$lfn}{pn} = $pn; # Producernummer
$pdcr->{$lfn}{feed} = $feed; # Eigenschaft der Energielieferung
$pdcr->{$lfn}{ptyp} = 'producer'; # Typ des Producers $pdcr->{$lfn}{ptyp} = 'producer'; # Typ des Producers
$ppall += $p; # aktuelle Erzeuguung aller nicht PV-Producer $ppall += $p; # aktuelle Erzeuguung aller nicht PV-Producer
@ -14135,21 +14181,25 @@ sub _flowGraphic {
for my $in (1..$maxinverter) { for my $in (1..$maxinverter) {
$in = sprintf "%02d", $in; $in = sprintf "%02d", $in;
my $p = InverterVal ($hash, $in, 'igeneration', undef); my $p = InverterVal ($hash, $in, 'igeneration', undef);
my $feed = InverterVal ($hash, $in, 'ifeed', 'default');
if (defined $p) { if (defined $p) {
$p = __normDecPlaces ($p); $p = __normDecPlaces ($p);
$pdcr->{$lfn}{p} = $p; # aktuelle Erzeugung Inverter
$pdcr->{$lfn}{pn} = $in; # Inverternummer $pdcr->{$lfn}{pn} = $in; # Inverternummer
$pdcr->{$lfn}{feed} = $feed; # Eigenschaft der Energielieferung
$pdcr->{$lfn}{ptyp} = 'inverter'; # Typ des Producers $pdcr->{$lfn}{ptyp} = 'inverter'; # Typ des Producers
$pvall += $p; $pdcr->{$lfn}{p} = $p; # aktuelle PV
$pv2node += $p if($feed eq 'default'); # PV-Erzeugung Inverter für das Hausnetz
$pv2grid += $p if($feed eq 'grid'); # PV nur für das öffentliche Netz
$lfn++; $lfn++;
} }
} }
my $pallsum = __normDecPlaces ($ppall + $pvall); my $node2grid = $cgfi; # vom Knoten zum Grid
my $pnodesum = __normDecPlaces ($ppall + $pv2node); # Erzeugung Summe im Knoten
my $producercount = keys %{$pdcr}; my $producercount = keys %{$pdcr};
my @producers = sort{$a<=>$b} keys %{$pdcr}; my @prodsorted = __sortProducer ($pdcr); # lfn Producer sortiert nach ptyp und feed
## definierte Verbraucher ermitteln ## definierte Verbraucher ermitteln
##################################### #####################################
@ -14177,19 +14227,19 @@ sub _flowGraphic {
$soc = 0; $soc = 0;
} }
my $grid_color = $cgfi ? 'flowg grid_color1' : 'flowg grid_color2'; my $grid_color = $node2grid ? 'flowg grid_color1' : 'flowg grid_color2';
my $cgc_style = $cgc ? 'flowg active_in' : 'flowg inactive_in'; my $cgc_style = $cgc ? 'flowg active_in' : 'flowg inactive_in';
my $batout_style = $batout ? 'flowg active_out active_bat_out' : 'flowg inactive_in'; my $batout_style = $batout ? 'flowg active_out active_bat_out' : 'flowg inactive_in';
$grid_color = 'flowg grid_color3' if(!$cgfi && !$cgc && $batout); # dritte Farbe $grid_color = 'flowg grid_color3' if(!$node2grid && !$cgc && $batout); # dritte Farbe
my $cgc_direction = 'M490,515 L670,590'; # Batterientladung ins Netz my $cgc_direction = 'M490,515 L670,590'; # Batterie wird geladen
if ($batout) { # Batterie wird entladen if ($batout) { # Batterie wird entladen
my $cgfo = $cgfi - $pvall; my $cgfo = $node2grid - $pv2node;
if ($cgfo > 1) { if ($cgfo > 1) {
$cgc_style = 'flowg active_out'; $cgc_style = 'flowg active_out';
$cgc_direction = 'M670,590 L490,515'; $cgc_direction = 'M670,590 L490,515';
$cgfi -= $cgfo; $node2grid -= $cgfo;
$cgc = $cgfo; $cgc = $cgfo;
} }
} }
@ -14197,7 +14247,7 @@ sub _flowGraphic {
my $batout_direction = 'M902,515 L730,590'; my $batout_direction = 'M902,515 L730,590';
if ($batin) { # Batterie wird geladen if ($batin) { # Batterie wird geladen
my $gbi = $batin - $pvall; my $gbi = $batin - $pv2node;
if ($gbi > 1) { # Batterieladung anteilig aus Hausnetz geladen if ($gbi > 1) { # Batterieladung anteilig aus Hausnetz geladen
$batin -= $gbi; $batin -= $gbi;
@ -14210,7 +14260,7 @@ sub _flowGraphic {
## Werte / SteuerungVars anpassen ## Werte / SteuerungVars anpassen
################################### ###################################
$flowgcons = 0 if(!$consumercount); # Consumer Anzeige ausschalten wenn keine Consumer definiert $flowgcons = 0 if(!$consumercount); # Consumer Anzeige ausschalten wenn keine Consumer definiert
my $p2home = __normDecPlaces ($csc + $ppall); # Energiefluß von Knoten zum Haus: Selbstverbrauch + alle Producer my $p2home = __normDecPlaces ($cself + $ppall); # Energiefluß von Knoten zum Haus: Selbstverbrauch + alle Producer
## SVG Box initialisieren mit Grid-Icon ## SVG Box initialisieren mit Grid-Icon
######################################### #########################################
@ -14254,7 +14304,7 @@ END0
$pos_left = $producer_start + 5; $pos_left = $producer_start + 5;
for my $lfn (@producers) { for my $lfn (@prodsorted) {
my $pn = $pdcr->{$lfn}{pn}; my $pn = $pdcr->{$lfn}{pn};
my ($picon, $ptxt) = __substituteIcon ( { hash => $hash, # Icon des Producerdevices my ($picon, $ptxt) = __substituteIcon ( { hash => $hash, # Icon des Producerdevices
name => $name, name => $name,
@ -14281,7 +14331,7 @@ END0
my ($nicon, $ntxt) = __substituteIcon ( { hash => $hash, my ($nicon, $ntxt) = __substituteIcon ( { hash => $hash,
name => $name, name => $name,
ptyp => 'node', ptyp => 'node',
pcurr => $pallsum, pcurr => $pnodesum,
lang => $lang lang => $lang
} }
); );
@ -14372,15 +14422,15 @@ END1
$ret .= '</g> '; $ret .= '</g> ';
} }
## Laufketten PV->Home, PV->Grid, Grid->Home ## Laufketten PV->Home, PV->Grid, Bat->Home
############################################## ##############################################
my $csc_style = $p2home ? 'flowg active_out' : 'flowg inactive_out'; my $csc_style = $p2home ? 'flowg active_out' : 'flowg inactive_out';
my $cgfi_style = $cgfi ? 'flowg active_out' : 'flowg inactive_out'; my $cgfi_style = $node2grid ? 'flowg active_out' : 'flowg inactive_out';
$ret .= << "END2"; $ret .= << "END2";
<g transform="translate(50,50),scale(0.5)" stroke-width="27" fill="none"> <g transform="translate(50,50),scale(0.5)" stroke-width="27" fill="none">
<path id="pv-home" class="$csc_style" d="M700,400 L700,580" /> <path id="pv-home" class="$csc_style" d="M700,400 L700,580" />
<path id="pv-grid" class="$cgfi_style" d="M670,400 L490,480" /> <path id="pv-grid" class="$cgfi_style" d="M670,400 L490,480" />
<path id="grid-home" class="$cgc_style" d="$cgc_direction" /> <path id="bat-home" class="$cgc_style" d="$cgc_direction" />
END2 END2
## Laufketten PV->Batterie, Batterie->Home ## Laufketten PV->Batterie, Batterie->Home
@ -14411,19 +14461,22 @@ END3
## Producer Laufketten ## Producer Laufketten
######################## ########################
$pos_left = $producer_start * 2; $pos_left = $producer_start * 2;
my $pos_left_start_con = 0; my $pos_left_start_nod = 0;
my $pos_left_start_grd = 390;
my $distance_prd = 65; my $distance_prd = 65;
if ($producercount % 2) { if ($producercount % 2) {
$pos_left_start_con = 700 - ($distance_prd * (($producercount -1) / 2)); $pos_left_start_nod = 700 - ($distance_prd * (($producercount -1) / 2));
} }
else { else {
$pos_left_start_con = 700 - ((($distance_prd ) / 2) * ($producercount-1)); $pos_left_start_nod = 700 - ((($distance_prd ) / 2) * ($producercount-1));
} }
for my $lfn (@producers) { for my $lfn (@prodsorted) {
my $pn = $pdcr->{$lfn}{pn}; my $pn = $pdcr->{$lfn}{pn};
my $p = $pdcr->{$lfn}{p}; my $p = $pdcr->{$lfn}{p};
my $feed = $pdcr->{$lfn}{feed}; # default | grid | bat
my $consumer_style = 'flowg inactive_out'; my $consumer_style = 'flowg inactive_out';
$consumer_style = 'flowg active_out' if($p > 0); $consumer_style = 'flowg active_out' if($p > 0);
my $chain_color = ''; # Farbe der Laufkette des Producers my $chain_color = ''; # Farbe der Laufkette des Producers
@ -14433,9 +14486,16 @@ END3
$chain_color = 'style="stroke: darkorange;"'; $chain_color = 'style="stroke: darkorange;"';
} }
$ret .= qq{<path id="genproducer_$pn " class="$consumer_style" $chain_color d=" M$pos_left,130 L$pos_left_start_con,200" />}; # Design Consumer Laufkette if ($feed eq 'default') {
$ret .= qq{<path id="genproducer_$lfn " class="$consumer_style" $chain_color d=" M$pos_left,130 L$pos_left_start_nod,200" />};
}
elsif ($feed eq 'grid') {
$ret .= qq{<path id="genproducer_$lfn " class="$consumer_style" $chain_color d=" M$pos_left,130 $pos_left_start_grd,390" />};
}
$pos_left += ($consDist * 2); $pos_left += ($consDist * 2);
$pos_left_start_con += $distance_prd; $pos_left_start_nod += $distance_prd;
$pos_left_start_grd += 10;
} }
## Consumer Laufketten ## Consumer Laufketten
@ -14481,10 +14541,10 @@ END3
## Textangaben an Grafikelementen ## Textangaben an Grafikelementen
################################### ###################################
$cc_dummy = sprintf("%.0f", $cc_dummy); # Verbrauch Dummy-Consumer $cc_dummy = sprintf("%.0f", $cc_dummy); # Verbrauch Dummy-Consumer
$ret .= qq{<text class="flowg text" id="node-txt" x="800" y="320" style="text-anchor: start;">$pallsum</text>} if ($pallsum > 0); $ret .= qq{<text class="flowg text" id="node-txt" x="800" y="320" style="text-anchor: start;">$pnodesum</text>} if ($pnodesum > 0);
$ret .= qq{<text class="flowg text" id="bat-txt" x="1110" y="520" style="text-anchor: start;">$soc %</text>} if ($hasbat); # Lage Text Batterieladungszustand $ret .= qq{<text class="flowg text" id="bat-txt" x="1110" y="520" style="text-anchor: start;">$soc %</text>} if ($hasbat); # Lage Text Batterieladungszustand
$ret .= qq{<text class="flowg text" id="node_home-txt" x="730" y="520" style="text-anchor: start;">$p2home</text>} if ($p2home); $ret .= qq{<text class="flowg text" id="node_home-txt" x="730" y="520" style="text-anchor: start;">$p2home</text>} if ($p2home);
$ret .= qq{<text class="flowg text" id="node-grid-txt" x="525" y="420" style="text-anchor: end;">$cgfi</text>} if ($cgfi); $ret .= qq{<text class="flowg text" id="node-grid-txt" x="525" y="420" style="text-anchor: end;">$node2grid</text>} if ($node2grid);
$ret .= qq{<text class="flowg text" id="grid-home-txt" x="515" y="610" style="text-anchor: end;">$cgc</text>} if ($cgc); $ret .= qq{<text class="flowg text" id="grid-home-txt" x="515" y="610" style="text-anchor: end;">$cgc</text>} if ($cgc);
$ret .= qq{<text class="flowg text" id="batout-txt" x="880" y="610" style="text-anchor: start;">$batout</text>} if ($batout && $hasbat); $ret .= qq{<text class="flowg text" id="batout-txt" x="880" y="610" style="text-anchor: start;">$batout</text>} if ($batout && $hasbat);
$ret .= qq{<text class="flowg text" id="batin-txt" x="880" y="420" style="text-anchor: start;">$batin</text>} if ($batin && $hasbat); $ret .= qq{<text class="flowg text" id="batin-txt" x="880" y="420" style="text-anchor: start;">$batin</text>} if ($batin && $hasbat);
@ -14497,7 +14557,7 @@ END3
######################## ########################
$pos_left = $producer_start * 2 - 70; # -XX -> Start Lage Producer Beschriftung $pos_left = $producer_start * 2 - 70; # -XX -> Start Lage Producer Beschriftung
for my $lfn (@producers) { for my $lfn (@prodsorted) {
my $pn = $pdcr->{$lfn}{pn}; my $pn = $pdcr->{$lfn}{pn};
$currentPower = $pdcr->{$lfn}{p}; $currentPower = $pdcr->{$lfn}{p};
$lcp = length $currentPower; $lcp = length $currentPower;
@ -14571,6 +14631,41 @@ END3
return $ret; return $ret;
} }
################################################################
# erzeugt eine Liste der Producernummern sortiert von
# links nach rechts:
# -> alle Inverter mit Feed-Typ 'grid'
# -> alle Producer (nicht PV)
# -> alle Inverter mit Feed-Typ 'default'
# -> alle Inverter mit Feed-Typ 'bat'
################################################################
sub __sortProducer {
my $pdcr = shift; # Hashref Producer
my @all = ();
my @igrid = ();
my @prod = ();
my @idef = ();
my @ibat = ();
for my $lfn (sort{$a<=>$b} keys %{$pdcr}) {
my $ptyp = $pdcr->{$lfn}{ptyp}; # producer | inverter
my $feed = $pdcr->{$lfn}{feed}; # default | grid | bat
push @igrid, $lfn if($ptyp eq 'inverter' && $feed eq 'grid');
push @prod, $lfn if($ptyp eq 'producer');
push @idef, $lfn if($ptyp eq 'inverter' && $feed eq 'default');
push @ibat, $lfn if($ptyp eq 'inverter' && $feed eq 'bat');
}
push @all, @igrid;
push @all, @prod;
push @all, @idef;
push @all, @ibat;
return @all;
}
################################################################ ################################################################
# prüfe ob Icon + Farbe angegeben ist # prüfe ob Icon + Farbe angegeben ist
# und setze ggf. Ersatzwerte # und setze ggf. Ersatzwerte
@ -14703,8 +14798,6 @@ sub __normIconScale {
$icon =~ s/width="(.*?)"/width="$widthnormpt"/; $icon =~ s/width="(.*?)"/width="$widthnormpt"/;
$icon =~ s/height="(.*?)"/height="$heightnormpt"/; $icon =~ s/height="(.*?)"/height="$heightnormpt"/;
# Log3 ($name, 2, "$name - widthnormpt: $widthnormpt, heightnormpt: $heightnormpt");
return ($fgscaledef, $icon); return ($fgscaledef, $icon);
} }
@ -16468,7 +16561,7 @@ sub checkPlantConfig {
for my $sn (sort keys %{$data{$type}{$name}{strings}}) { for my $sn (sort keys %{$data{$type}{$name}{strings}}) {
my $sp = $sn." => ".$sub->($sn)."<br>"; my $sp = $sn." => ".$sub->($sn)."<br>";
Log3 ($name, 1, "$name - sp: $sp");
$result->{'String Configuration'}{note} .= $sn." => ".$sub->($sn)."<br>"; $result->{'String Configuration'}{note} .= $sn." => ".$sub->($sn)."<br>";
if ($data{$type}{$name}{strings}{$sn}{peak} >= 500) { if ($data{$type}{$name}{strings}{$sn}{peak} >= 500) {
@ -20184,11 +20277,13 @@ to ensure that the system configuration is correct.
<table> <table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup> <colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>ietotal </b> </td><td>total energy generated by the inverter to date (Wh) </td></tr> <tr><td> <b>ietotal </b> </td><td>total energy generated by the inverter to date (Wh) </td></tr>
<tr><td> <b>ifeed </b> </td><td>Energy supply characteristics </td></tr>
<tr><td> <b>igeneration </b> </td><td>current PV generation (W) </td></tr> <tr><td> <b>igeneration </b> </td><td>current PV generation (W) </td></tr>
<tr><td> <b>iicon </b> </td><td>any icons defined for displaying the device in the graphic </td></tr> <tr><td> <b>iicon </b> </td><td>any icons defined for displaying the device in the graphic </td></tr>
<tr><td> <b>ialias </b> </td><td>Alias of the device </td></tr> <tr><td> <b>ialias </b> </td><td>Alias of the device </td></tr>
<tr><td> <b>iname </b> </td><td>Name of the device </td></tr> <tr><td> <b>iname </b> </td><td>Name of the device </td></tr>
<tr><td> <b>invertercap </b> </td><td>the nominal power (W) of the inverter (if defined) </td></tr> <tr><td> <b>invertercap </b> </td><td>the nominal power (W) of the inverter (if defined) </td></tr>
<tr><td> <b>istrings </b> </td><td>List of strings assigned to the inverter (if defined) </td></tr>
</table> </table>
</ul> </ul>
@ -20205,6 +20300,7 @@ to ensure that the system configuration is correct.
<table> <table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup> <colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>petotal </b> </td><td>total energy generated by the producer to date (Wh) </td></tr> <tr><td> <b>petotal </b> </td><td>total energy generated by the producer to date (Wh) </td></tr>
<tr><td> <b>pfeed </b> </td><td>Energy supply characteristics </td></tr>
<tr><td> <b>pgeneration </b> </td><td>current power (W) </td></tr> <tr><td> <b>pgeneration </b> </td><td>current power (W) </td></tr>
<tr><td> <b>picon </b> </td><td>any icons defined for displaying the device in the graphic </td></tr> <tr><td> <b>picon </b> </td><td>any icons defined for displaying the device in the graphic </td></tr>
<tr><td> <b>palias </b> </td><td>Alias of the device </td></tr> <tr><td> <b>palias </b> </td><td>Alias of the device </td></tr>
@ -21323,21 +21419,24 @@ to ensure that the system configuration is correct.
<a id="SolarForecast-attr-setupInverterDev" data-pattern="setupInverterDev.*"></a> <a id="SolarForecast-attr-setupInverterDev" data-pattern="setupInverterDev.*"></a>
<li><b>setupInverterDevXX &lt;Inverter Device Name&gt; pv=&lt;Readingname&gt;:&lt;Unit&gt; etotal=&lt;Readingname&gt;:&lt;Unit&gt; <li><b>setupInverterDevXX &lt;Inverter Device Name&gt; pv=&lt;Readingname&gt;:&lt;Unit&gt; etotal=&lt;Readingname&gt;:&lt;Unit&gt;
[capacity=&lt;max. WR-Leistung&gt;] [icon=&lt;Day&gt;[@&lt;Color&gt;][:&lt;Night&gt;[@&lt;Color&gt;]]] </b> <br><br> [capacity=&lt;max. WR-Leistung&gt;] [strings=&lt;String1&gt;,&lt;String2&gt;,...]
[feed=&lt;Delivery type&gt;]
[icon=&lt;Day&gt;[@&lt;Color&gt;][:&lt;Night&gt;[@&lt;Color&gt;]]] </b> <br><br>
Specifies any Device and its Readings to deliver the current PV generation values. Defines any inverter device or solar charger and its readings to supply the current PV generation values. <br>
It can also be a dummy device with appropriate readings. A solar charger does not convert the energy supplied by the solar cells into alternating current,
The values of several inverter devices are merged e.g. in a dummy device and this device is specified with the but instead directly charges an existing battery <br>
corresponding readings. <br> (e.g. a Victron SmartSolar MPPT). <br>
Several devices can be defined one after the other in the setupInverterDev01..XX attributes. <br>
This can also be a dummy device with corresponding readings. <br>
The values of several inverters can be combined in a dummy device, for example, and this device can
be specified with the corresponding readings. <br>
Specifying <b>capacity</b> is optional, but strongly recommended to optimize prediction accuracy. Specifying <b>capacity</b> is optional, but strongly recommended to optimize prediction accuracy.
<br><br> <br><br>
<ul> <ul>
<table> <table>
<colgroup> <col width="15%"> <col width="85%"> </colgroup> <colgroup> <col width="15%"> <col width="85%"> </colgroup>
<tr><td> <b>icon</b> </td><td>Icon for displaying the inverter in the flow chart (optional) </td></tr>
<tr><td> </td><td><b>&lt;Day&gt;</b> - Icon and optional color for activity after sunrise </td></tr>
<tr><td> </td><td><b>&lt;Night&gt;</b> - Icon and optional color after sunset, otherwise the moon phase is displayed </td></tr>
<tr><td> <b>pv</b> </td><td>Reading which provides the current PV generation as a positive value </td></tr> <tr><td> <b>pv</b> </td><td>Reading which provides the current PV generation as a positive value </td></tr>
<tr><td> <b>etotal</b> </td><td>Reading which provides the total PV energy generated (a steadily increasing counter). </td></tr> <tr><td> <b>etotal</b> </td><td>Reading which provides the total PV energy generated (a steadily increasing counter). </td></tr>
<tr><td> </td><td>If the reading violates the specification of a continuously rising counter, </td></tr> <tr><td> </td><td>If the reading violates the specification of a continuously rising counter, </td></tr>
@ -21345,13 +21444,22 @@ to ensure that the system configuration is correct.
<tr><td> <b>Einheit</b> </td><td>the respective unit (W,kW,Wh,kWh) </td></tr> <tr><td> <b>Einheit</b> </td><td>the respective unit (W,kW,Wh,kWh) </td></tr>
<tr><td> <b>capacity</b> </td><td>Rated power of the inverter according to data sheet, i.e. max. possible output in Watts </td></tr> <tr><td> <b>capacity</b> </td><td>Rated power of the inverter according to data sheet, i.e. max. possible output in Watts </td></tr>
<tr><td> </td><td>(The entry is optional, but is strongly recommended) </td></tr> <tr><td> </td><td>(The entry is optional, but is strongly recommended) </td></tr>
<tr><td> <b>strings</b> </td><td>Comma-separated list of the strings assigned to the inverter (optional). The string names </td></tr>
<tr><td> </td><td>are defined in the <a href=#SolarForecast-attr-setupInverterStrings”>setupInverterStrings</a> attribute. </td></tr>
<tr><td> </td><td>If 'strings' is not specified, all defined string names are assigned to the inverter. </td></tr>
<tr><td> <b>feed</b> </td><td>Defines special properties of the device's energy supply (optional). </td></tr>
<tr><td> </td><td>If the key is not set, the device feeds the PV energy into the house's AC grid. </td></tr>
<tr><td> </td><td><b>grid</b> - the energy is fed exclusively into the public grid </td></tr>
<tr><td> <b>icon</b> </td><td>Icon for displaying the inverter in the flow chart (optional) </td></tr>
<tr><td> </td><td><b>&lt;Day&gt;</b> - Icon and optional color for activity after sunrise </td></tr>
<tr><td> </td><td><b>&lt;Night&gt;</b> - Icon and optional color after sunset, otherwise the moon phase is displayed </td></tr>
</table> </table>
</ul> </ul>
<br> <br>
<ul> <ul>
<b>Example: </b> <br> <b>Example: </b> <br>
attr &lt;name&gt; setupInverterDev01 STP5000 pv=total_pac:kW etotal=etotal:kWh capacity=5000 icon=inverter@red:solar attr &lt;name&gt; setupInverterDev01 STP5000 pv=total_pac:kW etotal=etotal:kWh capacity=5000 strings=Garage icon=inverter@red:solar
</ul> </ul>
<br> <br>
@ -22600,11 +22708,13 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<table> <table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup> <colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>ietotal </b> </td><td>Stand gesamte bisher erzeugte Energie des Wechselrichters (Wh) </td></tr> <tr><td> <b>ietotal </b> </td><td>Stand gesamte bisher erzeugte Energie des Wechselrichters (Wh) </td></tr>
<tr><td> <b>ifeed </b> </td><td>Eigenschaften der Energielieferung </td></tr>
<tr><td> <b>igeneration </b> </td><td>aktuelle PV Erzeugung (W) </td></tr> <tr><td> <b>igeneration </b> </td><td>aktuelle PV Erzeugung (W) </td></tr>
<tr><td> <b>iicon </b> </td><td>die evtl. festgelegten Icons zur Darstellung des Gerätes in der Grafik </td></tr> <tr><td> <b>iicon </b> </td><td>die evtl. festgelegten Icons zur Darstellung des Gerätes in der Grafik </td></tr>
<tr><td> <b>ialias </b> </td><td>Alias des Devices </td></tr> <tr><td> <b>ialias </b> </td><td>Alias des Devices </td></tr>
<tr><td> <b>iname </b> </td><td>Name des Devices </td></tr> <tr><td> <b>iname </b> </td><td>Name des Devices </td></tr>
<tr><td> <b>invertercap </b> </td><td>die nominale Leistung (W) des Wechselrichters (falls definiert) </td></tr> <tr><td> <b>invertercap </b> </td><td>die nominale Leistung (W) des Wechselrichters (falls definiert) </td></tr>
<tr><td> <b>istrings </b> </td><td>Liste der dem Wechselrichter zugeordneten Strings (falls definiert) </td></tr>
</table> </table>
</ul> </ul>
@ -22621,6 +22731,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<table> <table>
<colgroup> <col width="20%"> <col width="80%"> </colgroup> <colgroup> <col width="20%"> <col width="80%"> </colgroup>
<tr><td> <b>petotal </b> </td><td>Stand gesamte bisher erzeugte Energie des Erzeugers (Wh) </td></tr> <tr><td> <b>petotal </b> </td><td>Stand gesamte bisher erzeugte Energie des Erzeugers (Wh) </td></tr>
<tr><td> <b>pfeed </b> </td><td>Eigenschaften der Energielieferung </td></tr>
<tr><td> <b>pgeneration </b> </td><td>aktuelle Leistung (W) </td></tr> <tr><td> <b>pgeneration </b> </td><td>aktuelle Leistung (W) </td></tr>
<tr><td> <b>picon </b> </td><td>die evtl. festgelegten Icons zur Darstellung des Gerätes in der Grafik </td></tr> <tr><td> <b>picon </b> </td><td>die evtl. festgelegten Icons zur Darstellung des Gerätes in der Grafik </td></tr>
<tr><td> <b>palias </b> </td><td>Alias des Devices </td></tr> <tr><td> <b>palias </b> </td><td>Alias des Devices </td></tr>
@ -23739,21 +23850,25 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<a id="SolarForecast-attr-setupInverterDev" data-pattern="setupInverterDev.*"></a> <a id="SolarForecast-attr-setupInverterDev" data-pattern="setupInverterDev.*"></a>
<li><b>setupInverterDevXX &lt;Inverter Device Name&gt; pv=&lt;Readingname&gt;:&lt;Einheit&gt; etotal=&lt;Readingname&gt;:&lt;Einheit&gt; <li><b>setupInverterDevXX &lt;Inverter Device Name&gt; pv=&lt;Readingname&gt;:&lt;Einheit&gt; etotal=&lt;Readingname&gt;:&lt;Einheit&gt;
[capacity=&lt;max. WR-Leistung&gt;] [icon=&lt;Tag&gt;[@&lt;Farbe&gt;][:&lt;Nacht&gt;[@&lt;Farbe&gt;]]] </b> <br><br> [capacity=&lt;max. WR-Leistung&gt;] [strings=&lt;String1&gt;,&lt;String2&gt;,...]
[feed=&lt;Liefertyp&gt;]
[icon=&lt;Tag&gt;[@&lt;Farbe&gt;][:&lt;Nacht&gt;[@&lt;Farbe&gt;]]] </b> <br><br>
Legt ein beliebiges Device und dessen Readings zur Lieferung der aktuellen PV Erzeugungswerte fest. Legt ein beliebiges Wechselrichter-Gerät bzw. Solar-Ladegerät und dessen Readings zur Lieferung der aktuellen
Es kann auch ein Dummy Device mit entsprechenden Readings sein. PV Erzeugungswerte fest. <br>
Die Werte mehrerer Inverterdevices führt man z.B. in einem Dummy Device zusammen und gibt dieses Device mit den Ein Solar-Ladegerät wandelt die von den Solarzellen gelieferte Energie nicht in Wechselstrom um, sondern
entsprechenden Readings an. <br> lädt damit direkt eine vorhandene Batterie <br>
(z.B. ein Victron SmartSolar MPPT). <br>
Es können nacheinander mehrere Geräte in den Attributen setupInverterDev01..XX definiert werden. <br>
Dabei kann es sich auch um ein Dummy Gerät mit entsprechenden Readings handeln. <br>
Die Werte mehrerer Wechselrichter kann man z.B. in einem Dummy Gerät zusammenführen und gibt dieses Gerät mit
den entsprechenden Readings an. <br>
Die Angabe von <b>capacity</b> ist optional, wird aber zur Optimierung der Vorhersagegenauigkeit dringend empfohlen. Die Angabe von <b>capacity</b> ist optional, wird aber zur Optimierung der Vorhersagegenauigkeit dringend empfohlen.
<br><br> <br><br>
<ul> <ul>
<table> <table>
<colgroup> <col width="15%"> <col width="85%"> </colgroup> <colgroup> <col width="15%"> <col width="85%"> </colgroup>
<tr><td> <b>icon</b> </td><td>Icon zur Darstellung des Inverters in der Flowgrafik (optional) </td></tr>
<tr><td> </td><td><b>&lt;Tag&gt;</b> - Icon und ggf. Farbe bei Aktivität nach Sonnenaufgang </td></tr>
<tr><td> </td><td><b>&lt;Nacht&gt;</b> - Icon und ggf. Farbe nach Sonnenuntergang, sonst wird die Mondphase angezeigt </td></tr>
<tr><td> <b>pv</b> </td><td>Reading welches die aktuelle PV-Erzeugung als positiven Wert liefert </td></tr> <tr><td> <b>pv</b> </td><td>Reading welches die aktuelle PV-Erzeugung als positiven Wert liefert </td></tr>
<tr><td> <b>etotal</b> </td><td>Reading welches die gesamte erzeugte PV-Energie liefert (ein stetig aufsteigender Zähler) </td></tr> <tr><td> <b>etotal</b> </td><td>Reading welches die gesamte erzeugte PV-Energie liefert (ein stetig aufsteigender Zähler) </td></tr>
<tr><td> </td><td>Sollte des Reading die Vorgabe eines stetig aufsteigenden Zählers verletzen, behandelt </td></tr> <tr><td> </td><td>Sollte des Reading die Vorgabe eines stetig aufsteigenden Zählers verletzen, behandelt </td></tr>
@ -23761,13 +23876,22 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> <b>Einheit</b> </td><td>die jeweilige Einheit (W,kW,Wh,kWh) </td></tr> <tr><td> <b>Einheit</b> </td><td>die jeweilige Einheit (W,kW,Wh,kWh) </td></tr>
<tr><td> <b>capacity</b> </td><td>Bemessungsleistung des Wechselrichters gemäß Datenblatt, d.h. max. möglicher Output in Watt </td></tr> <tr><td> <b>capacity</b> </td><td>Bemessungsleistung des Wechselrichters gemäß Datenblatt, d.h. max. möglicher Output in Watt </td></tr>
<tr><td> </td><td>(Die Angabe ist optional, wird aber dringend empfohlen zu setzen) </td></tr> <tr><td> </td><td>(Die Angabe ist optional, wird aber dringend empfohlen zu setzen) </td></tr>
<tr><td> <b>strings</b> </td><td>Komma getrennte Liste der dem Wechselrichter zugeordneten Strings (optional). Die Stringnamen </td></tr>
<tr><td> </td><td>werden im Attribut <a href="#SolarForecast-attr-setupInverterStrings">setupInverterStrings</a> definiert. </td></tr>
<tr><td> </td><td>Ist 'strings' nicht angegeben, werden alle definierten Stringnamen dem Wechselrichter zugeordnet. </td></tr>
<tr><td> <b>feed</b> </td><td>Definiert spezielle Eigenschaften der Energielieferung des Gerätes (optional). </td></tr>
<tr><td> </td><td>Ist der Schlüssel nicht gesetzt, speist das Gerät die PV-Energie in das Wechselstromnetz des Hauses ein. </td></tr>
<tr><td> </td><td><b>grid</b> - die Energie wird ausschließlich in das öffentlich Netz eingespeist </td></tr>
<tr><td> <b>icon</b> </td><td>Icon zur Darstellung des Inverters in der Flowgrafik (optional) </td></tr>
<tr><td> </td><td><b>&lt;Tag&gt;</b> - Icon und ggf. Farbe bei Aktivität nach Sonnenaufgang </td></tr>
<tr><td> </td><td><b>&lt;Nacht&gt;</b> - Icon und ggf. Farbe nach Sonnenuntergang, sonst wird die Mondphase angezeigt </td></tr>
</table> </table>
</ul> </ul>
<br> <br>
<ul> <ul>
<b>Beispiel: </b> <br> <b>Beispiel: </b> <br>
attr &lt;name&gt; setupInverterDev01 STP5000 pv=total_pac:kW etotal=etotal:kWh capacity=5000 icon=inverter@red:solar attr &lt;name&gt; setupInverterDev01 STP5000 pv=total_pac:kW etotal=etotal:kWh capacity=5000 strings=Garage icon=inverter@red:solar
</ul> </ul>
<br> <br>