From 1af9f6642d1b58f4d8d8781e3b6caa66a8827521 Mon Sep 17 00:00:00 2001 From: nasseeder1 Date: Wed, 27 Jan 2021 17:02:18 +0000 Subject: [PATCH] 76_SolarForecast.pm: contrib 0.6.0 git-svn-id: https://svn.fhem.de/fhem/trunk@23627 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/DS_Starter/76_SolarForecast.pm | 176 +++++--------------- 1 file changed, 44 insertions(+), 132 deletions(-) diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm index 135e3819c..37d53b9ba 100644 --- a/fhem/contrib/DS_Starter/76_SolarForecast.pm +++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm @@ -116,6 +116,7 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "0.6.0" => "27.01.2021 change calcPVforecast from formula 1 to formula 2 ", "0.5.0" => "25.01.2021 add multistring support, add reset inverterStrings ", "0.4.0" => "24.01.2021 setter moduleDirection, add Area factor to calcPVforecast, add reset pvCorrection ", "0.3.0" => "21.01.2021 add cloud correction, add rain correction, add reset pvHistory, setter writeHistory ", @@ -127,9 +128,7 @@ my %vNotesIntern = ( my %hset = ( # Hash der Set-Funktion currentForecastDev => { fn => \&_setcurrentForecastDev }, - moduleArea => { fn => \&_setmoduleArea }, - moduleEfficiency => { fn => \&_setmoduleEfficiency }, - inverterEfficiency => { fn => \&_setinverterEfficiency }, + modulePeakString => { fn => \&_setmodulePeakString }, inverterStrings => { fn => \&_setinverterStrings }, currentInverterDev => { fn => \&_setinverterDevice }, currentMeterDev => { fn => \&_setmeterDevice }, @@ -450,10 +449,8 @@ sub Set { "currentForecastDev:$fcd ". "currentInverterDev:textField-long ". "currentMeterDev:textField-long ". - "inverterEfficiency ". "inverterStrings ". - "moduleArea ". - "moduleEfficiency ". + "modulePeakString ". "moduleTiltAngle ". "moduleDirection ". "pvCorrectionFactor_Auto:on,off ". @@ -576,60 +573,29 @@ return; } ################################################################ -# Setter moduleArea +# Setter modulePeakString ################################################################ -sub _setmoduleArea { ## no critic "not used" +sub _setmodulePeakString { ## no critic "not used" my $paref = shift; my $hash = $paref->{hash}; my $name = $paref->{name}; - my $arg = $paref->{arg} // return qq{no PV module area specified}; + my $arg = $paref->{arg} // return qq{no PV module peak specified}; $arg =~ s/,/./xg; my ($a,$h) = parseParams ($arg); if(!keys %$h) { - return qq{The provided PV module area has wrong format}; + return qq{The provided PV module peak has wrong format}; } while (my ($key, $value) = each %$h) { if($value !~ /[0-9.]/x) { - return qq{The module area of "$key" must be specified by numbers and optionally with decimal places}; + return qq{The module peak of "$key" must be specified by numbers and optionally with decimal places}; } } - readingsSingleUpdate($hash, "moduleArea", $arg, 1); - - my $ret = createStringConfig ($hash); - return $ret if($ret); - -return; -} - -################################################################ -# Setter moduleEfficiency -################################################################ -sub _setmoduleEfficiency { ## no critic "not used" - my $paref = shift; - my $hash = $paref->{hash}; - my $name = $paref->{name}; - my $arg = $paref->{arg} // return qq{no PV module efficiency specified}; - - my ($a,$h) = parseParams ($arg); - - if(!keys %$h) { - return qq{The provided PV module efficiency has wrong format}; - } - - $arg =~ s/,/./xg; - - while (my ($key, $value) = each %$h) { - if($value !~ /[0-9.]/x) { - return qq{The module efficiency of "$key" must be specified by numbers and optionally with decimal places}; - } - } - - readingsSingleUpdate($hash, "moduleEfficiency", $arg, 1); + readingsSingleUpdate($hash, "modulePeakString", $arg, 1); my $ret = createStringConfig ($hash); return $ret if($ret); @@ -699,26 +665,6 @@ sub _setmoduleDirection { ## no critic "not used" return; } -################################################################ -# Setter inverterEfficiency -################################################################ -sub _setinverterEfficiency { ## no critic "not used" - my $paref = shift; - my $hash = $paref->{hash}; - my $name = $paref->{name}; - my $prop = $paref->{prop} // return qq{no inverter efficiency specified}; - - if($prop !~ /[0-9,.]/x) { - return qq{The inverter efficiency must be specified by numbers and optionally with decimal places}; - } - - $prop =~ s/,/./x; - - readingsSingleUpdate($hash, "inverterEfficiency", $prop, 1); - -return; -} - ################################################################ # Setter pvCorrectionFactor ################################################################ @@ -1114,27 +1060,15 @@ sub createStringConfig { ## no critic "not used" } } - my $area = ReadingsVal ($name, "moduleArea", ""); # Modul Fläche für jeden Stringbezeichner - my ($aa,$ha) = parseParams ($area); + my $peak = ReadingsVal ($name, "modulePeakString", ""); # kWp für jeden Stringbezeichner + my ($aa,$ha) = parseParams ($peak); while (my ($key, $value) = each %$ha) { if ($key ~~ @istrings) { - $data{$type}{$name}{strings}{"$key"}{area} = $value; + $data{$type}{$name}{strings}{"$key"}{peak} = $value; } else { - return qq{Check "moduleArea" -> the stringname "$key" is not defined as valid string in reading "inverterStrings"}; - } - } - - my $effi = ReadingsVal ($name, "moduleEfficiency", ""); # Modul Effizienz für jeden Stringbezeichner - my ($ae,$he) = parseParams ($effi); - - while (my ($key, $value) = each %$he) { - if ($key ~~ @istrings) { - $data{$type}{$name}{strings}{"$key"}{effi} = $value; - } - else { - return qq{Check "moduleEfficiency" -> the stringname "$key" is not defined as valid string in reading "inverterStrings"}; + return qq{Check "modulePeakString" -> the stringname "$key" is not defined as valid string in reading "inverterStrings"}; } } @@ -1151,7 +1085,7 @@ sub createStringConfig { ## no critic "not used" } if(!keys %{$data{$type}{$name}{strings}}) { - return qq{The string configuration is empty.\nPlease check the settings of inverterStrings, moduleArea, moduleDirection, moduleTiltAngle, moduleEfficiency}; + return qq{The string configuration is empty.\nPlease check the settings of inverterStrings, modulePeakString, moduleDirection, moduleTiltAngle}; } my @sca = keys %{$data{$type}{$name}{strings}}; # Gegencheck ob nicht mehr Strings in inverterStrings enthalten sind als eigentlich verwendet @@ -1580,12 +1514,11 @@ sub forecastGraphic { my $pv0 = ReadingsNum ($name, "ThisHour_PVforecast", undef); my $is = ReadingsVal ($name, "inverterStrings", undef); # String Konfig - my $ma = ReadingsVal ($name, "moduleArea", undef); # Modulfläche Konfig + my $peak = ReadingsVal ($name, "modulePeakString", undef); # String Peak my $dir = ReadingsVal ($name, "moduleDirection", undef); # Modulausrichtung Konfig my $ta = ReadingsVal ($name, "moduleTiltAngle", undef); # Modul Neigungswinkel Konfig - my $eff = ReadingsVal ($name, "moduleEfficiency", undef); # Modul Effizienz Konfig - if(!$is || !$fcdev || !$ma || !defined $pv0 || !$dir || !$ta || !$eff) { + if(!$is || !$fcdev || !$indev || !$peak || !defined $pv0 || !$dir || !$ta) { my $link = qq{$name}; $height = AttrNum($name, 'beamHeight', 200); $ret .= ""; @@ -1601,11 +1534,8 @@ sub forecastGraphic { elsif(!$is) { $ret .= qq{Please define all of your used string names with "set $link inverterStrings".}; } - elsif(!$ma) { - $ret .= qq{Please specify the total module area with "set $link moduleArea"}; - } - elsif(!$eff) { - $ret .= qq{Please specify the module efficiency with "set $link moduleEfficiency"}; + elsif(!$peak) { + $ret .= qq{Please specify the total module peak with "set $link modulePeakString"}; } elsif(!$dir) { $ret .= qq{Please specify the module direction with "set $link moduleDirection"}; @@ -2413,20 +2343,28 @@ return @aneeded; ################################################################################################## # PV Forecast Rad1h in kWh / Wh -# Für die Umrechnung in einen kWh/Wh-Wert benötigt man einen entsprechenden Faktorwert: +# Berechnung nach Formel 1 aus http://www.ing-büro-junge.de/html/photovoltaik.html: # # * Faktor für Umwandlung kJ in kWh: 0.00027778 # * Eigene Modulfläche in qm z.B.: 31,04 # * Wirkungsgrad der Module in % z.B.: 16,52 # * Wirkungsgrad WR in % z.B.: 98,3 -# * Korrekturwerte wegen Ausrichtung/Verschattung: 83% wegen Ost/West und Schatten (Iteration) +# * Korrekturwerte wegen Ausrichtung/Verschattung etc. # # Die Formel wäre dann: -# Ertrag in kWh = Rad1h * 0.00027778 * 31,04 qm * 16,52% * 98,3% * 100% +# Ertrag in Wh = Rad1h * 0.00027778 * 31,04 qm * 16,52% * 98,3% * 100% * 1000 # -# Damit ergibt sich ein Umrechnungsfaktor von: 0,00140019 für kWh / 1,40019 für Wh +# Berechnung nach Formel 2 aus http://www.ing-büro-junge.de/html/photovoltaik.html: # -# Bei einem Rad1h-Wert von 500 ergibt dies bei mir also 0,700095 kWh / 700,095 Wh +# * Globalstrahlung: G = kJ / m2 +# * Korrektur mit Flächenfaktor f: Gk = G * f +# * Globalstrahlung (STC): 1 kW/m2 +# * Peak Leistung String (kWp): Pnenn = x kW +# * Performance Ratio: PR (typisch 0,85 bis 0,9) +# * weitere Korrekturwerte für Regen, Wolken etc.: Korr +# +# pv (kWh) = G * f * 0.00027778 (kWh/m2) / 1 kW/m2 * Pnenn (kW) * PR * Korr +# pv (Wh) = G * f * 0.00027778 (kWh/m2) / 1 kW/m2 * Pnenn (kW) * PR * Korr * 1000 # # Die Abhängigkeit der Strahlungsleistung der Sonnenenergie nach Wetterlage und Jahreszeit ist # hier beschrieben: @@ -2435,8 +2373,6 @@ return @aneeded; # !!! PV Berechnungsgrundlagen !!! # https://www.energie-experten.org/erneuerbare-energien/photovoltaik/planung/ertrag # http://www.ing-büro-junge.de/html/photovoltaik.html -# -> es wird die Berechnung nach Formel 1 aus http://www.ing-büro-junge.de/html/photovoltaik.html -# verwendet # ################################################################################################## sub calcPVforecast { @@ -2447,6 +2383,7 @@ sub calcPVforecast { my $hash = $defs{$name}; my $type = $hash->{TYPE}; my $stch = $data{$type}{$name}{strings}; # String Configuration Hash + my $pr = 1.0; # Performance Ratio (PR) my @strings = sort keys %{$stch}; @@ -2457,31 +2394,29 @@ sub calcPVforecast { my $rcf = 1 - (($rainprob - $rain_base) * $rainslope / 100); # Rain Correction Faktor mit Steilheit my $kw = AttrVal ($name, 'Wh/kWh', 'Wh'); - my $ie = ReadingsNum ($name, "inverterEfficiency", $definve ); # Solar Inverter Wirkungsgrad (%) my $hc = ReadingsNum ($name, "pvCorrectionFactor_".sprintf("%02d",$fh), 1 ); # Korrekturfaktor für die Stunde des Tages my $pvsum = 0; for my $st (@strings) { # für jeden String der Config .. - my $ma = $stch->{"$st"}{area}; # Solar Modulfläche String + my $peak = $stch->{"$st"}{peak}; # String Peak (kWp) my $ta = $stch->{"$st"}{tilt}; # Neigungswinkel Solarmodule my $moddir = $stch->{"$st"}{dir}; # Ausrichtung der Solarmodule - my $me = $stch->{"$st"}{effi}; # Solar Modul Wirkungsgrad (%) my $af = $hff{$ta}{$moddir} / 100; # Flächenfaktor: http://www.ing-büro-junge.de/html/photovoltaik.html $hc = 1 if(1*$hc == 0); - my $pv = sprintf "%.1f", ($rad * $kJtokWh * $ma * $af * $me/100 * $ie/100 * $hc * $ccf * $rcf * 1000); + + # pv (Wh) = G * f * 0.00027778 (kWh/m2) / 1 kW/m2 * Pnenn (kW) * PR * Korr * 1000 + my $pv = sprintf "%.1f", ($rad * $af * $kJtokWh * $peak * $pr * $hc * $ccf * $rcf * 1000); my $lh = { # Log-Hash zur Ausgabe "moduleDirection" => $moddir, - "moduleArea" => $ma, + "modulePeakString" => $peak, "moduleTiltAngle" => $ta, "Area factor" => $af, "Cloudfactor" => $ccf, "Rainfactor" => $rcf, "pvCorrectionFactor" => $hc, - "moduleEfficiency" => $me/100, - "inverterEfficiency" => $ie/100, "Radiation" => $rad, "Factor kJ to kWh" => $kJtokWh, "PV generation (Wh)" => $pv @@ -2557,7 +2492,7 @@ sub calcVariance { my $cdone = ReadingsVal ($name, "pvCorrectionFactor_".sprintf("%02d",$h)."_autocalc", ""); if($cdone eq "done") { - Log3($name, 5, "$name - pvCorrectionFactor Hour: ".sprintf("%02d",$h). "already calculated"); + Log3($name, 5, "$name - pvCorrectionFactor Hour: ".sprintf("%02d",$h). " already calculated"); next; } @@ -2733,12 +2668,12 @@ sub checkStringConfig { my $cf = 0; for my $sn (sort keys %{$stch}) { my $sp = $sn." => ".$sub->($sn)."\n"; - $cf = 1 if($sp !~ /area.*?dir.*?effi.*?tilt/x); # Test Vollständigkeit: z.B. Ostlage => area: 31.04, dir: E, effi: 16.52, tilt: 30 + $cf = 1 if($sp !~ /dir.*?peak.*?tilt/x); # Test Vollständigkeit: z.B. Süddach => dir: S, peak: 5.13, tilt: 45 $sc .= $sp; } if($cf) { - $sc .= "\n\nOh no 🙁, your string configuration is inconsistent.\nPlease check the settings of moduleArea, moduleDirection, moduleEfficiency, moduleTiltAngle !"; + $sc .= "\n\nOh no 🙁, your string configuration is inconsistent.\nPlease check the settings of modulePeakString, moduleDirection, moduleTiltAngle !"; } else { $sc .= "\n\nCongratulations 😊, your string configuration checked without found errors !"; @@ -3006,15 +2941,6 @@ werden weitere SolarForecast Devices zugeordnet.
- - -

- -
-