diff --git a/contrib/DS_Starter/76_SolarForecast.pm b/contrib/DS_Starter/76_SolarForecast.pm index 53f11052a..c3b899eb5 100644 --- a/contrib/DS_Starter/76_SolarForecast.pm +++ b/contrib/DS_Starter/76_SolarForecast.pm @@ -120,6 +120,9 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "0.61.0 "=> "15.05.2022 limit PV forecast to inverter capacity ", + "0.60.1 "=> "15.05.2022 consumerHash -> new key avgruntime, don't modify mintime by avgruntime by default anymore ". + "debug switch conditions ", "0.60.0 "=> "14.05.2022 new key 'swoncond' in consumer attributes ", "0.59.0 "=> "01.05.2022 new attr createTomorrowPVFcReadings ", "0.58.0 "=> "20.04.2022 new setter consumerImmediatePlanning, functions isConsumerOn isConsumerOff ", @@ -2499,11 +2502,13 @@ sub _transferInverterValues { my ($a,$h) = parseParams ($indev); $indev = $a->[0] // ""; return if(!$indev || !$defs{$indev}); - + my $type = $hash->{TYPE}; my ($pvread,$pvunit) = split ":", $h->{pv}; # Readingname/Unit für aktuelle PV Erzeugung - my ($edread,$etunit) = split ":", $h->{etotal}; # Readingname/Unit für Energie total + my ($edread,$etunit) = split ":", $h->{etotal}; # Readingname/Unit für Energie total (PV Erzeugung) + + $data{$type}{$name}{current}{invertercapacity} = $h->{capacity} if($h->{capacity}); # optionale Angabe max. WR-Leistung return if(!$pvread || !$edread); @@ -2865,22 +2870,25 @@ sub _manageConsumerData { my $runhours = 0; my $dnum = 0; - for my $n (sort{$a<=>$b} keys %{$data{$type}{$name}{pvhist}}) { # gemessenen Verbrauch ermitteln - my $csme = HistoryVal ($hash, $n, 99, "csme${c}", 0); - next if(!$csme); + for my $n (sort{$a<=>$b} keys %{$data{$type}{$name}{pvhist}}) { # Betriebszeit und gemessenen Verbrauch ermitteln + my $csme = HistoryVal ($hash, $n, 99, "csme${c}", 0); my $hours = HistoryVal ($hash, $n, 99, "hourscsme${c}", 0); + next if(!$hours); $consumerco += $csme; $runhours += $hours; $dnum++; } - - if ($dnum) { - $data{$type}{$name}{consumers}{$c}{avgenergy} = ceil ($consumerco/$dnum); # Durchschnittsverbrauch eines Tages aus History - my $mintime = ConsumerVal ($hash, $c, "mintime", $defmintime); - my $avgruntime = (ceil($runhours/$dnum)) * 60; # Durchschnittslaufzeit in Minuten - $mintime = $avgruntime < $mintime ? $mintime : $avgruntime; - $data{$type}{$name}{consumers}{$c}{mintime} = $mintime; + + if ($dnum) { + if($consumerco) { + $data{$type}{$name}{consumers}{$c}{avgenergy} = ceil ($consumerco/$dnum); # Durchschnittsverbrauch eines Tages aus History + } + else { + delete $data{$type}{$name}{consumers}{$c}{avgenergy}; + } + + $data{$type}{$name}{consumers}{$c}{avgruntime} = (ceil($runhours/$dnum)) * 60; # Durchschnittslaufzeit in Minuten } $paref->{consumer} = $c; @@ -3361,6 +3369,7 @@ sub __switchConsumer { my $pstate = ConsumerVal ($hash, $c, "planstate", ""); my $cname = ConsumerVal ($hash, $c, "name", ""); # Consumer Device Name my $calias = ConsumerVal ($hash, $c, "alias", ""); # Consumer Device Alias + my $debug = AttrVal ($name, "debug", 0); ## Ist Verbraucher empfohlen ? ################################ @@ -3373,9 +3382,19 @@ sub __switchConsumer { ## Verbraucher einschalten ############################ - my $oncom = ConsumerVal ($hash, $c, "oncom", ""); # Set Command für "on" - my $auto = ConsumerVal ($hash, $c, "auto", 1); - my $swoncond = isAddSwitchOnCond ($hash, $c); # zusätzliche Switch on Bedingung + my $oncom = ConsumerVal ($hash, $c, "oncom", ""); # Set Command für "on" + my $auto = ConsumerVal ($hash, $c, "auto", 1); + my ($swoncond,$info,$err) = isAddSwitchOnCond ($hash, $c); # zusätzliche Switch on Bedingung + + Log3 ($name, 1, "$name - $err") if($err); + + if($debug) { # nur für Debugging + Log (1, qq{DEBUG> $name - Parameters for switch on decision consumer "$c": }. + qq{swoncond: $swoncond, auto mode: $auto, on-command: $oncom, }. + qq{planning state: $pstate, start timestamp: }.($startts ? $startts : "undef").", ". + qq{timestamp: $t} + ); + } if($swoncond && $auto && $oncom && $pstate =~ /planned|priority/xs && $startts && $t >= $startts) { # Verbraucher Start ist geplant && Startzeit überschritten @@ -3418,6 +3437,15 @@ sub __switchConsumer { ## Verbraucher ausschalten ############################ my $offcom = ConsumerVal ($hash, $c, "offcom", ""); # Set Command für "off" + + if($debug) { # nur für Debugging + Log (1, qq{DEBUG> $name - Parameters for switch off decision consumer "$c": }. + qq{auto mode: $auto, off-command: $offcom, }. + qq{planning state: $pstate, stop timestamp: }.($stopts ? $stopts : "undef").", ". + qq{timestamp: $t} + ); + } + if($auto && $offcom && $pstate !~ /switched\soff/xs && $stopts && $t >= $stopts) { # Verbraucher nicht switched off && Stopzeit überschritten CommandSet(undef,"$cname $offcom"); @@ -6134,7 +6162,14 @@ sub calcPVforecast { $data{$type}{$name}{current}{allstringspeak} = $peaksum; # insgesamt installierte Peakleistung in W $pvsum *= $hc; # Korrekturfaktor anwenden - $pvsum = $peaksum if($pvsum > $peaksum); + $pvsum = $peaksum if($pvsum > $peaksum); # Vorhersage nicht größer als die Summe aller PV-Strings Peak + + my $invcapacity = CurrentVal ($hash, "invertercapacity", 0); # Max. Leistung des Invertrs + + if ($invcapacity && $pvsum > $invcapacity) { + $pvsum = $invcapacity + ($invcapacity * 0.01); # PV Vorhersage auf WR Kapazität zzgl. 1% begrenzen + Log3 ($name, 4, "$name - PV forecast limited to $pvsum Watt due to inverter capacity"); + } my $logao = qq{}; $paref->{pvsum} = $pvsum; @@ -7148,18 +7183,23 @@ return; ################################################################ # Funktion liefert "1" wenn die zusätzliche Einschaltbedingung # aus dem Schlüssel "swoncond" im Consumer Attribut wahr ist +# +# +# +# ################################################################ sub isAddSwitchOnCond { my $hash = shift; - my $c = shift; + my $c = shift; + + my $info = q{}; + my $err = q{}; my $dswoncond = ConsumerVal ($hash, $c, "dswoncond", ""); # Device zur Lieferung einer zusätzlichen Einschaltbedingung if($dswoncond && !$defs{$dswoncond}) { - my $name = $hash->{NAME}; - my $err = qq{ERROR - the device "$dswoncond" doesn't exist! Check the key "swoncond" in attribute "consumer${c}"}; - Log3 ($name, 1, "$name - $err"); - return; + $err = qq{ERROR - the device "$dswoncond" doesn't exist! Check the key "swoncond" in attribute "consumer${c}"}; + return (0, $info, $err); } my $rswoncond = ConsumerVal ($hash, $c, "rswoncond", ""); # Reading zur Lieferung einer zusätzlichen Einschaltbedingung @@ -7167,10 +7207,12 @@ sub isAddSwitchOnCond { my $condstate = ReadingsVal ($dswoncond, $rswoncond, ""); if ($condstate =~ m/^$swoncondregex$/x) { - return 1; + return (1, $info, $err); } + + $info = qq{The device "$dswoncond", reading "$rswoncond" doen't match the Regex "$swoncondregex"}; -return; +return (0, $info, $err); } ############################################################################### @@ -7359,6 +7401,7 @@ return $def; # powerbatout - Batterie Entladeleistung # temp - aktuelle Außentemperatur # tomorrowconsumption - Verbrauch des kommenden Tages +# invertercapacity - Bemessungsleistung der Wechselrichters (max. W) # $def: Defaultwert # ############################################################################# @@ -7401,6 +7444,7 @@ return $def; # upcurr - Unit des aktuellen Verbrauchs # avgenergy - initialer / gemessener Durchschnittsverbrauch # eines Tages +# avgruntime - durchschnittliche Einschalt- bzw. Zykluszeit (Minuten) # epieces - prognostizierte Energiescheiben (Hash) # isConsumptionRecommended - ist Verbrauch empfohlen ? # dswoncond - Device zur Lieferung einer zusätzliche Einschaltbedingung @@ -7590,12 +7634,13 @@ Ein/Ausschaltzeiten sowie deren Ausführung vom SolarForecast Modul übernehmen @@ -8177,9 +8223,9 @@ Ein/Ausschaltzeiten sowie deren Ausführung vom SolarForecast Modul übernehmen Ist der Schüssel "auto" definiert, kann der Automatikmodus in der integrierten Verbrauchergrafik mit den entsprechenden Drucktasten umgeschaltet werden. Das angegebene Reading wird ggf. im Consumer Device angelegt falls es nicht vorhanden ist.
- Mit dem optionalen Schlüssel "swoncond" kann eine zusätzliche externe Bedingung definiert werden um den Einschaltvorgang des - Consumers freizugeben. Ist die Bedingung (Regex) nicht erfüllt, erfolgt kein Einschalten des Verbrauchers auch die - sonstigen Voraussetzungen wie Auto-Planung, mode, vorhandene PV-Leistung usw. gegeben sind. + Mit dem optionalen Schlüssel swoncond kann eine zusätzliche externe Bedingung definiert werden um den Einschaltvorgang des + Consumers freizugeben. Ist die Bedingung (Regex) nicht erfüllt, erfolgt kein Einschalten des Verbrauchers auch wenn die + sonstigen Voraussetzungen wie Zeitplanung, mode, vorhandene PV-Leistung usw. gegeben sind.