diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm index 600665063..46508d62d 100644 --- a/fhem/contrib/DS_Starter/76_SolarForecast.pm +++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm @@ -136,6 +136,8 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "0.79.3" => "21.05.2023 new CircularVal initdayfeedin, deactivate \$hash->{HELPER}{INITFEEDTOTAL} ". + "new statistic Reading statistic_todayGridFeedIn ", "0.79.2" => "21.05.2023 change process to calculate solCastAPIcallMultiplier, todayMaxAPIcalls ", "0.79.1" => "19.05.2023 extend debug solcastProcess, new key solcastAPIcall ", "0.79.0" => "13.05.2023 new consumer key locktime ", @@ -794,22 +796,23 @@ my %hef = ( "washingmachine" => { f => 0.50, m => 0.30, l => 0.40, mt => 120 }, ); -my %hcsr = ( # Funktiontemplate zur Erstellung optionaler Statistikreadings - currentAPIinterval => { fnr => 1, fn => \&SolCastAPIVal, def => 0 }, - lastretrieval_time => { fnr => 1, fn => \&SolCastAPIVal, def => '-' }, - lastretrieval_timestamp => { fnr => 1, fn => \&SolCastAPIVal, def => '-' }, - response_message => { fnr => 1, fn => \&SolCastAPIVal, def => '-' }, - todayMaxAPIcalls => { fnr => 1, fn => \&SolCastAPIVal, def => 'apimaxreq' }, - todayDoneAPIcalls => { fnr => 1, fn => \&SolCastAPIVal, def => 0 }, - todayDoneAPIrequests => { fnr => 1, fn => \&SolCastAPIVal, def => 0 }, - todayRemainingAPIcalls => { fnr => 1, fn => \&SolCastAPIVal, def => 'apimaxreq' }, - todayRemainingAPIrequests => { fnr => 1, fn => \&SolCastAPIVal, def => 'apimaxreq' }, - runTimeCentralTask => { fnr => 2, fn => \&CurrentVal, def => '-' }, - runTimeLastAPIAnswer => { fnr => 2, fn => \&CurrentVal, def => '-' }, - runTimeLastAPIProc => { fnr => 2, fn => \&CurrentVal, def => '-' }, - allStringsFullfilled => { fnr => 2, fn => \&CurrentVal, def => 0 }, - SunHours_Remain => { fnr => 3, fn => \&CurrentVal, def => 0 }, # fnr => 3 -> Custom Calc - SunMinutes_Remain => { fnr => 3, fn => \&CurrentVal, def => 0 }, +my %hcsr = ( # Funktiontemplate zur Erstellung optionaler Statistikreadings + currentAPIinterval => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => 0 }, # par = Parameter zur spezifischen Verwendung + lastretrieval_time => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => '-' }, + lastretrieval_timestamp => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => '-' }, + response_message => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => '-' }, + todayMaxAPIcalls => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => 'apimaxreq' }, + todayDoneAPIcalls => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => 0 }, + todayDoneAPIrequests => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => 0 }, + todayRemainingAPIcalls => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => 'apimaxreq' }, + todayRemainingAPIrequests => { fnr => 1, fn => \&SolCastAPIVal, par => '', def => 'apimaxreq' }, + runTimeCentralTask => { fnr => 2, fn => \&CurrentVal, par => '', def => '-' }, + runTimeLastAPIAnswer => { fnr => 2, fn => \&CurrentVal, par => '', def => '-' }, + runTimeLastAPIProc => { fnr => 2, fn => \&CurrentVal, par => '', def => '-' }, + allStringsFullfilled => { fnr => 2, fn => \&CurrentVal, par => '', def => 0 }, + SunHours_Remain => { fnr => 3, fn => \&CurrentVal, par => '', def => 0 }, # fnr => 3 -> Custom Calc + SunMinutes_Remain => { fnr => 3, fn => \&CurrentVal, par => '', def => 0 }, + todayGridFeedIn => { fnr => 3, fn => \&CircularVal, par => 99, def => 0 }, ); # Information zu verwendeten internen Datenhashes @@ -1866,7 +1869,9 @@ sub _setreset { ## no critic "not used" readingsDelete($hash, "Current_GridConsumption"); readingsDelete($hash, "Current_GridFeedIn"); delete $hash->{HELPER}{INITCONTOTAL}; - delete $hash->{HELPER}{INITFEEDTOTAL}; + # delete $hash->{HELPER}{INITFEEDTOTAL}; + delete $data{$type}{$name}{circular}{99}{initdayfeedin}; + delete $data{$type}{$name}{circular}{99}{feedintotal}; delete $data{$type}{$name}{current}{gridconsumption}; delete $data{$type}{$name}{current}{tomorrowconsumption}; delete $data{$type}{$name}{current}{gridfeedin}; @@ -3194,6 +3199,7 @@ sub centralTask { #delete $data{$type}{$name}{solcastapi}{'#All'}; #delete $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todaySolCastAPIcalls}; delete $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayRemaingAPIcalls}; + delete $data{$type}{$name}{circular}{99}{initgridfeedintotal}; for my $n (1..24) { $n = sprintf "%02d", $n; @@ -3519,12 +3525,13 @@ sub _specialActivities { } delete $hash->{HELPER}{INITCONTOTAL}; - delete $hash->{HELPER}{INITFEEDTOTAL}; + # delete $hash->{HELPER}{INITFEEDTOTAL}; delete $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIrequests}; delete $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIcalls}; delete $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayRemainingAPIrequests}; delete $data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayRemainingAPIcalls}; + delete $data{$type}{$name}{circular}{99}{initdayfeedin}; delete $data{$type}{$name}{current}{sunriseToday}; delete $data{$type}{$name}{current}{sunriseTodayTs}; delete $data{$type}{$name}{current}{sunsetToday}; @@ -4496,7 +4503,7 @@ sub _transferMeterValues { ($gfin,$gco) = substSpecialCases ($params); } - if ($gf eq "-gcon") { # Spezialfall gfeedin bei neg. gcon + if ($gf eq "-gcon") { # Spezialfall gfeedin bei neg. gcon $params = { dev => $medev, rdg => $gc, @@ -4507,16 +4514,18 @@ sub _transferMeterValues { } push @$daref, "Current_GridConsumption<>".(int $gco)." W"; - $data{$type}{$name}{current}{gridconsumption} = int $gco; # Hilfshash Wert current grid consumption Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251 + $data{$type}{$name}{current}{gridconsumption} = int $gco; # Hilfshash Wert current grid consumption Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251 push @$daref, "Current_GridFeedIn<>".(int $gfin)." W"; - $data{$type}{$name}{current}{gridfeedin} = int $gfin; # Hilfshash Wert current grid Feed in + $data{$type}{$name}{current}{gridfeedin} = int $gfin; # Hilfshash Wert current grid Feed in my $ctuf = $ctunit =~ /^kWh$/xi ? 1000 : 1; - my $gctotal = ReadingsNum ($medev, $gt, 0) * $ctuf; # Bezug total (Wh) + my $gctotal = ReadingsNum ($medev, $gt, 0) * $ctuf; # Bezug total (Wh) my $ftuf = $ftunit =~ /^kWh$/xi ? 1000 : 1; - my $fitotal = ReadingsNum ($medev, $ft, 0) * $ftuf; # Einspeisung total (Wh) + my $fitotal = ReadingsNum ($medev, $ft, 0) * $ftuf; # Einspeisung total (Wh) + + $data{$type}{$name}{circular}{99}{feedintotal} = $fitotal; # Total Feedin speichern my $debug = $paref->{debug}; if($debug =~ /collectData/x) { @@ -4533,6 +4542,7 @@ sub _transferMeterValues { } my $docon = 0; + if ($gcdaypast == 0) { # Management der Stundenberechnung auf Basis Totalwerte GridConsumtion if (defined $hash->{HELPER}{INITCONTOTAL}) { $docon = 1; @@ -4542,7 +4552,7 @@ sub _transferMeterValues { } } elsif (!defined $hash->{HELPER}{INITCONTOTAL}) { - $hash->{HELPER}{INITCONTOTAL} = $gctotal-$gcdaypast-ReadingsNum($name, "Today_Hour".sprintf("%02d",$chour+1)."_GridConsumption", 0); + $hash->{HELPER}{INITCONTOTAL} = $gctotal-$gcdaypast-ReadingsNum ($name, "Today_Hour".sprintf("%02d",$chour+1)."_GridConsumption", 0); } else { $docon = 1; @@ -4567,23 +4577,26 @@ sub _transferMeterValues { } my $dofeed = 0; + if ($gfdaypast == 0) { # Management der Stundenberechnung auf Basis Totalwerte GridFeedIn - if (defined $hash->{HELPER}{INITFEEDTOTAL}) { + if (defined CircularVal ($hash, 99, 'initdayfeedin', undef)) { $dofeed = 1; } else { - $hash->{HELPER}{INITFEEDTOTAL} = $fitotal; + # $hash->{HELPER}{INITFEEDTOTAL} = $fitotal; + $data{$type}{$name}{circular}{99}{initdayfeedin} = $fitotal; } } - elsif (!defined $hash->{HELPER}{INITFEEDTOTAL}) { - $hash->{HELPER}{INITFEEDTOTAL} = $fitotal-$gfdaypast-ReadingsNum($name, "Today_Hour".sprintf("%02d",$chour+1)."_GridFeedIn", 0); + elsif (!defined CircularVal ($hash, 99, 'initdayfeedin', undef)) { + # $hash->{HELPER}{INITFEEDTOTAL} = $fitotal - $gfdaypast - ReadingsNum ($name, "Today_Hour".sprintf("%02d",$chour+1)."_GridFeedIn", 0); + $data{$type}{$name}{circular}{99}{initdayfeedin} = $fitotal - $gfdaypast - ReadingsNum ($name, "Today_Hour".sprintf("%02d",$chour+1)."_GridFeedIn", 0); } else { $dofeed = 1; } if ($dofeed) { - my $gftotthishour = int ($fitotal - ($gfdaypast + $hash->{HELPER}{INITFEEDTOTAL})); + my $gftotthishour = int ($fitotal - ($gfdaypast + CircularVal ($hash, 99, 'initdayfeedin', 0))); if($gftotthishour < 0) { $gftotthishour = 0; @@ -6521,6 +6534,15 @@ sub genStatisticReadings { push @$daref, 'statistic_'.$kpi.'<>'. sprintf "%.0f", $smr; } + + if ($kpi eq 'todayGridFeedIn') { + my $idfi = &{$hcsr{$kpi}{fn}} ($hash, $hcsr{$kpi}{par}, 'initdayfeedin', $def); # initialer Tagesstartwert + my $cfi = &{$hcsr{$kpi}{fn}} ($hash, $hcsr{$kpi}{par}, 'feedintotal', $def); # aktuelles total Feed In + + my $dfi = $cfi - $idfi; + + push @$daref, 'statistic_'.$kpi.'<>'. (sprintf "%.1f", $dfi).' Wh'; + } } } @@ -9528,22 +9550,23 @@ sub listDataPool { return qq{Circular cache is empty.}; } for my $idx (sort keys %{$h}) { - my $pvfc = CircularVal ($hash, $idx, "pvfc", "-"); - my $pvrl = CircularVal ($hash, $idx, "pvrl", "-"); - my $confc = CircularVal ($hash, $idx, "confc", "-"); - my $gcons = CircularVal ($hash, $idx, "gcons", "-"); - my $gfeedin = CircularVal ($hash, $idx, "gfeedin", "-"); - my $wid = CircularVal ($hash, $idx, "weatherid", "-"); - my $wtxt = CircularVal ($hash, $idx, "weathertxt", "-"); - my $wccv = CircularVal ($hash, $idx, "wcc", "-"); - my $wrprb = CircularVal ($hash, $idx, "wrp", "-"); - my $temp = CircularVal ($hash, $idx, "temp", "-"); - my $pvcorrf = CircularVal ($hash, $idx, "pvcorrf", "-"); - my $quality = CircularVal ($hash, $idx, "quality", "-"); - my $batin = CircularVal ($hash, $idx, "batin", "-"); - my $batout = CircularVal ($hash, $idx, "batout", "-"); - my $tdayDvtn = CircularVal ($hash, $idx, "tdayDvtn", "-"); - my $ydayDvtn = CircularVal ($hash, $idx, "ydayDvtn", "-"); + my $pvfc = CircularVal ($hash, $idx, "pvfc", "-"); + my $pvrl = CircularVal ($hash, $idx, "pvrl", "-"); + my $confc = CircularVal ($hash, $idx, "confc", "-"); + my $gcons = CircularVal ($hash, $idx, "gcons", "-"); + my $gfeedin = CircularVal ($hash, $idx, "gfeedin", "-"); + my $wid = CircularVal ($hash, $idx, "weatherid", "-"); + my $wtxt = CircularVal ($hash, $idx, "weathertxt", "-"); + my $wccv = CircularVal ($hash, $idx, "wcc", "-"); + my $wrprb = CircularVal ($hash, $idx, "wrp", "-"); + my $temp = CircularVal ($hash, $idx, "temp", "-"); + my $pvcorrf = CircularVal ($hash, $idx, "pvcorrf", "-"); + my $quality = CircularVal ($hash, $idx, "quality", "-"); + my $batin = CircularVal ($hash, $idx, "batin", "-"); + my $batout = CircularVal ($hash, $idx, "batout", "-"); + my $tdayDvtn = CircularVal ($hash, $idx, "tdayDvtn", "-"); + my $ydayDvtn = CircularVal ($hash, $idx, "ydayDvtn", "-"); + my $idfi = CircularVal ($hash, $idx, "initdayfeedin", "-"); my $pvcf = qq{}; if(ref $pvcorrf eq "HASH") { @@ -9581,7 +9604,7 @@ sub listDataPool { $sq .= " quality: $cfq"; } else { - $sq .= $idx." => tdayDvtn: $tdayDvtn, ydayDvtn: $ydayDvtn"; + $sq .= $idx." => tdayDvtn: $tdayDvtn, ydayDvtn: $ydayDvtn, initdayfeedin: $idfi"; } } } @@ -10804,7 +10827,7 @@ sub HistoryVal { return $def; } -############################################################################# +##################################################################################################### # Wert des circular-Hash zurückliefern # Achtung: die Werte im circular-Hash haben nicht # zwingend eine Beziehung zueinander !! @@ -10812,7 +10835,7 @@ return $def; # Usage: # CircularVal ($hash, $hod, $key, $def) # -# $hod: Stunde des Tages (01,02,...,24) +# $hod: Stunde des Tages (01,02,...,24) bzw. 99 (besondere Verwendung) # $key: pvrl - realer PV Ertrag # pvfc - PV Vorhersage # confc - Vorhersage Hausverbrauch (Wh) @@ -10826,11 +10849,14 @@ return $def; # wrp - DWD Regenwahrscheinlichkeit # temp - Außentemperatur # pvcorrf - PV Autokorrekturfaktoren (HASH) -# tdayDvtn - heutige Abweichung PV Prognose/Erzeugung in % -# ydayDvtn - gestrige Abweichung PV Prognose/Erzeugung in % +# +# tdayDvtn - heutige Abweichung PV Prognose/Erzeugung in % +# ydayDvtn - gestrige Abweichung PV Prognose/Erzeugung in % +# initdayfeedin - initialer Wert für "gridfeedin" zu Beginn des Tages (Wh) +# # $def: Defaultwert # -############################################################################# +##################################################################################################### sub CircularVal { my $hash = shift; my $hod = shift; @@ -11834,22 +11860,23 @@ Planung und Steuerung von PV Überschuß abhängigen Verbraucherschaltungen. @@ -12298,10 +12325,11 @@ Planung und Steuerung von PV Überschuß abhängigen Verbraucherschaltungen. runTimeLastAPIProc die letzte Prozesszeit zur Verarbeitung der empfangenen SolCast API Daten (nur Model SolCastAPI) SunMinutes_Remain die verbleibenden Minuten bis Sonnenuntergang des aktuellen Tages SunHours_Remain die verbleibenden Stunden bis Sonnenuntergang des aktuellen Tages - todayMaxAPIcalls die maximal mögliche Anzahl SolCast API Calls (nur Model SolCastAPI). - Ein Call kann mehrere API Requests enthalten. todayDoneAPIcalls die Anzahl der am aktuellen Tag ausgeführten SolCast API Calls (nur Model SolCastAPI) todayDoneAPIrequests die Anzahl der am aktuellen Tag ausgeführten SolCast API Requests (nur Model SolCastAPI) + todayGridFeedIn die in das öffentliche Netz eingespeiste PV Leistung des aktuellen Tages + todayMaxAPIcalls die maximal mögliche Anzahl SolCast API Calls (nur Model SolCastAPI). + Ein Call kann mehrere API Requests enthalten. todayRemainingAPIcalls die Anzahl der am aktuellen Tag noch möglichen SolCast API Calls (nur Model SolCastAPI) todayRemainingAPIrequests die Anzahl der am aktuellen Tag noch möglichen SolCast API Requests (nur Model SolCastAPI)