76_SolarForecast: contrib 1.43.7
git-svn-id: https://svn.fhem.de/fhem/trunk@29536 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
@@ -157,6 +157,8 @@ BEGIN {
|
|||||||
|
|
||||||
# Versions History intern
|
# Versions History intern
|
||||||
my %vNotesIntern = (
|
my %vNotesIntern = (
|
||||||
|
"1.43.7" => "19.01.2025 _listDataPoolCircular: may select a dedicated hour, add temporary Migrate funktion ".
|
||||||
|
"fix interruptable key check in consumer attr Forum:https://forum.fhem.de/index.php?msg=1331073 ",
|
||||||
"1.43.6" => "17.01.2025 _calcCaQcomplex: additional write pvrl, pvfc to separate circular hash Array elements, listDataPool: show these Arrays ",
|
"1.43.6" => "17.01.2025 _calcCaQcomplex: additional write pvrl, pvfc to separate circular hash Array elements, listDataPool: show these Arrays ",
|
||||||
"1.43.5" => "15.01.2025 _flowGraphic: calculate the resulting SoC as a cluster of batteries ",
|
"1.43.5" => "15.01.2025 _flowGraphic: calculate the resulting SoC as a cluster of batteries ",
|
||||||
"1.43.4" => "14.01.2025 batsocslidereg: calculate the SoC as summary over all capacities in Wh, bugfix https://forum.fhem.de/index.php?msg=1330559 ",
|
"1.43.4" => "14.01.2025 batsocslidereg: calculate the SoC as summary over all capacities in Wh, bugfix https://forum.fhem.de/index.php?msg=1330559 ",
|
||||||
@@ -632,6 +634,7 @@ my %hget = ( # Ha
|
|||||||
valDecTree => { fn => \&_getaiDecTree, needcred => 0 },
|
valDecTree => { fn => \&_getaiDecTree, needcred => 0 },
|
||||||
ftuiFramefiles => { fn => \&_ftuiFramefiles, needcred => 0 },
|
ftuiFramefiles => { fn => \&_ftuiFramefiles, needcred => 0 },
|
||||||
dwdCatalog => { fn => \&_getdwdCatalog, needcred => 0 },
|
dwdCatalog => { fn => \&_getdwdCatalog, needcred => 0 },
|
||||||
|
'.migrate' => { fn => \&_getmigrate, needcred => 0 },
|
||||||
);
|
);
|
||||||
|
|
||||||
my %hattr = ( # Hash für Attr-Funktion
|
my %hattr = ( # Hash für Attr-Funktion
|
||||||
@@ -2152,6 +2155,10 @@ sub _setreset { ## no critic "not used"
|
|||||||
delete $data{$name}{circular}{$circh}{pvrlsum};
|
delete $data{$name}{circular}{$circh}{pvrlsum};
|
||||||
delete $data{$name}{circular}{$circh}{pvfcsum};
|
delete $data{$name}{circular}{$circh}{pvfcsum};
|
||||||
delete $data{$name}{circular}{$circh}{dnumsum};
|
delete $data{$name}{circular}{$circh}{dnumsum};
|
||||||
|
|
||||||
|
for my $k (keys %{$data{$name}{circular}{$circh}}) {
|
||||||
|
delete $data{$name}{circular}{$circh}{$k} if($k =~ /^(pvrl_|pvfc_)/xs);
|
||||||
|
}
|
||||||
|
|
||||||
for my $hid (keys %{$data{$name}{pvhist}}) {
|
for my $hid (keys %{$data{$name}{pvhist}}) {
|
||||||
delete $data{$name}{pvhist}{$hid}{$circh}{pvcorrf};
|
delete $data{$name}{pvhist}{$hid}{$circh}{pvcorrf};
|
||||||
@@ -2167,6 +2174,10 @@ sub _setreset { ## no critic "not used"
|
|||||||
delete $data{$name}{circular}{$hod}{pvrlsum};
|
delete $data{$name}{circular}{$hod}{pvrlsum};
|
||||||
delete $data{$name}{circular}{$hod}{pvfcsum};
|
delete $data{$name}{circular}{$hod}{pvfcsum};
|
||||||
delete $data{$name}{circular}{$hod}{dnumsum};
|
delete $data{$name}{circular}{$hod}{dnumsum};
|
||||||
|
|
||||||
|
for my $k (keys %{$data{$name}{circular}{$hod}}) {
|
||||||
|
delete $data{$name}{circular}{$hod}{$k} if($k =~ /^(pvrl_|pvfc_)/xs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for my $hid (keys %{$data{$name}{pvhist}}) {
|
for my $hid (keys %{$data{$name}{pvhist}}) {
|
||||||
@@ -2432,6 +2443,7 @@ sub Get {
|
|||||||
);
|
);
|
||||||
|
|
||||||
my @pha = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{pvhist}};
|
my @pha = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{pvhist}};
|
||||||
|
my @cla = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{circular}};
|
||||||
my @vcm = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{consumers}};
|
my @vcm = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{consumers}};
|
||||||
my @vba = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{batteries}};
|
my @vba = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{batteries}};
|
||||||
my @vin = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{inverters}};
|
my @vin = map {sprintf "%02d", $_} sort {$a<=>$b} keys %{$data{$name}{inverters}};
|
||||||
@@ -2440,6 +2452,7 @@ sub Get {
|
|||||||
|
|
||||||
my $hol = join ",", @ho;
|
my $hol = join ",", @ho;
|
||||||
my $pvl = join ",", @pha;
|
my $pvl = join ",", @pha;
|
||||||
|
my $cll = join ",", @cla;
|
||||||
my $cml = join ",", @vcm;
|
my $cml = join ",", @vcm;
|
||||||
my $bal = join ",", @vba;
|
my $bal = join ",", @vba;
|
||||||
my $inl = join ",", @vin;
|
my $inl = join ",", @vin;
|
||||||
@@ -2458,12 +2471,13 @@ sub Get {
|
|||||||
"ftuiFramefiles:noArg ".
|
"ftuiFramefiles:noArg ".
|
||||||
"html:$hol ".
|
"html:$hol ".
|
||||||
"nextHours:noArg ".
|
"nextHours:noArg ".
|
||||||
"pvCircular:noArg ".
|
"pvCircular:#,$cll ".
|
||||||
"pvHistory:#,exportToCsv,$pvl ".
|
"pvHistory:#,exportToCsv,$pvl ".
|
||||||
"rooftopData:noArg ".
|
"rooftopData:noArg ".
|
||||||
"radiationApiData:noArg ".
|
"radiationApiData:noArg ".
|
||||||
"statusApiData:noArg ".
|
"statusApiData:noArg ".
|
||||||
"valCurrent:noArg ".
|
"valCurrent:noArg ".
|
||||||
|
#".migrate:noArg ".
|
||||||
"weatherApiData:noArg "
|
"weatherApiData:noArg "
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -2506,6 +2520,59 @@ sub Get {
|
|||||||
return $getlist;
|
return $getlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Getter .migrate
|
||||||
|
################################################################
|
||||||
|
sub _getmigrate { ## no critic "not used"
|
||||||
|
my $paref = shift;
|
||||||
|
my $name = $paref->{name};
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
|
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
|
||||||
|
##########################################################################################################################
|
||||||
|
my $n = 0;
|
||||||
|
|
||||||
|
if (!exists $hash->{HELPER}{MIGDONE}) {
|
||||||
|
for my $hh (1..24) { # 18.01.25 -> Datenmigration pvrlsum, pvfcsum, dnumsum in pvrl_*, pvfc_*
|
||||||
|
$hh = sprintf "%02d", $hh;
|
||||||
|
|
||||||
|
for my $cul (sort keys %{$data{$name}{circular}{$hh}}) {
|
||||||
|
next if($cul ne 'dnumsum');
|
||||||
|
|
||||||
|
for my $dns (sort keys %{$data{$name}{circular}{$hh}{$cul}}) {
|
||||||
|
next if($dns eq 'simple');
|
||||||
|
|
||||||
|
my ($sabin, $crang) = split /\./, $dns;
|
||||||
|
my ($pvsum, $fcsum, $dnum) = CircularSumVal ($hash, $hh, $sabin, $crang, undef);
|
||||||
|
|
||||||
|
delete $data{$name}{circular}{$hh}{pvrlsum}{$dns};
|
||||||
|
delete $data{$name}{circular}{$hh}{pvfcsum}{$dns};
|
||||||
|
delete $data{$name}{circular}{$hh}{dnumsum}{$dns};
|
||||||
|
|
||||||
|
next if(!defined $pvsum || !defined $fcsum || !$dnum);
|
||||||
|
|
||||||
|
my $pvavg = sprintf "%.0f", ($pvsum / $dnum);
|
||||||
|
my $fcavg = sprintf "%.0f", ($fcsum / $dnum);
|
||||||
|
|
||||||
|
push @{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}}, $pvavg;
|
||||||
|
push @{$data{$name}{circular}{$hh}{'pvfc_'.$sabin}{"$crang"}}, $fcavg;
|
||||||
|
|
||||||
|
$n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($n) {
|
||||||
|
Log3 ($name, 1, "$name - NOTE - the stored PV real and forecast datasets (quantity: $n) were migrated to the new module structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#$hash->{HELPER}{MIGDONE} = 1;
|
||||||
|
|
||||||
|
return "Circular Store was migrated, $n datasets were processed and deleted";
|
||||||
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Getter roofTop data
|
# Getter roofTop data
|
||||||
################################################################
|
################################################################
|
||||||
@@ -4582,9 +4649,10 @@ return $ret;
|
|||||||
sub _getlistPVCircular {
|
sub _getlistPVCircular {
|
||||||
my $paref = shift;
|
my $paref = shift;
|
||||||
my $name = $paref->{name};
|
my $name = $paref->{name};
|
||||||
|
my $arg = $paref->{arg};
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
my $ret = listDataPool ($hash, 'circular');
|
my $ret = listDataPool ($hash, 'circular', $arg);
|
||||||
$ret .= lineFromSpaces ($ret, 20);
|
$ret .= lineFromSpaces ($ret, 20);
|
||||||
|
|
||||||
return $ret;
|
return $ret;
|
||||||
@@ -5607,13 +5675,19 @@ sub _attrconsumer { ## no critic "not used"
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (exists $h->{interruptable}) { # Check Regex/Hysterese
|
if (exists $h->{interruptable}) { # Check Regex/Hysterese
|
||||||
my (undef,undef,$regex,$hyst) = split ":", $h->{interruptable};
|
if ($h->{interruptable} !~ /^[01]$/xs) {
|
||||||
|
my ($dev,$rd,$regex,$hyst) = split ":", $h->{interruptable};
|
||||||
|
|
||||||
|
if (!$dev || !$rd || !defined $regex) {
|
||||||
|
return qq{A Device, Reading and Regex must be specified for the 'interruptable' key!};
|
||||||
|
}
|
||||||
|
|
||||||
$err = checkRegex ($regex);
|
$err = checkRegex ($regex);
|
||||||
return "interruptable: $err" if($err);
|
return "interruptable: $err" if($err);
|
||||||
|
|
||||||
if ($hyst && !isNumeric ($hyst)) {
|
if ($hyst && !isNumeric ($hyst)) {
|
||||||
return qq{The hysteresis of key "interruptable" must be a numeric value};
|
return qq{The hysteresis of key "interruptable" must be a numeric value};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7430,52 +7504,6 @@ sub centralTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exists $data{$name}{solcastapi}{'?IdPair'}) { # 29.11.2024
|
|
||||||
for my $pk (keys %{$data{$name}{solcastapi}{'?IdPair'}}) {
|
|
||||||
my $apikey = RadiationAPIVal ($hash, '?IdPair', $pk, 'apikey', '');
|
|
||||||
my $rtid = RadiationAPIVal ($hash, '?IdPair', $pk, 'rtid', '');
|
|
||||||
|
|
||||||
if ($apikey && $rtid) {
|
|
||||||
$data{$name}{statusapi}{'?IdPair'}{$pk}{rtid} = $rtid;
|
|
||||||
$data{$name}{statusapi}{'?IdPair'}{$pk}{apikey} = $apikey;
|
|
||||||
|
|
||||||
delete $data{$name}{solcastapi}{'?IdPair'}{$pk};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete $data{$name}{solcastapi}{'?IdPair'};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exists $data{$name}{solcastapi}{'?All'}{'?All'}) { # 29.11.2024
|
|
||||||
my ($rapi, $wapi) = getStatusApiName ($hash);
|
|
||||||
|
|
||||||
for my $key (keys %{$data{$name}{solcastapi}{'?All'}{'?All'}}) {
|
|
||||||
my $val = RadiationAPIVal ($hash, '?All', '?All', $key, '');
|
|
||||||
|
|
||||||
if ($rapi && $val) {
|
|
||||||
$data{$name}{statusapi}{$rapi}{'?All'}{$key} = $val;
|
|
||||||
delete $data{$name}{solcastapi}{'?All'}{'?All'}{$key};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete $data{$name}{solcastapi}{'?All'}{'?All'};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keys %{$data{$name}{solcastapi}{'?All'}}) { # 29.11.2024
|
|
||||||
for my $idx (keys %{$data{$name}{solcastapi}{'?All'}}) {
|
|
||||||
delete $data{$name}{solcastapi}{'?All'}{$idx} if($idx =~ /^fc?([0-9]{1,2})_?([0-9]{1,2})$/xs);
|
|
||||||
delete $data{$name}{solcastapi}{'?All'}{$idx} if($idx eq 'sunrise');
|
|
||||||
delete $data{$name}{solcastapi}{'?All'}{$idx} if($idx eq 'sunset');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete $data{$name}{solcastapi}{'?All'} if(!keys %{$data{$name}{solcastapi}{'?All'}});
|
|
||||||
|
|
||||||
my $vrmcr = RadiationAPIVal ($hash, '?VRM', '?API', 'credentials', ''); # 29.11.2024
|
|
||||||
if ($vrmcr) {
|
|
||||||
$data{$name}{statusapi}{'?VRM'}{'?API'}{credentials} = $vrmcr;
|
|
||||||
delete $data{$name}{solcastapi}{'?VRM'};
|
|
||||||
}
|
|
||||||
|
|
||||||
##########################################################################################################################
|
##########################################################################################################################
|
||||||
|
|
||||||
if (!CurrentVal ($hash, 'allStringsFullfilled', 0)) { # die String Konfiguration erstellen wenn noch nicht erfolgreich ausgeführt
|
if (!CurrentVal ($hash, 'allStringsFullfilled', 0)) { # die String Konfiguration erstellen wenn noch nicht erfolgreich ausgeführt
|
||||||
@@ -11624,11 +11652,6 @@ sub __getCyclesAndRuntime {
|
|||||||
|
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
|
|
||||||
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
|
|
||||||
##########################################################################################################################
|
|
||||||
|
|
||||||
##########################################################################################################################
|
|
||||||
|
|
||||||
my ($starthour, $startday);
|
my ($starthour, $startday);
|
||||||
|
|
||||||
if (isConsumerLogOn ($hash, $c, $pcurr)) { # Verbraucher ist logisch "an"
|
if (isConsumerLogOn ($hash, $c, $pcurr)) { # Verbraucher ist logisch "an"
|
||||||
@@ -12254,6 +12277,7 @@ sub _calcCaQcomplex {
|
|||||||
$paref->{calc} = 'Complex';
|
$paref->{calc} = 'Complex';
|
||||||
|
|
||||||
my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref);
|
my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref);
|
||||||
|
#my ($oldfac, $factor, $dnum) = __calcNewFactor_new ($paref);
|
||||||
|
|
||||||
delete $paref->{pvrl};
|
delete $paref->{pvrl};
|
||||||
delete $paref->{pvfc};
|
delete $paref->{pvfc};
|
||||||
@@ -12324,6 +12348,7 @@ sub _calcCaQsimple {
|
|||||||
$paref->{calc} = 'Simple';
|
$paref->{calc} = 'Simple';
|
||||||
|
|
||||||
my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref);
|
my ($oldfac, $factor, $dnum) = __calcNewFactor ($paref);
|
||||||
|
#my ($oldfac, $factor, $dnum) = __calcNewFactor_new ($paref);
|
||||||
|
|
||||||
delete $paref->{pvrl};
|
delete $paref->{pvrl};
|
||||||
delete $paref->{pvfc};
|
delete $paref->{pvfc};
|
||||||
@@ -12369,7 +12394,7 @@ sub __calcNewFactor {
|
|||||||
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> Start calculation correction factor for hour: $h");
|
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> Start calculation correction factor for hour: $h");
|
||||||
|
|
||||||
my $hh = sprintf "%02d", $h;
|
my $hh = sprintf "%02d", $h;
|
||||||
my ($oldfac, $oldq) = CircularSunCloudkorrVal ($hash, $hh, $sabin, $crang, 0); # bisher definierter Korrekturfaktor / Qualität
|
my ($oldfac, $oldq) = CircularSunCloudkorrVal ($hash, $hh, $sabin, $crang, 0); # bisher definierter Korrekturfaktor / Qualität
|
||||||
my ($pvhis, $fchis, $dnum) = CircularSumVal ($hash, $hh, $sabin, $crang, 0);
|
my ($pvhis, $fchis, $dnum) = CircularSumVal ($hash, $hh, $sabin, $crang, 0);
|
||||||
$oldfac = 1 if(1 * $oldfac == 0);
|
$oldfac = 1 if(1 * $oldfac == 0);
|
||||||
|
|
||||||
@@ -12403,9 +12428,8 @@ sub __calcNewFactor {
|
|||||||
Log3 ($name, 3, "$name - new $calc correction factor for hour $h calculated: $factor (old: $oldfac)");
|
Log3 ($name, 3, "$name - new $calc correction factor for hour $h calculated: $factor (old: $oldfac)");
|
||||||
}
|
}
|
||||||
|
|
||||||
$pvrl = sprintf "%.0f", $pvrl;
|
$pvrl = sprintf "%.0f", $pvrl;
|
||||||
$pvfc = sprintf "%.0f", $pvfc;
|
$pvfc = sprintf "%.0f", $pvfc;
|
||||||
|
|
||||||
my $qual = __calcFcQuality ($pvfc, $pvrl); # Qualität der Vorhersage für die vergangene Stunde
|
my $qual = __calcFcQuality ($pvfc, $pvrl); # Qualität der Vorhersage für die vergangene Stunde
|
||||||
|
|
||||||
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> determined values - hour: $h, Sun Altitude range: $sabin, Cloud range: $crang, old factor: $oldfac, new factor: $factor, days: $dnum");
|
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> determined values - hour: $h, Sun Altitude range: $sabin, Cloud range: $crang, old factor: $oldfac, new factor: $factor, days: $dnum");
|
||||||
@@ -12413,9 +12437,9 @@ sub __calcNewFactor {
|
|||||||
|
|
||||||
if ($crang ne 'simple') {
|
if ($crang ne 'simple') {
|
||||||
my $idx = $sabin.'.'.$crang; # value für pvcorrf Sonne Altitude
|
my $idx = $sabin.'.'.$crang; # value für pvcorrf Sonne Altitude
|
||||||
$data{$name}{circular}{$hh}{pvrlsum}{$idx} = $pvrlsum; # PV Erzeugung Summe speichern
|
$data{$name}{circular}{$hh}{pvrlsum}{$idx} = $pvrlsum; # PV Erzeugung Summe speichern
|
||||||
$data{$name}{circular}{$hh}{pvfcsum}{$idx} = $pvfcsum; # PV Prognose Summe speichern
|
$data{$name}{circular}{$hh}{pvfcsum}{$idx} = $pvfcsum; # PV Prognose Summe speichern
|
||||||
$data{$name}{circular}{$hh}{dnumsum}{$idx} = $dnum; # Anzahl aller historischen Tade dieser Range
|
$data{$name}{circular}{$hh}{dnumsum}{$idx} = $dnum; # Anzahl aller historischen Tade dieser Range
|
||||||
$data{$name}{circular}{$hh}{pvcorrf}{$idx} = $factor;
|
$data{$name}{circular}{$hh}{pvcorrf}{$idx} = $factor;
|
||||||
$data{$name}{circular}{$hh}{quality}{$idx} = $qual;
|
$data{$name}{circular}{$hh}{quality}{$idx} = $qual;
|
||||||
}
|
}
|
||||||
@@ -12432,6 +12456,101 @@ sub __calcNewFactor {
|
|||||||
return ($oldfac, $factor, $dnum);
|
return ($oldfac, $factor, $dnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# den neuen Korrekturfaktur berechnen (neue Funktion)
|
||||||
|
################################################################
|
||||||
|
sub __calcNewFactor_new {
|
||||||
|
my $paref = shift;
|
||||||
|
my $name = $paref->{name};
|
||||||
|
my $pvrl = $paref->{pvrl};
|
||||||
|
my $pvfc = $paref->{pvfc};
|
||||||
|
my $crang = $paref->{crang};
|
||||||
|
my $sabin = $paref->{sabin};
|
||||||
|
my $h = $paref->{h};
|
||||||
|
my $calc = $paref->{calc};
|
||||||
|
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
my ($factor, $pvcirc, $fccirc, $pvrlsum, $pvfcsum, $dnum);
|
||||||
|
|
||||||
|
my $hh = sprintf "%02d", $h;
|
||||||
|
my ($oldfac, $oldqal) = CircularSunCloudkorrVal ($hash, $hh, $sabin, $crang, 0); # bisher definierter Korrekturfaktor / Qualität
|
||||||
|
$oldfac = 1 if(1 * $oldfac == 0);
|
||||||
|
|
||||||
|
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> Start calculation correction factor for hour: $hh");
|
||||||
|
|
||||||
|
if ($calc eq 'Simple') {
|
||||||
|
($pvcirc, $fccirc, $dnum) = CircularSumVal ($hash, $hh, $sabin, 'simple', 0);
|
||||||
|
|
||||||
|
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> read stored values: PVreal sum: $pvcirc, PVforecast sum: $fccirc, days: $dnum");
|
||||||
|
|
||||||
|
if ($dnum) { # Werte in History vorhanden -> haben Prio !
|
||||||
|
$dnum++;
|
||||||
|
$pvrlsum = $pvrl + $pvcirc;
|
||||||
|
$pvfcsum = $pvfc + $fccirc;
|
||||||
|
$pvrl = $pvrlsum / $dnum;
|
||||||
|
$pvfc = $pvfcsum / $dnum;
|
||||||
|
$factor = sprintf "%.2f", ($pvrl / $pvfc); # Faktorberechnung: reale PV / Prognose
|
||||||
|
}
|
||||||
|
elsif ($oldfac && (!$pvcirc || !$fccirc)) { # Circular Hash liefert einen vorhandenen Korrekturfaktor aber keine gespeicherten PV-Werte
|
||||||
|
$dnum = 1;
|
||||||
|
$factor = sprintf "%.2f", ($pvrl / $pvfc);
|
||||||
|
$factor = sprintf "%.2f", ($factor + $oldfac) / 2;
|
||||||
|
}
|
||||||
|
else { # ganz neuer Wert
|
||||||
|
$dnum = 1;
|
||||||
|
$factor = sprintf "%.2f", ($pvrl / $pvfc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$pvrl = sprintf "%.0f", medianArray (\@{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}}); # neuen Median berechnen
|
||||||
|
$pvfc = sprintf "%.0f", medianArray (\@{$data{$name}{circular}{$hh}{'pvfc_'.$sabin}{"$crang"}}); # neuen Median berechnen
|
||||||
|
|
||||||
|
$dnum = scalar (@{$data{$name}{circular}{$hh}{'pvrl_'.$sabin}{"$crang"}});
|
||||||
|
$factor = sprintf "%.2f", ($pvrl / $pvfc);
|
||||||
|
|
||||||
|
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> read stored values: PVreal median: $pvrl, PVforecast median: $pvfc, days: $dnum");
|
||||||
|
}
|
||||||
|
|
||||||
|
$factor = 1.00 if(1 * $factor == 0); # 0.00-Werte ignorieren (Schleifengefahr)
|
||||||
|
|
||||||
|
## max. Faktorsteigerung berücksichtigen
|
||||||
|
##########################################
|
||||||
|
if (abs($factor - $oldfac) > $defmaxvar) {
|
||||||
|
$factor = sprintf "%.2f", ($factor > $oldfac ? $oldfac + $defmaxvar : $oldfac - $defmaxvar);
|
||||||
|
Log3 ($name, 3, "$name - new $calc correction factor calculated (limited by maximum Day Variance): $factor (old: $oldfac) for hour: $hh");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log3 ($name, 3, "$name - new $calc correction factor for hour $hh calculated: $factor (old: $oldfac)");
|
||||||
|
}
|
||||||
|
|
||||||
|
## Qualität berechnen
|
||||||
|
#######################
|
||||||
|
$oldfac = sprintf "%.2f", $oldfac;
|
||||||
|
$pvrl = sprintf "%.0f", $pvrl;
|
||||||
|
$pvfc = sprintf "%.0f", $pvfc;
|
||||||
|
my $qual = __calcFcQuality ($pvfc, $pvrl); # Qualität der Vorhersage für die vergangene Stunde
|
||||||
|
|
||||||
|
debugLog ($paref, 'pvCorrectionWrite', "$calc Corrf -> determined values - hour: $h, Sun Altitude range: $sabin, Cloud range: $crang, old factor: $oldfac, new factor: $factor, days: $dnum");
|
||||||
|
debugLog ($paref, 'pvCorrectionWrite|saveData2Cache', "$calc Corrf -> write correction values into Circular - hour: $h, Sun Altitude range: $sabin, Cloud range: $crang, factor: $factor, quality: $qual, days: $dnum");
|
||||||
|
|
||||||
|
## neue Werte speichern
|
||||||
|
#########################
|
||||||
|
if ($calc eq 'Simple') {
|
||||||
|
$data{$name}{circular}{$hh}{pvrlsum}{'simple'} = $pvrlsum;
|
||||||
|
$data{$name}{circular}{$hh}{pvfcsum}{'simple'} = $pvfcsum;
|
||||||
|
$data{$name}{circular}{$hh}{dnumsum}{'simple'} = $dnum;
|
||||||
|
$data{$name}{circular}{$hh}{pvcorrf}{'simple'} = $factor;
|
||||||
|
$data{$name}{circular}{$hh}{quality}{'simple'} = $qual;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
my $idx = $sabin.'.'.$crang;
|
||||||
|
$data{$name}{circular}{$hh}{pvcorrf}{$idx} = $factor;
|
||||||
|
$data{$name}{circular}{$hh}{quality}{$idx} = $qual;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($oldfac, $factor, $dnum);
|
||||||
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Qualität der Vorhersage berechnen
|
# Qualität der Vorhersage berechnen
|
||||||
################################################################
|
################################################################
|
||||||
@@ -13091,11 +13210,6 @@ sub _checkSetupNotComplete {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $type = $hash->{TYPE};
|
my $type = $hash->{TYPE};
|
||||||
|
|
||||||
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
##########################################################################################
|
|
||||||
|
|
||||||
my $strings = 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
|
||||||
@@ -17429,175 +17543,7 @@ sub listDataPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($htol eq "circular") {
|
if ($htol eq "circular") {
|
||||||
$h = $data{$name}{circular};
|
$sq = _listDataPoolCircular ($hash, $par);
|
||||||
if (!keys %{$h}) {
|
|
||||||
return qq{Circular cache is empty.};
|
|
||||||
}
|
|
||||||
|
|
||||||
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
|
|
||||||
##########################################################################################################################
|
|
||||||
delete $data{$name}{circular}{'01'}{pvrl_5};
|
|
||||||
delete $data{$name}{circular}{'01'}{pvrl_10};
|
|
||||||
delete $data{$name}{circular}{'01'}{pvrl_25};
|
|
||||||
delete $data{$name}{circular}{'01'}{pvrl_60};
|
|
||||||
delete $data{$name}{circular}{'01'}{pvrl_65};
|
|
||||||
delete $data{$name}{circular}{'01'}{pvrl_90};
|
|
||||||
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4561;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4562;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4563;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4564;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4565;
|
|
||||||
#
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_65}{60}}, 3561;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_65}{60}}, 3562;
|
|
||||||
#
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4561;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4562;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4563;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4564;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4565;
|
|
||||||
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_90}{60}}, 3561;
|
|
||||||
#push @{$data{$name}{circular}{'01'}{pvrl_90}{60}}, 3562;
|
|
||||||
|
|
||||||
############################################################################################################
|
|
||||||
|
|
||||||
for my $idx (sort keys %{$h}) {
|
|
||||||
my $pvrl = CircularVal ($hash, $idx, 'pvrl', '-');
|
|
||||||
my $pvfc = CircularVal ($hash, $idx, 'pvfc', '-');
|
|
||||||
my $pvrlsum = CircularVal ($hash, $idx, 'pvrlsum', '-');
|
|
||||||
my $pvfcsum = CircularVal ($hash, $idx, 'pvfcsum', '-');
|
|
||||||
my $dnumsum = CircularVal ($hash, $idx, 'dnumsum', '-');
|
|
||||||
my $pvaifc = CircularVal ($hash, $idx, 'pvaifc', '-');
|
|
||||||
my $pvapifc = CircularVal ($hash, $idx, 'pvapifc', '-');
|
|
||||||
my $aihit = CircularVal ($hash, $idx, 'aihit', '-');
|
|
||||||
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 $rr1c = CircularVal ($hash, $idx, 'rr1c', '-');
|
|
||||||
my $temp = CircularVal ($hash, $idx, 'temp', '-');
|
|
||||||
my $pvcorrf = CircularVal ($hash, $idx, 'pvcorrf', '-');
|
|
||||||
my $quality = CircularVal ($hash, $idx, 'quality', '-');
|
|
||||||
my $tdayDvtn = CircularVal ($hash, $idx, 'tdayDvtn', '-');
|
|
||||||
my $ydayDvtn = CircularVal ($hash, $idx, 'ydayDvtn', '-');
|
|
||||||
my $fitot = CircularVal ($hash, $idx, 'feedintotal', '-');
|
|
||||||
my $idfi = CircularVal ($hash, $idx, 'initdayfeedin', '-');
|
|
||||||
my $gcontot = CircularVal ($hash, $idx, 'gridcontotal', '-');
|
|
||||||
my $idgcon = CircularVal ($hash, $idx, 'initdaygcon', '-');
|
|
||||||
my $rtaitr = CircularVal ($hash, $idx, 'runTimeTrainAI', '-');
|
|
||||||
my $fsaitr = CircularVal ($hash, $idx, 'aitrainLastFinishTs', '-');
|
|
||||||
my $airn = CircularVal ($hash, $idx, 'aiRulesNumber', '-');
|
|
||||||
my $aicts = CircularVal ($hash, $idx, 'attrInvChangedTs', '-');
|
|
||||||
|
|
||||||
my $pvcf = _ldchash2val ( {pool => $h, idx => $idx, key => 'pvcorrf', cval => $pvcorrf} );
|
|
||||||
my $cfq = _ldchash2val ( {pool => $h, idx => $idx, key => 'quality', cval => $quality} );
|
|
||||||
my $pvrs = _ldchash2val ( {pool => $h, idx => $idx, key => 'pvrlsum', cval => $pvrlsum} );
|
|
||||||
my $pvfs = _ldchash2val ( {pool => $h, idx => $idx, key => 'pvfcsum', cval => $pvfcsum} );
|
|
||||||
my $dnus = _ldchash2val ( {pool => $h, idx => $idx, key => 'dnumsum', cval => $dnumsum} );
|
|
||||||
|
|
||||||
$sq .= "\n" if($sq);
|
|
||||||
|
|
||||||
if ($idx != 99) {
|
|
||||||
my $prdl;
|
|
||||||
for my $pn (1..$maxproducer) { # alle Producer
|
|
||||||
$pn = sprintf "%02d", $pn;
|
|
||||||
my $pprl = CircularVal ($hash, $idx, 'pprl'.$pn, '-');
|
|
||||||
$prdl .= ', ' if($prdl);
|
|
||||||
$prdl .= "pprl${pn}: $pprl";
|
|
||||||
}
|
|
||||||
|
|
||||||
my ($bin, $bout);
|
|
||||||
for my $bn (1..$maxbatteries) { # alle Batterien
|
|
||||||
$bn = sprintf "%02d", $bn;
|
|
||||||
my $batin = CircularVal ($hash, $idx, 'batin'. $bn, '-');
|
|
||||||
my $batout = CircularVal ($hash, $idx, 'batout'.$bn, '-');
|
|
||||||
$bin .= ', ' if($bin);
|
|
||||||
$bin .= "batin${bn}: $batin";
|
|
||||||
$bout .= ', ' if($bout);
|
|
||||||
$bout .= "batout${bn}: $batout";
|
|
||||||
}
|
|
||||||
|
|
||||||
my ($pvrlnew, $pvfcnew);
|
|
||||||
my @pvrlkeys = map { $_ =~ /^pvrl_/xs ? $_ : '' } sort keys %{$h->{$idx}};
|
|
||||||
my @pvfckeys = map { $_ =~ /^pvfc_/xs ? $_ : '' } sort keys %{$h->{$idx}};
|
|
||||||
|
|
||||||
for my $prl (@pvrlkeys) {
|
|
||||||
next if(!$prl);
|
|
||||||
my $lref = CircularVal ($hash, $idx, $prl, '');
|
|
||||||
next if(!$lref);
|
|
||||||
|
|
||||||
$pvrlnew .= "\n " if($pvrlnew);
|
|
||||||
$pvrlnew .= _ldchash2val ( { pool => $h, idx => $idx, key => $prl, cval => $lref } );
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $pfc (@pvfckeys) {
|
|
||||||
next if(!$pfc);
|
|
||||||
my $cref = CircularVal ($hash, $idx, $pfc, '');
|
|
||||||
next if(!$cref);
|
|
||||||
|
|
||||||
$pvfcnew .= "\n " if($pvfcnew);
|
|
||||||
$pvfcnew .= _ldchash2val ( { pool => $h, idx => $idx, key => $pfc, cval => $cref } );
|
|
||||||
}
|
|
||||||
|
|
||||||
$sq .= $idx." => pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit, pvrl: $pvrl";
|
|
||||||
$sq .= "\n $bin";
|
|
||||||
$sq .= "\n $bout";
|
|
||||||
$sq .= "\n confc: $confc, gcon: $gcons, gfeedin: $gfeedin, wcc: $wccv, rr1c: $rr1c";
|
|
||||||
$sq .= "\n temp: $temp, wid: $wid, wtxt: $wtxt";
|
|
||||||
$sq .= "\n $prdl";
|
|
||||||
$sq .= "\n pvcorrf: $pvcf";
|
|
||||||
$sq .= "\n quality: $cfq";
|
|
||||||
$sq .= "\n pvrlsum: $pvrs";
|
|
||||||
$sq .= "\n pvfcsum: $pvfs";
|
|
||||||
$sq .= "\n dnumsum: $dnus";
|
|
||||||
$sq .= "\n $pvrlnew" if($pvrlnew);
|
|
||||||
$sq .= "\n $pvfcnew" if($pvfcnew);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
my ($batvl1, $batvl2, $batvl3, $batvl4, $batvl5, $batvl6, $batvl7);
|
|
||||||
for my $bn (1..$maxbatteries) { # + alle Batterien
|
|
||||||
$bn = sprintf "%02d", $bn;
|
|
||||||
my $idbintot = CircularVal ($hash, $idx, 'initdaybatintot'. $bn, '-');
|
|
||||||
my $idboutot = CircularVal ($hash, $idx, 'initdaybatouttot'.$bn, '-');
|
|
||||||
my $bintot = CircularVal ($hash, $idx, 'batintot'. $bn, '-');
|
|
||||||
my $boutot = CircularVal ($hash, $idx, 'batouttot'. $bn, '-');
|
|
||||||
my $lstmsr = CircularVal ($hash, $idx, 'lastTsMaxSocRchd'.$bn, '-');
|
|
||||||
my $ntsmsc = CircularVal ($hash, $idx, 'nextTsMaxSocChge'.$bn, '-');
|
|
||||||
my $dtocare = CircularVal ($hash, $idx, 'days2care'. $bn, '-');
|
|
||||||
$batvl1 .= ', ' if($batvl1);
|
|
||||||
$batvl1 .= "initdaybatintot${bn}: $idbintot";
|
|
||||||
$batvl2 .= ', ' if($batvl2);
|
|
||||||
$batvl2 .= "initdaybatouttot${bn}: $idboutot";
|
|
||||||
$batvl3 .= ', ' if($batvl3);
|
|
||||||
$batvl3 .= "batintot${bn}: $bintot";
|
|
||||||
$batvl4 .= ', ' if($batvl4);
|
|
||||||
$batvl4 .= "batouttot${bn}: $boutot";
|
|
||||||
$batvl5 .= ', ' if($batvl5);
|
|
||||||
$batvl5 .= "lastTsMaxSocRchd${bn}: $lstmsr";
|
|
||||||
$batvl6 .= ', ' if($batvl6);
|
|
||||||
$batvl6 .= "nextTsMaxSocChge${bn}: $ntsmsc";
|
|
||||||
$batvl7 .= ', ' if($batvl7);
|
|
||||||
$batvl7 .= "days2care${bn}: $dtocare";
|
|
||||||
}
|
|
||||||
|
|
||||||
$sq .= $idx." => tdayDvtn: $tdayDvtn, ydayDvtn: $ydayDvtn \n";
|
|
||||||
$sq .= " feedintotal: $fitot, initdayfeedin: $idfi \n";
|
|
||||||
$sq .= " gridcontotal: $gcontot, initdaygcon: $idgcon \n";
|
|
||||||
$sq .= " $batvl1\n";
|
|
||||||
$sq .= " $batvl2\n";
|
|
||||||
$sq .= " $batvl3\n";
|
|
||||||
$sq .= " $batvl4\n";
|
|
||||||
$sq .= " $batvl5\n";
|
|
||||||
$sq .= " $batvl6\n";
|
|
||||||
$sq .= " $batvl7\n";
|
|
||||||
$sq .= " runTimeTrainAI: $rtaitr, aitrainLastFinishTs: $fsaitr, aiRulesNumber: $airn \n";
|
|
||||||
$sq .= " attrInvChangedTs: $aicts \n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($htol eq "nexthours") {
|
if ($htol eq "nexthours") {
|
||||||
@@ -17809,6 +17755,192 @@ sub listDataPool {
|
|||||||
return $sq;
|
return $sq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Listing des Circular Speichers
|
||||||
|
################################################################
|
||||||
|
sub _listDataPoolCircular {
|
||||||
|
my $hash = shift;
|
||||||
|
my $par = shift // q{};
|
||||||
|
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my $h = $data{$name}{circular};
|
||||||
|
|
||||||
|
if (!keys %{$h}) {
|
||||||
|
return qq{Circular cache is empty.};
|
||||||
|
}
|
||||||
|
|
||||||
|
my $sq;
|
||||||
|
|
||||||
|
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
|
||||||
|
##########################################################################################################################
|
||||||
|
delete $data{$name}{circular}{'01'}{pvrl_5};
|
||||||
|
delete $data{$name}{circular}{'01'}{pvrl_10};
|
||||||
|
delete $data{$name}{circular}{'01'}{pvrl_25};
|
||||||
|
delete $data{$name}{circular}{'01'}{pvrl_60};
|
||||||
|
delete $data{$name}{circular}{'01'}{pvrl_65};
|
||||||
|
delete $data{$name}{circular}{'01'}{pvrl_90};
|
||||||
|
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4561;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4562;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4563;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4564;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_65}{100}}, 4565;
|
||||||
|
#
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_65}{60}}, 3561;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_65}{60}}, 3562;
|
||||||
|
#
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4561;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4562;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4563;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4564;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_90}{100}}, 4565;
|
||||||
|
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_90}{60}}, 3561;
|
||||||
|
#push @{$data{$name}{circular}{'01'}{pvrl_90}{60}}, 3562;
|
||||||
|
|
||||||
|
############################################################################################################
|
||||||
|
|
||||||
|
for my $idx (sort keys %{$h}) {
|
||||||
|
next if($par && $idx ne $par);
|
||||||
|
|
||||||
|
my $pvrl = CircularVal ($hash, $idx, 'pvrl', '-');
|
||||||
|
my $pvfc = CircularVal ($hash, $idx, 'pvfc', '-');
|
||||||
|
my $pvrlsum = CircularVal ($hash, $idx, 'pvrlsum', '-');
|
||||||
|
my $pvfcsum = CircularVal ($hash, $idx, 'pvfcsum', '-');
|
||||||
|
my $dnumsum = CircularVal ($hash, $idx, 'dnumsum', '-');
|
||||||
|
my $pvaifc = CircularVal ($hash, $idx, 'pvaifc', '-');
|
||||||
|
my $pvapifc = CircularVal ($hash, $idx, 'pvapifc', '-');
|
||||||
|
my $aihit = CircularVal ($hash, $idx, 'aihit', '-');
|
||||||
|
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 $rr1c = CircularVal ($hash, $idx, 'rr1c', '-');
|
||||||
|
my $temp = CircularVal ($hash, $idx, 'temp', '-');
|
||||||
|
my $pvcorrf = CircularVal ($hash, $idx, 'pvcorrf', '-');
|
||||||
|
my $quality = CircularVal ($hash, $idx, 'quality', '-');
|
||||||
|
my $tdayDvtn = CircularVal ($hash, $idx, 'tdayDvtn', '-');
|
||||||
|
my $ydayDvtn = CircularVal ($hash, $idx, 'ydayDvtn', '-');
|
||||||
|
my $fitot = CircularVal ($hash, $idx, 'feedintotal', '-');
|
||||||
|
my $idfi = CircularVal ($hash, $idx, 'initdayfeedin', '-');
|
||||||
|
my $gcontot = CircularVal ($hash, $idx, 'gridcontotal', '-');
|
||||||
|
my $idgcon = CircularVal ($hash, $idx, 'initdaygcon', '-');
|
||||||
|
my $rtaitr = CircularVal ($hash, $idx, 'runTimeTrainAI', '-');
|
||||||
|
my $fsaitr = CircularVal ($hash, $idx, 'aitrainLastFinishTs', '-');
|
||||||
|
my $airn = CircularVal ($hash, $idx, 'aiRulesNumber', '-');
|
||||||
|
my $aicts = CircularVal ($hash, $idx, 'attrInvChangedTs', '-');
|
||||||
|
|
||||||
|
my $pvcf = _ldchash2val ( {pool => $h, idx => $idx, key => 'pvcorrf', cval => $pvcorrf} );
|
||||||
|
my $cfq = _ldchash2val ( {pool => $h, idx => $idx, key => 'quality', cval => $quality} );
|
||||||
|
my $pvrs = _ldchash2val ( {pool => $h, idx => $idx, key => 'pvrlsum', cval => $pvrlsum} );
|
||||||
|
my $pvfs = _ldchash2val ( {pool => $h, idx => $idx, key => 'pvfcsum', cval => $pvfcsum} );
|
||||||
|
my $dnus = _ldchash2val ( {pool => $h, idx => $idx, key => 'dnumsum', cval => $dnumsum} );
|
||||||
|
|
||||||
|
$sq .= "\n" if($sq);
|
||||||
|
|
||||||
|
if ($idx != 99) {
|
||||||
|
my $prdl;
|
||||||
|
for my $pn (1..$maxproducer) { # alle Producer
|
||||||
|
$pn = sprintf "%02d", $pn;
|
||||||
|
my $pprl = CircularVal ($hash, $idx, 'pprl'.$pn, '-');
|
||||||
|
$prdl .= ', ' if($prdl);
|
||||||
|
$prdl .= "pprl${pn}: $pprl";
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($bin, $bout);
|
||||||
|
for my $bn (1..$maxbatteries) { # alle Batterien
|
||||||
|
$bn = sprintf "%02d", $bn;
|
||||||
|
my $batin = CircularVal ($hash, $idx, 'batin'. $bn, '-');
|
||||||
|
my $batout = CircularVal ($hash, $idx, 'batout'.$bn, '-');
|
||||||
|
$bin .= ', ' if($bin);
|
||||||
|
$bin .= "batin${bn}: $batin";
|
||||||
|
$bout .= ', ' if($bout);
|
||||||
|
$bout .= "batout${bn}: $batout";
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($pvrlnew, $pvfcnew);
|
||||||
|
my @pvrlkeys = map { $_ =~ /^pvrl_/xs ? $_ : '' } sort keys %{$h->{$idx}};
|
||||||
|
my @pvfckeys = map { $_ =~ /^pvfc_/xs ? $_ : '' } sort keys %{$h->{$idx}};
|
||||||
|
|
||||||
|
for my $prl (@pvrlkeys) {
|
||||||
|
next if(!$prl);
|
||||||
|
my $lref = CircularVal ($hash, $idx, $prl, '');
|
||||||
|
next if(!$lref);
|
||||||
|
|
||||||
|
$pvrlnew .= "\n " if($pvrlnew);
|
||||||
|
$pvrlnew .= _ldchash2val ( { pool => $h, idx => $idx, key => $prl, cval => $lref } );
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $pfc (@pvfckeys) {
|
||||||
|
next if(!$pfc);
|
||||||
|
my $cref = CircularVal ($hash, $idx, $pfc, '');
|
||||||
|
next if(!$cref);
|
||||||
|
|
||||||
|
$pvfcnew .= "\n " if($pvfcnew);
|
||||||
|
$pvfcnew .= _ldchash2val ( { pool => $h, idx => $idx, key => $pfc, cval => $cref } );
|
||||||
|
}
|
||||||
|
|
||||||
|
$sq .= $idx." => pvapifc: $pvapifc, pvaifc: $pvaifc, pvfc: $pvfc, aihit: $aihit, pvrl: $pvrl";
|
||||||
|
$sq .= "\n $bin";
|
||||||
|
$sq .= "\n $bout";
|
||||||
|
$sq .= "\n confc: $confc, gcon: $gcons, gfeedin: $gfeedin, wcc: $wccv, rr1c: $rr1c";
|
||||||
|
$sq .= "\n temp: $temp, wid: $wid, wtxt: $wtxt";
|
||||||
|
$sq .= "\n $prdl";
|
||||||
|
$sq .= "\n pvcorrf: $pvcf";
|
||||||
|
$sq .= "\n quality: $cfq";
|
||||||
|
$sq .= "\n pvrlsum: $pvrs";
|
||||||
|
$sq .= "\n pvfcsum: $pvfs";
|
||||||
|
$sq .= "\n dnumsum: $dnus";
|
||||||
|
$sq .= "\n $pvrlnew" if($pvrlnew);
|
||||||
|
$sq .= "\n $pvfcnew" if($pvfcnew);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
my ($batvl1, $batvl2, $batvl3, $batvl4, $batvl5, $batvl6, $batvl7);
|
||||||
|
for my $bn (1..$maxbatteries) { # + alle Batterien
|
||||||
|
$bn = sprintf "%02d", $bn;
|
||||||
|
my $idbintot = CircularVal ($hash, $idx, 'initdaybatintot'. $bn, '-');
|
||||||
|
my $idboutot = CircularVal ($hash, $idx, 'initdaybatouttot'.$bn, '-');
|
||||||
|
my $bintot = CircularVal ($hash, $idx, 'batintot'. $bn, '-');
|
||||||
|
my $boutot = CircularVal ($hash, $idx, 'batouttot'. $bn, '-');
|
||||||
|
my $lstmsr = CircularVal ($hash, $idx, 'lastTsMaxSocRchd'.$bn, '-');
|
||||||
|
my $ntsmsc = CircularVal ($hash, $idx, 'nextTsMaxSocChge'.$bn, '-');
|
||||||
|
my $dtocare = CircularVal ($hash, $idx, 'days2care'. $bn, '-');
|
||||||
|
$batvl1 .= ', ' if($batvl1);
|
||||||
|
$batvl1 .= "initdaybatintot${bn}: $idbintot";
|
||||||
|
$batvl2 .= ', ' if($batvl2);
|
||||||
|
$batvl2 .= "initdaybatouttot${bn}: $idboutot";
|
||||||
|
$batvl3 .= ', ' if($batvl3);
|
||||||
|
$batvl3 .= "batintot${bn}: $bintot";
|
||||||
|
$batvl4 .= ', ' if($batvl4);
|
||||||
|
$batvl4 .= "batouttot${bn}: $boutot";
|
||||||
|
$batvl5 .= ', ' if($batvl5);
|
||||||
|
$batvl5 .= "lastTsMaxSocRchd${bn}: $lstmsr";
|
||||||
|
$batvl6 .= ', ' if($batvl6);
|
||||||
|
$batvl6 .= "nextTsMaxSocChge${bn}: $ntsmsc";
|
||||||
|
$batvl7 .= ', ' if($batvl7);
|
||||||
|
$batvl7 .= "days2care${bn}: $dtocare";
|
||||||
|
}
|
||||||
|
|
||||||
|
$sq .= $idx." => tdayDvtn: $tdayDvtn, ydayDvtn: $ydayDvtn \n";
|
||||||
|
$sq .= " feedintotal: $fitot, initdayfeedin: $idfi \n";
|
||||||
|
$sq .= " gridcontotal: $gcontot, initdaygcon: $idgcon \n";
|
||||||
|
$sq .= " $batvl1\n";
|
||||||
|
$sq .= " $batvl2\n";
|
||||||
|
$sq .= " $batvl3\n";
|
||||||
|
$sq .= " $batvl4\n";
|
||||||
|
$sq .= " $batvl5\n";
|
||||||
|
$sq .= " $batvl6\n";
|
||||||
|
$sq .= " $batvl7\n";
|
||||||
|
$sq .= " runTimeTrainAI: $rtaitr, aitrainLastFinishTs: $fsaitr, aiRulesNumber: $airn \n";
|
||||||
|
$sq .= " attrInvChangedTs: $aicts \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sq;
|
||||||
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Hashwert aus CircularVal in formatierten String umwandeln
|
# Hashwert aus CircularVal in formatierten String umwandeln
|
||||||
################################################################
|
################################################################
|
||||||
@@ -17830,17 +17962,23 @@ sub _ldchash2val {
|
|||||||
|
|
||||||
if (ref $pool->{$idx}{$key}{$f} eq 'ARRAY') {
|
if (ref $pool->{$idx}{$key}{$f} eq 'ARRAY') {
|
||||||
my @sub_arrays = arraySplitBy (20, @{$pool->{$idx}{$key}{$f}}); # Array in Teil-Arrays zu je 20 Elemente aufteilen
|
my @sub_arrays = arraySplitBy (20, @{$pool->{$idx}{$key}{$f}}); # Array in Teil-Arrays zu je 20 Elemente aufteilen
|
||||||
|
my $ln0 = length $key;
|
||||||
|
my $blk0 = ' ' x 17;
|
||||||
|
my $blkadd0 = ' ' x (7 - ($ln0 > 7 ? 0 : $ln0));
|
||||||
|
|
||||||
|
my $ln1 = length $f;
|
||||||
|
my $blkadd1 = ' ' x (3 - ($ln1 > 3 ? 0 : $ln1));
|
||||||
|
|
||||||
for my $suaref (@sub_arrays) { # für jedes Teil-Array Join ausführen
|
for my $suaref (@sub_arrays) { # für jedes Teil-Array Join ausführen
|
||||||
my $suajoined = join ' ', @{$suaref};
|
my $suajoined = join ' ', @{$suaref};
|
||||||
|
|
||||||
if (!$ret) {
|
if (!$ret) {
|
||||||
$ret .= $key.' => ';
|
$ret .= $key.$blkadd0.' => ';
|
||||||
$ret .= $f.' @ '.$suajoined;
|
$ret .= $f.$blkadd1.' @ '.$suajoined;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$ret .= "\n ";
|
$ret .= "\n".$blk0;
|
||||||
$ret .= $f.' @ '.$suajoined;
|
$ret .= $f.$blkadd1.' @ '.$suajoined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20020,7 +20158,7 @@ return $ps;
|
|||||||
sub checkRegex {
|
sub checkRegex {
|
||||||
my $regexp = shift;
|
my $regexp = shift;
|
||||||
|
|
||||||
return 'no Regex is provided' if(!$regexp);
|
return 'no Regex is provided' if(!defined $regexp);
|
||||||
|
|
||||||
eval { "Hallo" =~ m/^$regexp$/;
|
eval { "Hallo" =~ m/^$regexp$/;
|
||||||
1;
|
1;
|
||||||
@@ -21971,13 +22109,13 @@ to ensure that the system configuration is correct.
|
|||||||
<ul>
|
<ul>
|
||||||
<a id="SolarForecast-get-pvCircular"></a>
|
<a id="SolarForecast-get-pvCircular"></a>
|
||||||
<li><b>pvCircular </b> <br><br>
|
<li><b>pvCircular </b> <br><br>
|
||||||
Lists the existing values in the ring buffer.
|
Lists the stored data for the selected hour or all existing values in the ring buffer. <br>
|
||||||
The hours 01 - 24 refer to the hour of the day, e.g. the hour 09 refers to the time from
|
The hours 01 - 24 refer to the hour of the day, e.g. the hour 09 refers to the time from
|
||||||
08 - 09 o'clock. <br>
|
08 - 09 o'clock. <br>
|
||||||
Hour 99 has a special function. <br>
|
Hour 99 has a special function. <br>
|
||||||
The values of the keys pvcorrf, quality, pvrlsum, pvfcsum and dnumsum are coded in the form
|
The values of the keys pvcorrf, quality, pvrlsum, pvfcsum and dnumsum are coded in the form
|
||||||
<range sun elevation>.<cloud cover range>. <br>
|
<range sun elevation>.<cloud cover range>.
|
||||||
Explanation of the values: <br><br>
|
<br><br>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<table>
|
<table>
|
||||||
@@ -24444,13 +24582,13 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
|||||||
<ul>
|
<ul>
|
||||||
<a id="SolarForecast-get-pvCircular"></a>
|
<a id="SolarForecast-get-pvCircular"></a>
|
||||||
<li><b>pvCircular </b> <br><br>
|
<li><b>pvCircular </b> <br><br>
|
||||||
Listet die vorhandenen Werte im Ringspeicher auf.
|
Listet die gespeicherten Daten der ausgewählten Stunde oder alle vorhandenen Werte im Ringspeicher auf. <br>
|
||||||
Die Stundenangaben 01 - 24 beziehen sich auf die Stunde des Tages, z.B. bezieht sich die Stunde 09 auf die Zeit von
|
Die Stundenangaben 01 - 24 beziehen sich auf die Stunde des Tages, z.B. bezieht sich die Stunde 09 auf die Zeit von
|
||||||
08 - 09 Uhr. <br>
|
08 - 09 Uhr. <br>
|
||||||
Die Stunde 99 hat eine Sonderfunktion. <br>
|
Die Stunde 99 hat eine Sonderfunktion. <br>
|
||||||
Die Werte der Schlüssel pvcorrf, quality, pvrlsum, pvfcsum und dnumsum sind in der Form
|
Die Werte der Schlüssel pvcorrf, quality, pvrlsum, pvfcsum und dnumsum sind in der Form
|
||||||
<Bereich Sonnenstand Höhe>.<Bewölkungsbereich> kodiert. <br>
|
<Bereich Sonnenstand Höhe>.<Bewölkungsbereich> kodiert.
|
||||||
Erläuterung der Werte: <br><br>
|
<br><br>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<table>
|
<table>
|
||||||
|
|||||||
Reference in New Issue
Block a user