2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 03:06:37 +00:00

76_SolarForecast: options for conprice, feedprice and more

git-svn-id: https://svn.fhem.de/fhem/trunk@28768 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2024-04-07 19:01:05 +00:00
parent 355bbfc281
commit 4ade58741d
2 changed files with 302 additions and 257 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it
- feature: 76_SolarForecast: options for conprice, feedprice and more
- change: 49_SSCam: check SSChatBot/TelegramBot is disabled before send data
- feature: 70_PylonLowVoltage: add specific Alarm readings, support of US5000
- bugfix: 73_PRESENCE2: BlockingCall loglevel = GetVerbose($name)

View File

@ -158,6 +158,11 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
"1.17.6" => "07.04.2024 new sub writeToHistory with many internal changes in pvHistory write process ".
"_transferInverterValues: react on inverter etotal behavior ",
"1.17.5" => "04.04.2024 currentInverterDev: check syntax of key capacity if set, change defmaxvar back from 0.8 to 0.5 ".
"currentMeterDev: [conprice=<Devicename>:<Readingname>:<Einheit>] [feedprice=<Devicename>:<Readingname>:<Einheit>] ".
"___setOpenMeteoAPIcallKeyData: new sub to calculate the minimum Open-Meteo request intervalls ",
"1.17.4" => "01.04.2024 fix ctrlWeatherDev1 Drop-Down list if no DWD Device exists, edit commandref ",
"1.17.3" => "31.03.2024 edit commandref, valDecTree: more infos in aiRuleStrings output, integrate OpenMeteoDWDEnsemble-API ".
"change Call interval Open-Meteo API to 900s, OpenMeteo-API: fix todayDoneAPIcalls, implement callequivalent".
@ -327,12 +332,6 @@ my %vNotesIntern = (
"0.77.1" => "07.05.2023 rewrite function pageRefresh ",
"0.77.0" => "03.05.2023 new attribute ctrlUserExitFn ",
"0.76.0" => "01.05.2023 new ctrlStatisticReadings SunMinutes_Remain, SunHours_Remain ",
"0.75.3" => "23.04.2023 fix Illegal division by zero at ./FHEM/76_SolarForecast.pm line 6199 ",
"0.75.2" => "16.04.2023 some minor changes ",
"0.75.1" => "24.03.2023 change epieces for consumer type washingmachine, PV Vorhersage auf WR Kapazität begrenzen ",
"0.75.0" => "16.02.2023 new attribute ctrlSolCastAPImaxReq, rename attr ctrlOptimizeSolCastInterval to ctrlSolCastAPIoptimizeReq ",
"0.74.8" => "11.02.2023 change description of 'mintime', mintime with SunPath value possible ",
"0.74.7" => "23.01.2023 fix evaljson evaluation ",
"0.1.0" => "09.12.2020 initial Version "
);
@ -344,7 +343,7 @@ my @chours = (5..21);
my $kJtokWh = 0.0002777777778; # Umrechnungsfaktor kJ in kWh
my $kJtoWh = 0.2777777778; # Umrechnungsfaktor kJ in Wh
my $WhtokJ = 3.6; # Umrechnungsfaktor Wh in kJ
my $defmaxvar = 0.8; # max. Varianz pro Tagesberechnung Autokorrekturfaktor
my $defmaxvar = 0.5; # max. Varianz pro Tagesberechnung Autokorrekturfaktor
my $definterval = 70; # Standard Abfrageintervall
my $defslidenum = 3; # max. Anzahl der Arrayelemente in Schieberegistern
my $weatherDevMax = 3; # max. Anzahl Wetter Devices (Attr ctrlWeatherDevX)
@ -384,7 +383,7 @@ my $forapirepdef = 900;
my $ometeorepdef = 900; # default Abrufintervall Open-Meteo API (s)
my $vrmapirepdef = 300; # default Abrufintervall Victron VRM API Forecast
my $solcmaxreqdef = 50; # max. täglich mögliche Requests SolCast API
my $ometmaxreq = 9500; # Beschränkung auf max. mögliche Requests Open-Meteo API
my $ometmaxreq = 9700; # Beschränkung auf max. mögliche Requests Open-Meteo API
my $leadtime = 3600; # relative Zeit vor Sonnenaufgang zur Freigabe API Abruf / Verbraucherplanung
my $lagtime = 1800; # Nachlaufzeit relativ zu Sunset bis Sperrung API Abruf
@ -1032,7 +1031,7 @@ my %hfspvh = (
batoutthishour => { fn => \&_storeVal, storname => 'batout', validkey => undef, fpar => 'comp99' }, # Batterieentladung in Stunde
pvfc => { fn => \&_storeVal, storname => 'pvfc', validkey => undef, fpar => 'comp99' }, # prognostizierter Energieertrag
confc => { fn => \&_storeVal, storname => 'confc', validkey => undef, fpar => 'comp99' }, # prognostizierter Hausverbrauch
cons => { fn => \&_storeVal, storname => 'gcons', validkey => undef, fpar => 'comp99' }, # bezogene Energie
gcons => { fn => \&_storeVal, storname => 'gcons', validkey => undef, fpar => 'comp99' }, # bezogene Energie
gfeedin => { fn => \&_storeVal, storname => 'gfeedin', validkey => undef, fpar => 'comp99' }, # eingespeiste Energie
con => { fn => \&_storeVal, storname => 'con', validkey => undef, fpar => 'comp99' }, # realer Hausverbrauch Energie
pvrl => { fn => \&_storeVal, storname => 'pvrl', validkey => 'pvrlvd', fpar => 'comp99' }, # realer Energieertrag
@ -1756,13 +1755,17 @@ sub _setinverterDevice { ## no critic "not used"
my ($a,$h) = parseParams ($arg);
my $indev = $a->[0] // "";
if(!$indev || !$defs{$indev}) {
if (!$indev || !$defs{$indev}) {
return qq{The device "$indev" doesn't exist!};
}
if(!$h->{pv} || !$h->{etotal}) {
if (!$h->{pv} || !$h->{etotal}) {
return qq{The syntax of "$opt" is not correct. Please consider the commandref.};
}
if ($h->{capacity} && !isNumeric($h->{capacity})) {
return qq{The syntax of key "capacity" is not correct. Please consider the commandref.};
}
readingsSingleUpdate ($hash, 'currentInverterDev', $arg, 1);
createAssociatedWith ($hash);
@ -1835,14 +1838,14 @@ sub _setmeterDevice { ## no critic "not used"
return qq{Incorrect input. It is not allowed that the keys gcon and gfeedin refer to each other.};
}
if ($h->{conprice}) {
my ($gcp,$gcpcucy) = split ":", $h->{conprice};
return qq{Incorrect input for key 'conprice'. Please consider the commandref.} if(!$gcp || !$gcpcucy);
if ($h->{conprice}) { # Bezugspreis (Arbeitspreis) pro kWh
my @acp = split ":", $h->{conprice};
return qq{Incorrect input for key 'conprice'. Please consider the commandref.} if(scalar(@acp) != 2 && scalar(@acp) != 3);
}
if ($h->{feedprice}) {
my ($gfr,$gfrcucy) = split ":", $h->{feedprice};
return qq{Incorrect input for key 'feedprice'. Please consider the commandref.} if(!$gfr || !$gfrcucy);
if ($h->{feedprice}) { # Einspeisevergütung pro kWh
my @afp = split ":", $h->{feedprice};
return qq{Incorrect input for key 'feedprice'. Please consider the commandref.} if(scalar(@afp) != 2 && scalar(@afp) != 3);
}
## alte Speicherwerte löschen
@ -2231,7 +2234,9 @@ sub _setreset { ## no critic "not used"
$paref->{reorg} = 1; # den Tag Stunde "99" reorganisieren
$paref->{reorgday} = $dday;
setPVhistory ($paref);
delete $paref->{reorg};
delete $paref->{reorgday};
}
@ -3433,7 +3438,7 @@ sub __forecastSolar_ApiResponse {
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{requests_limit} = $jdata->{'message'}{'ratelimit'}{'limit'}; # Requests Limit in Periode
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{place} = encode ("utf8", $jdata->{'message'}{'info'}{'place'});
if($debug =~ /apiCall/x) {
if ($debug =~ /apiCall/x) {
Log3 ($name, 1, qq{$name DEBUG> ForecastSolar API Call - server response for PV string "$string"});
Log3 ($name, 1, "$name DEBUG> ForecastSolar API Call - request time: ". $rt." ($rts)");
Log3 ($name, 1, "$name DEBUG> ForecastSolar API Call - requests remaining: ".$jdata->{'message'}{'ratelimit'}{'remaining'});
@ -4132,8 +4137,9 @@ sub __openMeteoDWD_ApiRequest {
my $submodel = $paref->{submodel}; # abzufragendes Wettermodell
if (!$allstrings) { # alle Strings wurden abgerufen
writeCacheToFile ($hash, 'solcastapi', $scpicache.$name);
readingsSingleUpdate ($hash, 'nextRadiationAPICall', $hqtxt{after}{$lang}.' '.(timestampToTimestring ($t + $ometeorepdef, $lang))[0], 1);
writeCacheToFile ($hash, 'solcastapi', $scpicache.$name);
my $apiitv = SolCastAPIVal ($hash, '?All', '?All', 'currentAPIinterval', $ometeorepdef);
readingsSingleUpdate ($hash, 'nextRadiationAPICall', $hqtxt{after}{$lang}.' '.(timestampToTimestring ($t + $apiitv, $lang))[0], 1);
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIcalls} += 1;
return;
}
@ -4300,7 +4306,6 @@ sub __openMeteoDWD_ApiResponse {
if ($debug =~ /apiCall/xs) {
Log3 ($name, 1, qq{$name DEBUG> Open-Meteo API Call - server response for PV string "$string"});
Log3 ($name, 1, "$name DEBUG> Open-Meteo API Call - request time: ".$rt." ($t)");
Log3 ($name, 1, "$name DEBUG> Open-Meteo API Call - status: success");
}
@ -4445,7 +4450,7 @@ sub __openMeteoDWD_ApiResponse {
}
}
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIrequests} += $paref->{callequivalent};
___setOpenMeteoAPIcallKeyData ($paref);
Log3 ($name, 4, qq{$name - Open-Meteo DWD ICON API answer received for string "$string"});
@ -4466,6 +4471,49 @@ sub __openMeteoDWD_ApiResponse {
return &$caller($param);
}
################################################################
# Kennzahlen aus letzten Open-Meteo Request ableiten
################################################################
sub ___setOpenMeteoAPIcallKeyData {
my $paref = shift;
my $hash = $paref->{hash};
my $lang = $paref->{lang};
my $debug = $paref->{debug};
my $cequ = $paref->{callequivalent};
my $t = $paref->{t} // time;
my $name = $hash->{NAME};
my $type = $hash->{TYPE};
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayDoneAPIrequests} += $cequ;
my $dar = SolCastAPIVal ($hash, '?All', '?All', 'todayDoneAPIrequests', 0);
my $dac = SolCastAPIVal ($hash, '?All', '?All', 'todayDoneAPIcalls', 0);
my $asc = CurrentVal ($hash, 'allstringscount', 1);
my $drr = $ometmaxreq - $dar;
$drr = 0 if($drr < 0);
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{todayRemainingAPIrequests} = $drr;
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{currentAPIinterval} = $ometeorepdef;
## Berechnung des optimalen Request Intervalls
################################################
my $edate = strftime "%Y-%m-%d 23:58:00", localtime($t);
my $ets = timestringToTimestamp ($edate);
my $rmdif = $ets - int $t;
if ($drr) {
my $optrep = $rmdif / ($drr / ($cequ * $asc));
$optrep = $ometeorepdef if($optrep < $ometeorepdef);
$data{$type}{$name}{solcastapi}{'?All'}{'?All'}{currentAPIinterval} = $optrep;
}
debugLog ($paref, "apiProcess|apiCall", "Open-Meteo API Call - remaining API Requests: $drr, Request equivalents p. call: $cequ, new call interval: ".SolCastAPIVal ($hash, '?All', '?All', 'currentAPIinterval', $ometeorepdef));
return;
}
###############################################################
# Getter data
###############################################################
@ -6205,6 +6253,8 @@ sub centralTask {
RemoveInternalTimer ($hash, 'FHEM::SolarForecast::centralTask');
RemoveInternalTimer ($hash, 'FHEM::SolarForecast::singleUpdateState');
return if(!$init_done);
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
##########################################################################################################################
@ -6235,8 +6285,6 @@ sub centralTask {
}
#######################################################################################################################
return if(!$init_done);
setModel ($hash); # Model setzen
my (undef, $disabled, $inactive) = controller ($name);
@ -6893,30 +6941,11 @@ sub _transferWeatherValues {
}
if ($fd == 0 && $fh1) { # Weather in pvHistory speichern
$paref->{val} = $wid;
$paref->{histname} = 'weatherid';
$paref->{nhour} = sprintf "%02d", $fh1;
setPVhistory ($paref);
$paref->{val} = $neff // 0;
$paref->{histname} = 'weathercloudcover';
setPVhistory ($paref);
$paref->{val} = $rr1c;
$paref->{histname} = 'totalrain';
setPVhistory ($paref);
$paref->{val} = $temp;
$paref->{histname} = 'temperature';
setPVhistory ($paref);
$paref->{val} = $don;
$paref->{histname} = 'DoN';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{val};
delete $paref->{nhour};
writeToHistory ( { paref => $paref, key => 'weatherid', val => $wid, hour => $fh1 } );
writeToHistory ( { paref => $paref, key => 'weathercloudcover', val => $neff // 0, hour => $fh1 } );
writeToHistory ( { paref => $paref, key => 'totalrain', val => $rr1c, hour => $fh1 } );
writeToHistory ( { paref => $paref, key => 'temperature', val => $temp, hour => $fh1 } );
writeToHistory ( { paref => $paref, key => 'DoN', val => $don, hour => $fh1 } );
}
}
@ -7300,18 +7329,8 @@ sub _transferAPIRadiationValues {
}
if ($fd == 0 && $fh1) {
$paref->{nhour} = sprintf "%02d", $fh1;
$paref->{val} = $pvfc;
$paref->{histname} = 'pvfc';
setPVhistory ($paref);
$paref->{val} = $rad1h;
$paref->{histname} = 'radiation';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{val};
delete $paref->{nhour};
writeToHistory ( { paref => $paref, key => 'pvfc', val => $pvfc, hour => $fh1 } );
writeToHistory ( { paref => $paref, key => 'radiation', val => $rad1h, hour => $fh1 } );
}
}
@ -7362,19 +7381,9 @@ sub __calcSunPosition {
debugLog ($paref, 'collectData', "Sun position: day: $wtday, hod: $hodn, $tstr, azimuth: $az, altitude: $alt");
if ($fd == 0 && $hodn) { # Sun Position in pvHistory speichern
$paref->{nhour} = $hodn;
$paref->{val} = $az;
$paref->{histname} = 'sunaz';
setPVhistory ($paref);
$paref->{val} = $alt;
$paref->{histname} = 'sunalt';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{val};
delete $paref->{nhour};
if ($fd == 0 && $hodn) { # Sun Position in pvHistory speichern
writeToHistory ( { paref => $paref, key => 'sunaz', val => $az, hour => $hodn } );
writeToHistory ( { paref => $paref, key => 'sunalt', val => $alt, hour => $hodn } );
}
return;
@ -7494,8 +7503,8 @@ return $pvsum;
######################################################################
# Complex:
# Liest bewölkungsabhängige Korrekturfaktor/Qualität und
# speichert die Werte im Nexthours / pvHistory Hash
# Liest bewölkungsabhängige Korrekturfaktor/Qualität aus pvCircular
# und speichert die Werte im Nexthours / pvHistory Hash
#
# Simple:
# Liest Korrekturfaktor/Qualität aus pvCircular simple und
@ -7547,16 +7556,8 @@ sub ___readCandQ {
$data{$type}{$name}{nexthours}{"NextHour".sprintf("%02d",$num)}{pvcorrf} = $hc."/".$hq;
if($fd == 0 && $fh1) {
$paref->{val} = $hc.'/'.$hq;
$paref->{nhour} = sprintf "%02d", $fh1;
$paref->{histname} = 'pvcorrfactor';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{val};
delete $paref->{nhour};
if ($fd == 0 && $fh1) {
writeToHistory ( { paref => $paref, key => 'pvcorrfactor', val => $hc.'/'.$hq, hour => $fh1 } );
}
return ($hc, $hq);
@ -7675,7 +7676,7 @@ 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 (PV Erzeugung)
$data{$type}{$name}{current}{invertercapacity} = $h->{capacity} if($h->{capacity}); # optionale Angabe max. WR-Leistung
$data{$type}{$name}{current}{invertercapacity} = $h->{capacity} if(defined $h->{capacity}); # optionale Angabe max. WR-Leistung
return if(!$pvread || !$edread);
@ -7696,47 +7697,43 @@ sub _transferInverterValues {
debugLog ($paref, "collectData", "pv: $pv W, etotal: $etotal Wh");
my $nhour = $chour + 1;
my $histetot = HistoryVal ($hash, $day, sprintf("%02d",$nhour), "etotal", 0); # etotal zu Beginn einer Stunde
my $ethishour;
if (!$histetot) { # etotal der aktuelle Stunde gesetzt ?
$paref->{val} = $etotal;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = 'etotal';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
my $etot = CurrentVal ($hash, "etotal", $etotal);
$ethishour = int ($etotal - $etot);
my $histetot = HistoryVal ($hash, $day, sprintf("%02d",$nhour), 'etotal', 0); # etotal zu Beginn einer Stunde
my $warn = '';
my ($ethishour, $etotsvd);
if (!$histetot) { # etotal der aktuelle Stunde gesetzt ?
writeToHistory ( { paref => $paref, key => 'etotal', val => $etotal, hour => $nhour } );
$etotsvd = CurrentVal ($hash, 'etotal', $etotal);
$ethishour = int ($etotal - $etotsvd);
}
else {
$ethishour = int ($etotal - $histetot);
if (defined $h->{capacity} && $ethishour > 2 x $h->{capacity}) { # Schutz vor plötzlichem Anstieg von 0 auf mehr als doppelte WR-Kapazität
Log3 ($name, 1, "$name - WARNING - The generated PV of Inverter '$indev' is much more higher than inverter capacity. It seems to be a failure and Energy Total is reinitialized.");
$warn = ' (WARNING: too much generated PV was registered - see log file)';
writeToHistory ( { paref => $paref, key => 'etotal', val => $etotal, hour => $nhour } );
$etotsvd = CurrentVal ($hash, 'etotal', $etotal);
$ethishour = int ($etotal - $etotsvd);
}
}
$data{$type}{$name}{current}{etotal} = $etotal; # aktuellen etotal des WR speichern
if ($ethishour < 0) {
$ethishour = 0;
Log3 ($name, 1, "$name - WARNING - The Total Energy from Inverter '$indev' is lower than the value saved before. This situation is invalid and the Energy generated of current hour is set to '0'.");
$warn = ' (WARNING invalid real PV occured - see Logfile)';
}
$ethishour = 0 if($ethishour < 0);
storeReading ('Today_Hour'.sprintf("%02d",$nhour).'_PVreal', $ethishour.' Wh');
storeReading ('Today_Hour'.sprintf("%02d",$nhour).'_PVreal', $ethishour.' Wh'.$warn);
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{pvrl} = $ethishour; # Ringspeicher PV real Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
my ($acu, $aln) = isAutoCorrUsed ($name);
$paref->{val} = $ethishour;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = 'pvrl';
$paref->{pvrlvd} = $aln; # 1: beim Learning berücksichtigen, 0: nicht
setPVhistory ($paref);
delete $paref->{pvrlvd};
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
writeToHistory ( { paref => $paref, key => 'pvrl', val => $ethishour, hour => $nhour, valid => $aln } ); # valid=1: beim Learning berücksichtigen, 0: nicht
return;
}
@ -7765,16 +7762,44 @@ sub _transferMeterValues {
return if(!$gc || !$gf || !$gt || !$ft);
if ($h->{conprice}) {
my ($gcp,$gcpcucy) = split ":", $h->{conprice}; # Bezugspreis (Arbeitspreis) pro kWh
$data{$type}{$name}{current}{ePurchasePrice} = $gcp;
$data{$type}{$name}{current}{ePurchasePriceCcy} = $gcpcucy;
if ($h->{conprice}) { # Bezugspreis (Arbeitspreis) pro kWh
my @acp = split ":", $h->{conprice};
if (scalar(@acp) == 3) {
$data{$type}{$name}{current}{ePurchasePrice} = ReadingsNum ($acp[0], $acp[1], 0);
$data{$type}{$name}{current}{ePurchasePriceCcy} = $acp[2];
}
if (scalar(@acp) == 2) {
if (isNumeric($acp[0])) {
$data{$type}{$name}{current}{ePurchasePrice} = $acp[0];
$data{$type}{$name}{current}{ePurchasePriceCcy} = $acp[1];
}
else {
$data{$type}{$name}{current}{ePurchasePrice} = ReadingsNum ($medev, $acp[0], 0);
$data{$type}{$name}{current}{ePurchasePriceCcy} = $acp[1];
}
}
}
if ($h->{feedprice}) {
my ($gfr,$gfrcucy) = split ":", $h->{feedprice}; # Einspeisevergütung pro kWh
$data{$type}{$name}{current}{eFeedInTariff} = $gfr;
$data{$type}{$name}{current}{eFeedInTariffCcy} = $gfrcucy;
if ($h->{feedprice}) { # Einspeisevergütung pro kWh
my @afp = split ":", $h->{feedprice};
if (scalar(@afp) == 3) {
$data{$type}{$name}{current}{eFeedInTariff} = ReadingsNum ($afp[0], $afp[1], 0);
$data{$type}{$name}{current}{eFeedInTariffCcy} = $afp[2];
}
if (scalar(@afp) == 2) {
if (isNumeric($afp[0])) {
$data{$type}{$name}{current}{eFeedInTariff} = $afp[0];
$data{$type}{$name}{current}{eFeedInTariffCcy} = $afp[1];
}
else {
$data{$type}{$name}{current}{eFeedInTariff} = ReadingsNum ($medev, $afp[0], 0);
$data{$type}{$name}{current}{eFeedInTariffCcy} = $afp[1];
}
}
}
$gfunit //= $gcunit;
@ -7863,16 +7888,8 @@ sub _transferMeterValues {
my $nhour = $chour + 1;
storeReading ('Today_Hour'.sprintf("%02d",$nhour).'_GridConsumption', $gctotthishour.' Wh');
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{gcons} = $gctotthishour; # Hilfshash Wert Bezug (Wh) Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$paref->{val} = $gctotthishour;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = 'cons';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
writeToHistory ( { paref => $paref, key => 'gcons', val => $gctotthishour, hour => $nhour } );
}
my $dofeed = 0;
@ -7902,16 +7919,8 @@ sub _transferMeterValues {
my $nhour = $chour+1;
storeReading ('Today_Hour'.sprintf("%02d",$nhour).'_GridFeedIn', $gftotthishour.' Wh');
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{gfeedin} = $gftotthishour;
$paref->{val} = $gftotthishour;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = 'gfeedin';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
writeToHistory ( { paref => $paref, key => 'gfeedin', val => $gftotthishour, hour => $nhour } );
}
return;
@ -8013,15 +8022,17 @@ sub _transferBatteryValues {
my $batinthishour;
if (!defined $histbatintot) { # totale Batterieladung der aktuelle Stunde gesetzt ?
$paref->{val} = $btotin;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = 'batintotal';
#$paref->{val} = $btotin;
#$paref->{nhour} = sprintf "%02d", $nhour;
#$paref->{histname} = 'batintotal';
setPVhistory ($paref);
#setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
#delete $paref->{histname};
#delete $paref->{nhour};
#delete $paref->{val};
writeToHistory ( { paref => $paref, key => 'batintotal', val => $btotin, hour => $nhour } );
my $bitot = CurrentVal ($hash, "batintotal", $btotin);
$batinthishour = int ($btotin - $bitot);
@ -8034,15 +8045,17 @@ sub _transferBatteryValues {
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{batin} = $batinthishour; # Ringspeicher Battery In Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$paref->{val} = $batinthishour;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = 'batinthishour';
#$paref->{val} = $batinthishour;
#$paref->{nhour} = sprintf "%02d", $nhour;
#$paref->{histname} = 'batinthishour';
setPVhistory ($paref);
#setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
#delete $paref->{histname};
#delete $paref->{nhour};
#delete $paref->{val};
writeToHistory ( { paref => $paref, key => 'batinthishour', val => $batinthishour, hour => $nhour } );
# Batterieentladung aktuelle Stunde in pvHistory speichern
############################################################
@ -8050,15 +8063,17 @@ sub _transferBatteryValues {
my $batoutthishour;
if (!defined $histbatouttot) { # totale Betterieladung der aktuelle Stunde gesetzt ?
$paref->{val} = $btotout;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = 'batouttotal';
#$paref->{val} = $btotout;
#$paref->{nhour} = sprintf "%02d", $nhour;
#$paref->{histname} = 'batouttotal';
setPVhistory ($paref);
#setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
#delete $paref->{histname};
#delete $paref->{nhour};
#delete $paref->{val};
writeToHistory ( { paref => $paref, key => 'batouttotal', val => $btotout, hour => $nhour } );
my $botot = CurrentVal ($hash, 'batouttotal', $btotout);
$batoutthishour = int ($btotout - $botot);
@ -8071,30 +8086,34 @@ sub _transferBatteryValues {
$data{$type}{$name}{circular}{sprintf("%02d",$nhour)}{batout} = $batoutthishour; # Ringspeicher Battery In Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$paref->{val} = $batoutthishour;
$paref->{nhour} = sprintf "%02d", $nhour;
$paref->{histname} = 'batoutthishour';
#$paref->{val} = $batoutthishour;
#$paref->{nhour} = sprintf "%02d", $nhour;
#$paref->{histname} = 'batoutthishour';
setPVhistory ($paref);
#setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
#delete $paref->{histname};
#delete $paref->{nhour};
#delete $paref->{val};
writeToHistory ( { paref => $paref, key => 'batoutthishour', val => $batoutthishour, hour => $nhour } );
# täglichen max. SOC in pvHistory speichern
#############################################
my $batmaxsoc = HistoryVal ($hash, $day, 99, 'batmaxsoc', 0); # gespeicherter max. SOC des Tages
if ($soc >= $batmaxsoc) {
$paref->{val} = $soc;
$paref->{nhour} = 99;
$paref->{histname} = 'batmaxsoc';
#$paref->{val} = $soc;
#$paref->{nhour} = 99;
#$paref->{histname} = 'batmaxsoc';
setPVhistory ($paref);
#setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
#delete $paref->{histname};
#delete $paref->{nhour};
#delete $paref->{val};
writeToHistory ( { paref => $paref, key => 'batmaxsoc', val => $soc, hour => 99 } );
}
######
@ -8240,19 +8259,10 @@ sub _batSocTarget {
($chargereq ? 'yes (battery charge is below minimum SoC)' : 'no (Battery is sufficiently charged)'));
## pvHistory/Readings schreiben
#################################
$paref->{val} = $target;
$paref->{nhour} = 99;
$paref->{histname} = 'batsetsoc';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
storeReading ('Battery_OptimumTargetSoC', $target.' %');
storeReading ('Battery_ChargeRequest', $chargereq);
#################################
writeToHistory ( { paref => $paref, key => 'batsetsoc', val => $target, hour => 99 } );
storeReading ('Battery_OptimumTargetSoC', $target.' %');
storeReading ('Battery_ChargeRequest', $chargereq);
return;
}
@ -10045,17 +10055,8 @@ sub _estConsumptionForecast {
$data{$type}{$name}{nexthours}{$k}{confc} = $conavg; # Durchschnittsverbrauch aller gleicher Wochentage pro Stunde
if (NexthoursVal ($hash, $k, "today", 0)) { # nur Werte des aktuellen Tag speichern
$data{$type}{$name}{circular}{sprintf("%02d",$nhhr)}{confc} = $conavg;
$paref->{val} = $conavg;
$paref->{nhour} = sprintf "%02d", $nhhr;
$paref->{histname} = 'confc';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
$data{$type}{$name}{circular}{sprintf("%02d",$nhhr)}{confc} = $conavg;
writeToHistory ( { paref => $paref, key => 'confc', val => $conavg, hour => $nhhr } );
}
debugLog ($paref, "consumption", "estimated Consumption for $nhday -> starttime: $nhtime, confc: $conavg, days for avg: $dnum, hist. consumption registered consumers: ".sprintf "%.2f", $consumerco);
@ -10558,24 +10559,15 @@ sub saveEnergyConsumption {
my $name = $paref->{name};
my $chour = $paref->{chour};
my $shr = $chour+1;
my $shr = $chour + 1;
my $pvrl = ReadingsNum ($name, "Today_Hour".sprintf("%02d",$shr)."_PVreal", 0);
my $gfeedin = ReadingsNum ($name, "Today_Hour".sprintf("%02d",$shr)."_GridFeedIn", 0);
my $gcon = ReadingsNum ($name, "Today_Hour".sprintf("%02d",$shr)."_GridConsumption", 0);
my $batin = ReadingsNum ($name, "Today_Hour".sprintf("%02d",$shr)."_BatIn", 0);
my $batout = ReadingsNum ($name, "Today_Hour".sprintf("%02d",$shr)."_BatOut", 0);
my $con = $pvrl - $gfeedin + $gcon - $batin + $batout;
$paref->{val} = $con;
$paref->{nhour} = sprintf "%02d", $shr;
$paref->{histname} = 'con';
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
my $con = $pvrl - $gfeedin + $gcon - $batin + $batout;
writeToHistory ( { paref => $paref, key => 'con', val => $con, hour => $shr } );
return;
}
@ -11506,7 +11498,7 @@ sub _graphicHeader {
$api .= '&nbsp;&nbsp;(';
$api .= SolCastAPIVal ($hash, '?All', '?All', 'todayDoneAPIrequests', 0);
$api .= '/';
$api .= SolCastAPIVal ($hash, '?All', '?All', 'todayRemainingAPIrequests', 50);
$api .= SolCastAPIVal ($hash, '?All', '?All', 'todayRemainingAPIrequests', $solcmaxreqdef);
$api .= ')';
$api .= '</span>';
}
@ -11593,9 +11585,11 @@ sub _graphicHeader {
$scicon = "<a>$img</a>";
$api .= '&nbsp;&nbsp;'.$scicon;
$api .= '<span title="'.$htitles{dapic}{$lang}.'">';
$api .= '<span title="'.$htitles{dapic}{$lang}.' / '.$htitles{rapic}{$lang}.'">';
$api .= '&nbsp;&nbsp;(';
$api .= SolCastAPIVal ($hash, '?All', '?All', 'todayDoneAPIrequests', 0);
$api .= '/';
$api .= SolCastAPIVal ($hash, '?All', '?All', 'todayRemainingAPIrequests', $ometmaxreq);
$api .= ')';
$api .= '</span>';
}
@ -14192,6 +14186,39 @@ sub _aiMakeIdxRaw {
return $ridx;
}
################################################################
# einen Schlüssel-Wert in die pvHistory schreiben
# $valid - Wert für Valid-Key festgelegt in $hfspvh Hash
# z.B. pvrlvd = 1: beim Learning berücksichtigen, 0: nicht
################################################################
sub writeToHistory {
my $ph = shift;
my $paref = $ph->{paref};
my $key = $ph->{key};
my $val = $ph->{val};
my $hour = $ph->{hour};
my $valid = $ph->{valid};
$paref->{val} = $val;
$paref->{nhour} = sprintf "%02d", $hour;
$paref->{histname} = $key;
if (defined $hfspvh{$key}{validkey}) {
$paref->{$hfspvh{$key}{validkey}} = $valid;
}
setPVhistory ($paref);
delete $paref->{histname};
delete $paref->{nhour};
delete $paref->{val};
delete $paref->{$hfspvh{$key}{validkey}} if(defined $hfspvh{$key}{validkey});
return;
}
################################################################
# History-Hash verwalten
################################################################
@ -14205,7 +14232,6 @@ sub setPVhistory {
my $nhour = $paref->{nhour};
my $histname = $paref->{histname};
my $val = $paref->{val}; # Wert zur Speicherung in pvHistory (soll mal generell verwendet werden -> Change)
my $pvrlvd = $paref->{pvrlvd}; # 1: Eintrag 'pvrl' wird im Lernprozess berücksichtigt
my $reorg = $paref->{reorg} // 0; # Neuberechnung von Werten in Stunde "99" nach Löschen von Stunden eines Tages
my $reorgday = $paref->{reorgday} // q{}; # Tag der reorganisiert werden soll
@ -14313,7 +14339,7 @@ sub _storeVal { ## no critic "not used"
$data{$type}{$name}{pvhist}{$day}{$nhour}{$store} = $val;
if (defined $hfspvh{$histname}{validkey}) {
if (defined $hfspvh{$histname}{validkey}) { # 1: bestimmter Eintrag wird intern für Prozesse (z.B. Lernprozess) berücksichtigt oder nicht (0)
$validkey = $hfspvh{$histname}{validkey};
$validval = $paref->{$validkey};
$data{$type}{$name}{pvhist}{$day}{$nhour}{$validkey} = $validval;
@ -14358,7 +14384,7 @@ sub listDataPool {
my $pvrl = HistoryVal ($hash, $day, $key, 'pvrl', '-');
my $pvrlvd = HistoryVal ($hash, $day, $key, 'pvrlvd', '-');
my $pvfc = HistoryVal ($hash, $day, $key, 'pvfc', '-');
my $gcon = HistoryVal ($hash, $day, $key, 'gcons', '-');
my $gcons = HistoryVal ($hash, $day, $key, 'gcons', '-');
my $con = HistoryVal ($hash, $day, $key, 'con', '-');
my $confc = HistoryVal ($hash, $day, $key, 'confc', '-');
my $gfeedin = HistoryVal ($hash, $day, $key, 'gfeedin', '-');
@ -14384,7 +14410,7 @@ sub listDataPool {
$ret .= $key." => ";
$ret .= "etotal: $etotal, pvfc: $pvfc, pvrl: $pvrl, pvrlvd: $pvrlvd, rad1h: $rad1h";
$ret .= "\n ";
$ret .= "confc: $confc, con: $con, gcon: $gcon, gfeedin: $gfeedin";
$ret .= "confc: $confc, con: $con, gcon: $gcons, gfeedin: $gfeedin";
$ret .= "\n ";
$ret .= "DoN: $don, sunaz: $sunaz, sunalt: $sunalt";
$ret .= "\n ";
@ -14648,7 +14674,7 @@ sub listDataPool {
}
for my $idx (sort keys %{$h}) {
if (ref $h->{$idx} ne "ARRAY") {
$sq .= $idx." => ".$h->{$idx}."\n";
$sq .= $idx." => ".(defined $h->{$idx} ? $h->{$idx} : '')."\n";
}
else {
my $aser = join " ",@{$h->{$idx}};
@ -17770,11 +17796,12 @@ to ensure that the system configuration is correct.
<ul>
<table>
<colgroup> <col width="15%"> <col width="85%"> </colgroup>
<tr><td> <b>pv</b> </td><td>Reading which provides the current PV generation </td></tr>
<tr><td> <b>etotal</b> </td><td>Reading which provides the total PV energy generated (a steadily increasing counter). </td></tr>
<tr><td> <b>Einheit</b> </td><td>the respective unit (W,kW,Wh,kWh) </td></tr>
<tr><td> <b>capacity</b> </td><td>Rated power of the inverter according to data sheet (max. possible output in watts) </td></tr>
</table>
<tr><td> <b>pv</b> </td><td>Reading which provides the current PV generation </td></tr>
<tr><td> <b>etotal</b> </td><td>Reading which provides the total PV energy generated (a steadily increasing counter). </td></tr>
<tr><td> <b>Einheit</b> </td><td>the respective unit (W,kW,Wh,kWh) </td></tr>
<tr><td> <b>capacity</b> </td><td>Rated power of the inverter according to data sheet, i.e. max. possible output in Watts </td></tr>
<tr><td> </td><td>(The entry is optional, but is strongly recommended) </td></tr>
</table>
</ul>
<br>
@ -17791,9 +17818,9 @@ to ensure that the system configuration is correct.
<ul>
<a id="SolarForecast-set-currentMeterDev"></a>
<li><b>currentMeterDev &lt;Meter Device Name&gt; gcon=&lt;Readingname&gt;:&lt;Einheit&gt; contotal=&lt;Readingname&gt;:&lt;Einheit&gt;
gfeedin=&lt;Readingname&gt;:&lt;Einheit&gt; feedtotal=&lt;Readingname&gt;:&lt;Einheit&gt;
[conprice=&lt;Wert&gt;:&lt;Currency&gt;] [feedprice=&lt;Wert&gt;:&lt;Currency&gt;] </b> <br><br>
<li><b>currentMeterDev &lt;Meter Device Name&gt; gcon=&lt;Readingname&gt;:&lt;Unit&gt; contotal=&lt;Readingname&gt;:&lt;Unit&gt;
gfeedin=&lt;Readingname&gt;:&lt;Unit&gt; feedtotal=&lt;Readingname&gt;:&lt;Unit&gt;
[conprice=&lt;Field&gt;] [feedprice=&lt;Field&gt;] </b> <br><br>
Sets any device and its readings for energy measurement.
The module assumes that the numeric value of the readings is positive.
@ -17803,13 +17830,21 @@ to ensure that the system configuration is correct.
<ul>
<table>
<colgroup> <col width="15%"> <col width="85%"> </colgroup>
<tr><td> <b>gcon</b> </td><td>Reading which supplies the power currently drawn from the grid </td></tr>
<tr><td> <b>contotal</b> </td><td>Reading which provides the sum of the energy drawn from the grid (a constantly increasing meter) </td></tr>
<tr><td> <b>gfeedin</b> </td><td>Reading which supplies the power currently fed into the grid </td></tr>
<tr><td> <b>feedtotal</b> </td><td>Reading which provides the sum of the energy fed into the grid (a constantly increasing meter) </td></tr>
<tr><td> <b>Einheit</b> </td><td>the respective unit (W,kW,Wh,kWh) </td></tr>
<tr><td> <b>conprice</b> </td><td>Price and currency for the purchase of one kWh (optional) </td></tr>
<tr><td> <b>feedprice</b> </td><td>Price and currency for the feed-in of one kWh (optional) </td></tr>
<tr><td> <b>gcon</b> </td><td>Reading which supplies the power currently drawn from the grid </td></tr>
<tr><td> <b>contotal</b> </td><td>Reading which provides the sum of the energy drawn from the grid (a constantly increasing meter) </td></tr>
<tr><td> <b>gfeedin</b> </td><td>Reading which supplies the power currently fed into the grid </td></tr>
<tr><td> <b>feedtotal</b> </td><td>Reading which provides the sum of the energy fed into the grid (a constantly increasing meter) </td></tr>
<tr><td> <b>Unit</b> </td><td>the respective unit (W,kW,Wh,kWh) </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>conprice</b> </td><td>Price for the purchase of one kWh (optional). The &lt;field&gt; can be specified in one of the following variants: </td></tr>
<tr><td> </td><td>&lt;Price&gt;:&lt;Currency&gt; - Price as a numerical value and its currency </td></tr>
<tr><td> </td><td>&lt;Reading&gt;:&lt;Currency&gt; - Reading of the <b>meter device</b> that contains the price : Currency </td></tr>
<tr><td> </td><td>&lt;Device&gt;:&lt;Reading&gt;:&lt;Currency&gt; - any device and reading containing the price : Currency </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>feedprice</b> </td><td>Remuneration for the feed-in of one kWh (optional). The &lt;field&gt; can be specified in one of the following variants: </td></tr>
<tr><td> </td><td>&lt;Remuneration&gt;:&lt;Currency&gt; - Remuneration as a numerical value and its currency </td></tr>
<tr><td> </td><td>&lt;Reading&gt;:&lt;Currency&gt; - Reading of the <b>meter device</b> that contains the remuneration : Currency </td></tr>
<tr><td> </td><td>&lt;Device&gt;:&lt;Reading&gt;:&lt;Currency&gt; - any device and reading containing the remuneration : Currency </td></tr>
</table>
</ul>
<br>
@ -17826,7 +17861,7 @@ to ensure that the system configuration is correct.
<ul>
<b>Example: </b> <br>
set &lt;name&gt; currentMeterDev Meter gcon=Wirkleistung:W contotal=BezWirkZaehler:kWh gfeedin=-gcon feedtotal=EinWirkZaehler:kWh conprice=0.2958: feedprice=0.1269: <br>
set &lt;name&gt; currentMeterDev Meter gcon=Wirkleistung:W contotal=BezWirkZaehler:kWh gfeedin=-gcon feedtotal=EinWirkZaehler:kWh conprice=powerCost: feedprice=0.1269: <br>
<br>
# Device Meter provides the current grid reference in the reading "Wirkleistung" (W),
the sum of the grid reference in the reading "BezWirkZaehler" (kWh), the current feed in "Wirkleistung" if "Wirkleistung" is negative,
@ -19247,7 +19282,7 @@ to ensure that the system configuration is correct.
<a id="SolarForecast-attr-ctrlWeatherDev" data-pattern="ctrlWeatherDev.*"></a>
<li><b>ctrlWeatherDevX </b> <br><br>
Specifies the device or API that provides the required weather data (cloud cover, precipitation, etc.).<br>
Specifies the device or API for providing the required weather data (cloud cover, precipitation, etc.).<br>
The attribute 'ctrlWeatherDev1' specifies the leading weather service and is mandatory.<br>
If an Open-Meteo API is selected in the 'ctrlWeatherDev1' attribute, this Open-Meteo service is automatically set as the
source of the radiation data (Setter currentRadiationAPI). <br><br>
@ -20000,10 +20035,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<ul>
<table>
<colgroup> <col width="15%"> <col width="85%"> </colgroup>
<tr><td> <b>pv</b> </td><td>Reading welches die aktuelle PV-Erzeugung liefert </td></tr>
<tr><td> <b>etotal</b> </td><td>Reading welches die gesamte erzeugte PV-Energie liefert (ein stetig aufsteigender Zähler) </td></tr>
<tr><td> <b>Einheit</b> </td><td>die jeweilige Einheit (W,kW,Wh,kWh) </td></tr>
<tr><td> <b>capacity</b> </td><td>Bemessungsleistung des Wechselrichters gemäß Datenblatt (max. möglicher Output in Watt) </td></tr>
<tr><td> <b>pv</b> </td><td>Reading welches die aktuelle PV-Erzeugung liefert </td></tr>
<tr><td> <b>etotal</b> </td><td>Reading welches die gesamte erzeugte PV-Energie liefert (ein stetig aufsteigender Zähler) </td></tr>
<tr><td> <b>Einheit</b> </td><td>die jeweilige Einheit (W,kW,Wh,kWh) </td></tr>
<tr><td> <b>capacity</b> </td><td>Bemessungsleistung des Wechselrichters gemäß Datenblatt, d.h. max. möglicher Output in Watt </td></tr>
<tr><td> </td><td>(Die Angabe ist optional, wird aber dringend empfohlen zu setzen) </td></tr>
</table>
</ul>
<br>
@ -20023,7 +20059,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<a id="SolarForecast-set-currentMeterDev"></a>
<li><b>currentMeterDev &lt;Meter Device Name&gt; gcon=&lt;Readingname&gt;:&lt;Einheit&gt; contotal=&lt;Readingname&gt;:&lt;Einheit&gt;
gfeedin=&lt;Readingname&gt;:&lt;Einheit&gt; feedtotal=&lt;Readingname&gt;:&lt;Einheit&gt;
[conprice=&lt;Wert&gt;:&lt;Currency&gt;] [feedprice=&lt;Wert&gt;:&lt;Currency&gt;] </b> <br><br>
[conprice=&lt;Feld&gt;] [feedprice=&lt;Feld&gt;] </b> <br><br>
Legt ein beliebiges Device und seine Readings zur Energiemessung fest.
Das Modul geht davon aus, dass der numerische Wert der Readings positiv ist.
@ -20033,14 +20069,22 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<ul>
<table>
<colgroup> <col width="15%"> <col width="85%"> </colgroup>
<tr><td> <b>gcon</b> </td><td>Reading welches die aktuell aus dem Netz bezogene Leistung liefert </td></tr>
<tr><td> <b>contotal</b> </td><td>Reading welches die Summe der aus dem Netz bezogenen Energie liefert (ein sich stetig erhöhender Zähler) </td></tr>
<tr><td> <b>gfeedin</b> </td><td>Reading welches die aktuell in das Netz eingespeiste Leistung liefert </td></tr>
<tr><td> <b>feedtotal</b> </td><td>Reading welches die Summe der in das Netz eingespeisten Energie liefert (ein sich stetig erhöhender Zähler) </td></tr>
<tr><td> <b>Einheit</b> </td><td>die jeweilige Einheit (W,kW,Wh,kWh) </td></tr>
<tr><td> <b>conprice</b> </td><td>Preis und Währung für den Bezug einer kWh (optional) </td></tr>
<tr><td> <b>feedprice</b> </td><td>Preis und Währung für die Einspeisung einer kWh (optional) </td></tr>
</table>
<tr><td> <b>gcon</b> </td><td>Reading welches die aktuell aus dem Netz bezogene Leistung liefert </td></tr>
<tr><td> <b>contotal</b> </td><td>Reading welches die Summe der aus dem Netz bezogenen Energie liefert (ein sich stetig erhöhender Zähler) </td></tr>
<tr><td> <b>gfeedin</b> </td><td>Reading welches die aktuell in das Netz eingespeiste Leistung liefert </td></tr>
<tr><td> <b>feedtotal</b> </td><td>Reading welches die Summe der in das Netz eingespeisten Energie liefert (ein sich stetig erhöhender Zähler) </td></tr>
<tr><td> <b>Einheit</b> </td><td>die jeweilige Einheit (W,kW,Wh,kWh) </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>conprice</b> </td><td>Preis für den Bezug einer kWh (optional). Die Angabe &lt;Feld&gt; ist in einer der folgenden Varianten möglich: </td></tr>
<tr><td> </td><td>&lt;Preis&gt;:&lt;Währung&gt; - Preis als numerischer Wert und dessen Währung </td></tr>
<tr><td> </td><td>&lt;Reading&gt;:&lt;Währung&gt; - Reading des <b>Meter Device</b> das den Preis enthält : Währung </td></tr>
<tr><td> </td><td>&lt;Device&gt;:&lt;Reading&gt;:&lt;Währung&gt; - beliebiges Device und Reading welches den Preis enthält : Währung </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>feedprice</b> </td><td>Vergütung für die Einspeisung einer kWh (optional). Die Angabe &lt;Feld&gt; ist in einer der folgenden Varianten möglich: </td></tr>
<tr><td> </td><td>&lt;Vergütung&gt;:&lt;Währung&gt; - Vergütung als numerischer Wert und dessen Währung </td></tr>
<tr><td> </td><td>&lt;Reading&gt;:&lt;Währung&gt; - Reading des <b>Meter Device</b> das die Vergütung enthält : Währung </td></tr>
<tr><td> </td><td>&lt;Device&gt;:&lt;Reading&gt;:&lt;Währung&gt; - beliebiges Device und Reading welches die Vergütung enthält : Währung </td></tr>
</table>
</ul>
<br>
@ -20056,7 +20100,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<ul>
<b>Beispiel: </b> <br>
set &lt;name&gt; currentMeterDev Meter gcon=Wirkleistung:W contotal=BezWirkZaehler:kWh gfeedin=-gcon feedtotal=EinWirkZaehler:kWh conprice=0.2958: feedprice=0.1269: <br>
set &lt;name&gt; currentMeterDev Meter gcon=Wirkleistung:W contotal=BezWirkZaehler:kWh gfeedin=-gcon feedtotal=EinWirkZaehler:kWh conprice=powerCost: feedprice=0.1269: <br>
<br>
# Device Meter liefert den aktuellen Netzbezug im Reading "Wirkleistung" (W),
die Summe des Netzbezugs im Reading "BezWirkZaehler" (kWh), die aktuelle Einspeisung in "Wirkleistung" wenn "Wirkleistung" negativ ist,
@ -21489,7 +21533,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<a id="SolarForecast-attr-ctrlWeatherDev" data-pattern="ctrlWeatherDev.*"></a>
<li><b>ctrlWeatherDevX </b> <br><br>
Gibt das Gerät oder die API an, das/die die erforderlichen Wetterdaten (Wolkendecke, Niederschlag usw.) liefert.<br>
Gibt das Gerät oder die API zur Lieferung der erforderlichen Wetterdaten (Wolkendecke, Niederschlag usw.) an.<br>
Das Attribut 'ctrlWeatherDev1' definiert den führenden Wetterdienst und ist zwingend erforderlich.<br>
Ist eine Open-Meteo API im Attribut 'ctrlWeatherDev1' ausgewählt, wird dieser Open-Meteo Dienst automatisch auch als Quelle
der Strahlungsdaten (Setter currentRadiationAPI) eingestellt. <br><br>