From 86c39996425250ff4cd0036dfd9a5b0986832f13 Mon Sep 17 00:00:00 2001 From: nasseeder1 Date: Wed, 17 Mar 2021 20:06:19 +0000 Subject: [PATCH] 76_SolarForecast.pm: contrib 0.14.0 git-svn-id: https://svn.fhem.de/fhem/trunk@23990 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/DS_Starter/76_SolarForecast.pm | 230 ++++++++++++++++---- 1 file changed, 192 insertions(+), 38 deletions(-) diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm index e4bed355b..c8d08be0e 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.14.0" => "17.03.2021 new getter PVReal, weatherData, consumtion total in currentMeterdev ", "0.13.0" => "16.03.2021 changed sub forecastGraphic from Wzut ", "0.12.0" => "16.03.2021 switch etoday to etotal ", "0.11.0" => "14.03.2021 new attr history_hour, beam1Content, beam2Content, implement sub forecastGraphic from Wzut, ". @@ -170,6 +171,8 @@ my %hget = ( # Ha html => { fn => \&_gethtml, needcred => 0 }, ftui => { fn => \&_getftui, needcred => 0 }, pvHistory => { fn => \&_getlistPVHistory, needcred => 0 }, + pvReal => { fn => \&_getlistPVReal, needcred => 0 }, + weatherData => { fn => \&_getlistWeather, needcred => 0 }, stringConfig => { fn => \&_getstringConfig, needcred => 0 }, ); @@ -605,7 +608,7 @@ sub _setmeterDevice { ## no critic "not used" return qq{The device "$medev" doesn't exist!}; } - if(!$h->{gcon}) { + if(!$h->{gcon} || !$h->{contotal}) { return qq{The syntax of "$opt" isn't right. Please consider the commandref.}; } @@ -834,7 +837,9 @@ sub Get { "data:noArg ". "html:noArg ". "pvHistory:noArg ". - "stringConfig:noArg " + "pvReal:noArg ". + "stringConfig:noArg ". + "weatherData:noArg " ; return if(IsDisabled($name)); @@ -895,8 +900,41 @@ return pageAsHtml ($hash,"ftui"); sub _getlistPVHistory { my $paref = shift; my $hash = $paref->{hash}; - - my $ret = listPVHistory ($hash); + + my $name = $hash->{NAME}; + my $type = $hash->{TYPE}; + + my $ret = listDataPool ($hash, "pvhist"); + +return $ret; +} + +############################################################### +# Getter listPVReal +############################################################### +sub _getlistPVReal { + my $paref = shift; + my $hash = $paref->{hash}; + + my $name = $hash->{NAME}; + my $type = $hash->{TYPE}; + + my $ret = listDataPool ($hash, "pvreal"); + +return $ret; +} + +############################################################### +# Getter listWeather +############################################################### +sub _getlistWeather { + my $paref = shift; + my $hash = $paref->{hash}; + + my $name = $hash->{NAME}; + my $type = $hash->{TYPE}; + + my $ret = listDataPool ($hash, "weather"); return $ret; } @@ -1438,6 +1476,8 @@ sub _transferInverterValues { 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 + return if(!$pvread || !$edread); + Log3($name, 5, "$name - collect Inverter data: device=$indev, pv=$pvread ($pvunit), etotal=$edread ($etunit)"); my $pvuf = $pvunit =~ /^kW$/xi ? 1000 : 1; @@ -1450,17 +1490,14 @@ sub _transferInverterValues { my $etotal = ReadingsNum ($indev, $edread, 0) * $etuf; # Erzeugung total (Wh) my $edaypast = 0; - # deleteReadingspec ($hash, "Today_Hour00_PVreal"); for my $hour (0..int $chour) { # alle bisherigen Erzeugungen des Tages summieren $edaypast += ReadingsNum ($name, "Today_Hour".sprintf("%02d",$hour)."_PVreal", 0); } my $do = 0; - if ($edaypast == 0) { + if ($edaypast == 0) { # Management der Stundenberechnung auf Basis Totalwerte if (defined $hash->{HELPER}{INITETOTAL}) { - # $edaypast = $hash->{HELPER}{INITETOTAL}; - # $hash->{HELPER}{INITETOTAL} = $etotal; $do = 1; } else { @@ -1508,20 +1545,76 @@ sub _transferMeterValues { my $chour = $paref->{chour}; my $daref = $paref->{daref}; - my $medev = ReadingsVal($name, "currentMeterDev", ""); # aktuelles Meter device + my $medev = ReadingsVal($name, "currentMeterDev", ""); # aktuelles Meter device my ($a,$h) = parseParams ($medev); $medev = $a->[0] // ""; return if(!$medev || !$defs{$medev}); - my ($gc,$gcunit) = split ":", $h->{gcon}; # Readingname/Unit für aktuellen Netzbezug + my $tlim = "23"; # Stunde 23 -> bestimmte Aktionen + my $type = $hash->{TYPE}; - Log3($name, 5, "$name - collect Meter data: device=$medev, gcon=$gc ($gcunit)"); + if($chour =~ /^($tlim)$/x) { + deleteReadingspec ($hash, "Today_Hour.*_Consumption"); + delete $hash->{HELPER}{INITCONTOTAL}; + } + + my ($gc,$gcunit) = split ":", $h->{gcon}; # Readingname/Unit für aktuellen Netzbezug + my ($gt,$ctunit) = split ":", $h->{contotal}; # Readingname/Unit für Bezug total + + return if(!$gc || !$gt); + + Log3($name, 5, "$name - collect Meter data: device=$medev, gcon=$gc ($gcunit), contotal=$gt ($ctunit)"); my $gcuf = $gcunit =~ /^kW$/xi ? 1000 : 1; - my $co = ReadingsNum ($medev, $gc, 0) * $gcuf; # aktueller Bezug (-) oder Einspeisung - + my $co = ReadingsNum ($medev, $gc, 0) * $gcuf; # aktueller Bezug (W) + push @$daref, "Current_GridConsumption:".$co." W"; - $data{$hash->{TYPE}}{$name}{current}{consumption} = $co; # Hilfshash Wert current grid consumption Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251 + $data{$type}{$name}{current}{consumption} = $co; # Hilfshash Wert current grid consumption Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251 + + my $ctuf = $ctunit =~ /^kWh$/xi ? 1000 : 1; + my $gctotal = ReadingsNum ($medev, $gt, 0) * $ctuf; # Bezug total (Wh) + + my $cdaypast = 0; + + for my $hour (0..int $chour) { # alle bisherigen Erzeugungen des Tages summieren + $cdaypast += ReadingsNum ($name, "Today_Hour".sprintf("%02d",$hour)."_Consumption", 0); + } + + my $do = 0; + if ($cdaypast == 0) { # Management der Stundenberechnung auf Basis Totalwerte + if (defined $hash->{HELPER}{INITCONTOTAL}) { + $do = 1; + } + else { + $hash->{HELPER}{INITCONTOTAL} = $gctotal; + } + } + elsif (!defined $hash->{HELPER}{INITCONTOTAL}) { + $hash->{HELPER}{INITCONTOTAL} = $gctotal-$cdaypast-ReadingsNum($name, "Today_Hour".sprintf("%02d",$chour+1)."_Consumption", 0); + } + else { + $do = 1; + } + + if ($do) { + my $gctotthishour = int ($gctotal - ($cdaypast + $hash->{HELPER}{INITCONTOTAL})); + + # Log3($name, 1, "$name - gctotal: $gctotal, cdaypast: $cdaypast, HELPER: $hash->{HELPER}{INITCONTOTAL}, gctotthishour: $gctotthishour "); + + if($gctotthishour < 0) { + $gctotthishour = 0; + } + + my $nhour = $chour+1; + push @$daref, "Today_Hour".sprintf("%02d",$nhour)."_Consumption:".$gctotthishour." Wh"; + $data{$type}{$name}{consumption}{sprintf("%02d",$nhour)} = $gctotthishour; # Hilfshash Wert Bezug (Wh) Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350 + + $paref->{gctotthishour} = $gctotthishour; + $paref->{nhour} = sprintf("%02d",$nhour); + $paref->{histname} = "cons"; + setPVhistory ($paref); + delete $paref->{histname}; + } return; } @@ -2817,9 +2910,10 @@ sub setPVhistory { my $t = $paref->{t}; # aktuelle Unix-Zeit my $nhour = $paref->{nhour}; my $day = $paref->{day}; - my $histname = $paref->{histname} // qq{}; - my $ethishour = $paref->{ethishour} // 0; - my $calcpv = $paref->{calcpv} // 0; + my $histname = $paref->{histname} // qq{}; + my $ethishour = $paref->{ethishour} // 0; + my $calcpv = $paref->{calcpv} // 0; + my $gthishour = $paref->{gctotthishour} // 0; my $type = $hash->{TYPE}; my $val = q{}; @@ -2848,42 +2942,80 @@ sub setPVhistory { $data{$type}{$name}{pvhist}{$day}{99}{pvfc} = $pvfcsum; } + if($histname eq "cons") { # bezogene Energie + $val = $gthishour; + $data{$type}{$name}{pvhist}{$day}{$nhour}{cons} = $gthishour; + + my $gcsum = 0; + for my $k (keys %{$data{$type}{$name}{pvhist}{$day}}) { + next if($k eq "99"); + $gcsum += $data{$type}{$name}{pvhist}{$day}{$k}{cons} // 0; + } + $data{$type}{$name}{pvhist}{$day}{99}{cons} = $gcsum; + } + Log3 ($name, 5, "$name - set PV History hour: $nhour, hash: $histname, val: $val"); return; } ################################################################ -# liefert aktuelle Einträge des PV Cache +# liefert aktuelle Einträge des in $htol +# angegebenen internen Hash ################################################################ -sub listPVHistory { +sub listDataPool { my $hash = shift; + my $htol = shift; my $name = $hash->{NAME}; my $type = $hash->{TYPE}; - my $pvhh = $data{$type}{$name}{pvhist}; - # Log3 ($name, 5, "$name - PV History content: ".Dumper $pvhh); + my ($sq,$h); my $sub = sub { my $day = shift; my $ret; - for my $key (sort{$a<=>$b} keys %{$pvhh->{$day}}) { - my $pvrl = $pvhh->{$day}{$key}{pvrl} // 0; - my $pvfc = $pvhh->{$day}{$key}{pvfc} // 0; + for my $key (sort{$a<=>$b} keys %{$h->{$day}}) { + my $pvrl = $h->{$day}{$key}{pvrl} // 0; + my $pvfc = $h->{$day}{$key}{pvfc} // 0; + my $cons = $h->{$day}{$key}{cons} // 0; $ret .= "\n " if($ret); - $ret .= $key." => pvreal: $pvrl, pvforecast: $pvfc"; + $ret .= $key." => pvreal: $pvrl, pvforecast: $pvfc, consumption: $cons"; } return $ret; }; - - if (!keys %{$pvhh}) { - return qq{PV cache is empty.}; + + if ($htol eq "pvhist") { + $h = $data{$type}{$name}{pvhist}; + if (!keys %{$h}) { + return qq{PV cache is empty.}; + } + for my $idx (reverse sort{$a<=>$b} keys %{$h}) { + $sq .= $idx." => ".$sub->($idx)."\n"; + } } - my $sq; - for my $idx (reverse sort{$a<=>$b} keys %{$pvhh}) { - $sq .= $idx." => ".$sub->($idx)."\n"; + if ($htol eq "weather") { + $h = $data{$hash->{TYPE}}{$name}{weather}; + if (!keys %{$h}) { + return qq{Weather cache is empty.}; + } + for my $idx (sort{$a<=>$b} keys %{$h}) { + $sq .= $idx." => id: ".$data{$hash->{TYPE}}{$name}{weather}{$idx}{id}. "\n"; + $sq .= " => txt: " .$data{$hash->{TYPE}}{$name}{weather}{$idx}{txt}. "\n"; + $sq .= " => cloudcover: " .$data{$hash->{TYPE}}{$name}{weather}{$idx}{cloudcover}."\n"; + $sq .= " => rainprob: " .$data{$hash->{TYPE}}{$name}{weather}{$idx}{rainprob}. "\n"; + } + } + + if ($htol eq "pvreal") { + $h = $data{$type}{$name}{pvreal}; + if (!keys %{$h}) { + return qq{PV real cache is empty.}; + } + for my $idx (sort{$a<=>$b} keys %{$h}) { + $sq .= $idx." => ".$data{$type}{$name}{pvreal}{$idx}."\n"; + } } return $sq; @@ -2991,6 +3123,9 @@ return $timestamp; # $daref: Referenz zum Array der zu erstellenden Readings # muß Paare : enthalten # $doevt: 1-Events erstellen, 0-keine Events erstellen +# +# readingsBulkUpdate($hash,$reading,$value,$changed,$timestamp) +# ################################################################ sub createReadingsFromArray { my $hash = shift; @@ -3158,7 +3293,7 @@ werden weitere SolarForecast Devices zugeordnet.
    -
  • currentInverterDev <Inverter Device Name> pv=<Reading aktuelle PV-Leistung>:<Einheit> etotal=<Reading Energieerzeugung total>:<Einheit>
    +
  • currentInverterDev <Inverter Device Name> pv=<Reading aktuelle PV-Leistung>:<Einheit> etotal=<Reading Summe Energieerzeugung>:<Einheit>
    Legt ein beliebiges Device zur Lieferung der aktuellen PV Erzeugungswerte fest.
    @@ -3184,23 +3319,24 @@ werden weitere SolarForecast Devices zugeordnet.
      -
    • currentMeterDev <Meter Device Name> gcon=<Reading aktueller Netzbezug>:<Einheit>
      - Legt ein beliebiges Device zur Messung des aktuellen Energiebezugs fest. +
    • currentMeterDev <Meter Device Name> gcon=<Reading aktueller Netzbezug>:<Einheit> contotal=<Reading Summe Netzbezug>:<Einheit>
      + Legt ein beliebiges Device zur Messung des Energiebezugs fest.
        - - + + +
        gcon Reading welches die aktuell aus dem Netz bezogene Leistung liefert
        Einheit die jeweilige Einheit (W,kW)
        gcon Reading welches die aktuell aus dem Netz bezogene Leistung liefert
        contotal Reading welches die Summe der aus dem Netz bezogenen Energie liefert
        Einheit die jeweilige Einheit (W,kW,Wh,kWh)

        Beispiel:
        - set <name> currentMeterDev SMA_Energymeter gcon=Bezug_Wirkleistung:W
        - # Device SMA_Energymeter liefert den aktuellen Netzbezug im Reading "Bezug_Wirkleistung" (W) + set <name> currentMeterDev SMA_Energymeter gcon=Bezug_Wirkleistung:W contotal=Bezug_Wirkleistung_Zaehler:kWh
        + # Device SMA_Energymeter liefert den aktuellen Netzbezug im Reading "Bezug_Wirkleistung" (W) und den totalen Bezug im Reading "Bezug_Wirkleistung_Zaehler" (kWh)
    @@ -3349,6 +3485,24 @@ werden weitere SolarForecast Devices zugeordnet.

+
    + +
  • pvReal
    + Listet die ermittelten PV Werte des Ringwertzählers der letzten 24h auf. Die Stundenangaben beziehen sich auf die Stunde + des Tages, z.B. Stunde 09 ist die Zeit von 08:00-09:00. +
  • +
+
+ +
    + +
  • weatherData
    + Listet die ermittelten Wetterdaten des Ringwertzählers der letzten 24h auf. Die Stundenangaben beziehen sich auf den + Beginn der Stunde, z.B. bezieht sich die Angabe 09 auf die Zeit von 09:00-10:00. +
  • +
+
+