25 Commits

Author SHA1 Message Date
73a071351f WS3600: readingFnAttributes 2025-11-25 21:31:36 +01:00
jowiemann
3f3d78330f 72_FRITZBOX.pm: Version 08.20.08
git-svn-id: https://svn.fhem.de/fhem/trunk@30553 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-25 07:08:10 +00:00
jowiemann
d599516f69 CHANGED: 72_FRITZBOX.pm
git-svn-id: https://svn.fhem.de/fhem/trunk@30552 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-25 07:02:33 +00:00
fhemupdate
71f05de0eb controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30551 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-25 06:45:18 +00:00
fhemupdate
9c39c38a87 controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30550 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-24 06:45:18 +00:00
fhemupdate
57ded9e36f controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30549 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-23 06:45:31 +00:00
DS_Starter
625f37f317 76_SolarForecast: new special Reading BatRatio
git-svn-id: https://svn.fhem.de/fhem/trunk@30548 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-22 19:59:56 +00:00
fhemupdate
209f66d94f controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30547 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-22 06:45:17 +00:00
fhemupdate
6a75fc2538 controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30546 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-21 06:45:18 +00:00
phenning
c92494750d 72_FBTAM.pm: Bugfix beim Passwort
git-svn-id: https://svn.fhem.de/fhem/trunk@30545 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-20 15:26:52 +00:00
DS_Starter
6c0864c70d 76_SolarForecast: contrib version 1.60.7
git-svn-id: https://svn.fhem.de/fhem/trunk@30544 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-20 14:00:32 +00:00
fhemupdate
8d459f12ba controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30543 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-20 06:45:17 +00:00
DS_Starter
378fa74d68 76_SolarForecast: contrib Version 1.60.7
git-svn-id: https://svn.fhem.de/fhem/trunk@30542 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-19 21:01:35 +00:00
fhemupdate
046c1e42c2 controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30541 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-19 06:45:18 +00:00
DS_Starter
b9dfa2360a 76_SolarForecast: fix consumption till sunset,SOC use of consumption
git-svn-id: https://svn.fhem.de/fhem/trunk@30540 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-18 19:14:52 +00:00
DS_Starter
312d319a98 76_SolarForecast: contrib version 1.60.6
git-svn-id: https://svn.fhem.de/fhem/trunk@30539 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-18 16:25:20 +00:00
DS_Starter
fe808898c7 76_SolarForecast: contrib version 1.60.6
git-svn-id: https://svn.fhem.de/fhem/trunk@30538 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-18 10:40:29 +00:00
fhemupdate
75e3215986 controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30537 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-18 06:45:18 +00:00
fhemupdate
8c29786907 controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30536 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-17 06:45:18 +00:00
DS_Starter
ecff834d4a 76_SolarForecast: Version 1.60.5
git-svn-id: https://svn.fhem.de/fhem/trunk@30535 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-16 22:05:17 +00:00
DS_Starter
8e0010bb38 76_SolarForecast: Version 1.60.5
git-svn-id: https://svn.fhem.de/fhem/trunk@30534 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-16 16:10:27 +00:00
DS_Starter
107668395b 76_SolarForecast: Version 1.60.5
git-svn-id: https://svn.fhem.de/fhem/trunk@30533 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-16 13:39:47 +00:00
DS_Starter
24ce02989d 76_SolarForecast: Version 1.60.5
git-svn-id: https://svn.fhem.de/fhem/trunk@30532 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-16 13:30:14 +00:00
DS_Starter
974eee8d59 76_SolarForecast: Version 1.60.5
git-svn-id: https://svn.fhem.de/fhem/trunk@30531 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-16 09:10:28 +00:00
fhemupdate
773b95993b controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30530 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-16 06:45:17 +00:00
7 changed files with 1332 additions and 539 deletions

View File

@@ -1,5 +1,11 @@
# 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
- bugfix: 72_FRITZBOX: Fehlerkorrekturen
- feature: 72_FRITZBOX: zusätzliche Readings für SmartHome
set <name> smartHome <deviceID> <boost:0..120>
- feature: 76_SolarForecast: new special Reading BatRatio
- bugfix: 76_SolarForecast: fix consumption till sunset,SOC use of consumption
- feature: 76_SolarForecast: Version 1.60.5
- feature: 76_SolarForecast: Version 1.60.4
- feature: 76_SolarForecast: Version 1.60.3, new param barrierSoC
- bugfix: 72_FRITZBOX: box_ppp_ überarbeitet

View File

@@ -181,7 +181,8 @@ WS3600_Initialize($)
# Consumer
$hash->{DefFn} = "WS3600_Define";
$hash->{AttrList}= "model:WS3600,WS2300,WS1080,WS3080";
$hash->{AttrList}= "model:WS3600,WS2300,WS1080,WS3080 ".
$readingFnAttributes;
# $hash->{ReadFn} = "WS3600_Read";
$hash->{UndefFn} = "WS3600_Undef";
}
@@ -267,7 +268,7 @@ WS3600_Read($)
# Log 1-GetLogLevel($name,0), "WS3600(Err): (1) Error";
# Log3 $name, 4, "WS3600(Dbg): $name Read started using \"$dev\"";
Log3 $name, 3, "WS3600(Msg): $name Read started";
# Log3 $name, 3, "WS3600(Msg): $name Read started";
@lines = `$dev`; # call external program
foreach my $inputline ( @lines ) {
@@ -275,10 +276,14 @@ WS3600_Read($)
my ($rawreading, $val, $val2) = split(/ /, $inputline, 3);
if(defined($rawreading)) {
if(!defined($val2)) { $val2 = ""; }
Log3 $name, 4, "WS3600(Dbg): $name read $inputline|$rawreading|$val|$val2";
my $logmsg = "WS3600(Dbg): $name read $inputline|$rawreading|$val";
$logmsg .= "|$val2" if(defined($val2));
# Log3 $name, 4, $logmsg;
# Log3 $name, 4, "WS3600(Dbg): $name read $inputline|$rawreading|$val|$val2";
if(defined($TranslatedCodes{$rawreading})) {
$reading = $TranslatedCodes{$rawreading};
readingsBulkUpdate($hash,$reading, $val);
Log3 $name, 4, "WS3600(Dbg): $name read $inputline|$rawreading|$reading|$val|$val2";
$AnythingRead = 1;
}
# write Date/Time-Records
@@ -304,7 +309,7 @@ WS3600_Read($)
. " Ti: " . $defs{$name}{READINGS}{"Temp-inside"}{VAL}
. " Hi: " . $defs{$name}{READINGS}{"rel-Humidity-inside"}{VAL};
$hash->{CHANGED}[0] = $hash->{STATE};
# $hash->{CHANGED}[0] = $hash->{STATE};
}
else {
$hash->{STATE} = "no data received";

View File

@@ -31,9 +31,9 @@ package main;
use strict;
use warnings;
use XML::Simple;
use Digest::MD5 qw(md5_hex);
#use Digest::SHA qw(sha256_hex);
use HttpUtils;
use HTTP::Request;
use HTTP::Request::Common qw(POST);
@@ -212,6 +212,8 @@ sub FBTAM_storepassword {
sub FBTAM_readpassword {
my ($hash) = @_;
my $name = $hash->{NAME};
my $savedUser = AttrVal($name, "username", undef);
$hash->{USERNAME} = $savedUser if defined $savedUser;
my $keyname = 'FBTAM_' . $name . '_PASSWORD';
my $key = getUniqueId() . $keyname;
@@ -264,8 +266,8 @@ sub FBTAM_Update {
my $fbip = InternalVal($fbDev, 'HOST', undef);
readingsSingleUpdate($hash, 'fritzbox_ip', $fbip, 0) if $fbip;
my $username = $hash->{USERNAME} // '';
my $password = FBTAM_readpassword($hash);
my $username = $hash->{USERNAME};
my $tam = $hash->{TAM};
return unless $fbip && $username && $password;
@@ -415,8 +417,8 @@ sub FBTAM_getMsgListUrl {
my $fbip = InternalVal($fbDev, 'HOST', undef);
my $tamIndex = $hash->{TAM}-1;
my $username = $hash->{USERNAME} // '';
my $password = FBTAM_readpassword($hash);
my $username = $hash->{USERNAME};
my $ua = LWP::UserAgent->new(timeout => 10);
$ua->credentials("$fbip:49000", "HTTPS Access", $username, $password);
@@ -485,8 +487,8 @@ sub FBTAM_getMsgList {
return undef;
}
my $username = $hash->{USERNAME} // '';
my $password = FBTAM_readpassword($hash);
my $username = $hash->{USERNAME};
my $ua = LWP::UserAgent->new;
$ua->credentials($fbip . ':49000', 'HTTPS Access', $username, $password);
@@ -990,8 +992,8 @@ sub FBTAM_deleteMsg {
return
}
my $username = $hash->{USERNAME} // '';
my $password = FBTAM_readpassword($hash);
my $username = $hash->{USERNAME};
my $ua = LWP::UserAgent->new(timeout => 10);
$ua->credentials("$fbip:49000", "HTTPS Access", $username, $password);
@@ -1053,8 +1055,8 @@ sub FBTAM_markMsg {
my $tamIndex = $hash->{TAM}-1;
my $username = $hash->{USERNAME} // '';
my $password = FBTAM_readpassword($hash);
my $username = $hash->{USERNAME};
my $ua = LWP::UserAgent->new(timeout => 10);
$ua->credentials("$fbip:49000", "HTTPS Access", $username, $password);
@@ -1112,8 +1114,8 @@ sub FBTAM_enableTAM {
#-- careful: tamIndex = tamNr-1
my $tamIndex = $hash->{TAM}-1;
my $username = $hash->{USERNAME} // '';
my $password = FBTAM_readpassword($hash);
my $username = $hash->{USERNAME};
my $ua = LWP::UserAgent->new(timeout => 10);
$ua->credentials("$fbip:49000", "HTTPS Access", $username, $password);
@@ -1163,8 +1165,8 @@ sub FBTAM_getinfo {
#-- careful: tamIndex = tamNr-1
my $tamIndex = $hash->{TAM}-1;
my $username = $hash->{USERNAME} // '';
my $password = FBTAM_readpassword($hash);
my $username = $hash->{USERNAME};
my $ua = LWP::UserAgent->new(timeout => 10);
$ua->credentials("$fbip:49000", "HTTPS Access", $username, $password);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -162,7 +162,11 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
"1.60.5" => "14.11.2025 ___csmSpecificEpieces: implement EPIECMAXOPHRS , ___batAdjustPowerByMargin: adjust pow with otpMargin ",
"1.60.7" => "19.11.2025 new special Reading BatRatio ",
"1.60.6" => "18.11.2025 _createSummaries: fix tdConFcTillSunset, _batSocTarget: apply 75% of tomorrow consumption ",
"1.60.5" => "16.11.2025 ___csmSpecificEpieces: implement EPIECMAXOPHRS , ___batAdjustPowerByMargin: adjust pow with otpMargin ".
"__solCast_ApiResponse: evaluation of httpheader ".
"___csmSpecificEpieces: fix {epiecAVG}{hour} calculation, edit comref, isConsumerLogOn: small fix ",
"1.60.4" => "13.11.2025 smoothValue as OOP implemantation, battery efficiency rework, edit comref, expand loadTarget by time target ".
"_batSocTarget: surplus for next day adjusted, some code changes ",
"1.60.3" => "06.11.2025 more preparation for barrierSoC, ___batFindMinPhWh: code change, new parameter ctrlBatSocManagementXX->barrierSoC ",
@@ -178,7 +182,7 @@ my %vNotesIntern = (
"_setreset: set reset is reworked with widgetList, aiData can be deleted by index ".
"_flowGraphic: new variable node2home_direction ".
"new sub askLogtime to avoid error logs too often, Forum: https://forum.fhem.de/index.php?msg=1350716 ",
"1.59.5" => "15.10.2025 new sub ___batAdjustPowerByMargin: implement optPower Safety margin decreasing proportionally to the linear surplus ".
"1.59.5" => "15.10.2025 new ___batAdjustPowerByMargin: implement optPower Safety margin decreasing proportionally to the linear surplus ".
"new Reading Battery_TargetAchievable_XX, _batSocTarget: minor code change ",
"1.59.4" => "14.10.2025 new subs, ctrlBatSocManagementXX: new key loadTarget, replace __batCapShareFactor by __batDeficitShareFactor ".
"__batChargeOptTargetPower: use pinmax if achievable==0, new ctrlBatSocManagementXX->stepSoC key ".
@@ -457,7 +461,7 @@ use constant {
CONDAYSLIDEMAX => 30, # max. Anzahl der Arrayelemente im Register pvCircular -> con_all / gcons_a -> <Tag>
WHISTREPEAT => 851, # Wiederholungsintervall Cache File Daten schreiben
EPIECMAXCYCLES => 10, # Anzahl Einschaltzyklen für verbraucherspezifische Energiestück Ermittlung (EnergyPieces)
EPIECMAXOPHRS => 5, # max. Anzahl ununterbrochene Betriebsstunden für Verbraucher ohne Cycle Switch (EnergyPieces)
EPIECMAXOPHRS => 10, # max. Anzahl ununterbrochene Betriebsstunden für Verbraucher ohne Cycle Switch (EnergyPieces)
MAXWEATHERDEV => 3, # max. Anzahl Wetter Devices (Attr setupWeatherDevX)
MAXBATTERIES => 3, # maximale Anzahl der möglichen Batterien
@@ -469,7 +473,9 @@ use constant {
MAXSOCDEF => 95, # default Wert (%) auf den die Batterie maximal aufgeladen werden soll bzw. als aufgeladen gilt
CARECYCLEDEF => 20, # default max. Anzahl Tage die zwischen der Batterieladung auf maxSoC liegen dürfen
BATSOCCHGDAY => 5, # Batterie: prozentuale SoC Anpassung pro Tag
PERCCONINSOC => 0.75, # Batterie SoC-Management: Anteilsfaktor für Verbrauch
STOREFFDEF => 87, # default Batterie Effizienz (https://www.energie-experten.org/erneuerbare-energien/photovoltaik/stromspeicher/wirkungsgrad)
GMFBLTO => 30, # Timeout Aholen Message File aus GIT
GMFILEREPEAT => 3600, # Base Wiederholungsuntervall Abholen Message File aus GIT
GMFILERANDOM => 10800, # Random AddOn zu GMFILEREPEAT
@@ -500,7 +506,6 @@ use constant {
PRDEF => 0.9, # default Performance Ratio (PR)
SFTYMARGIN_20 => 20, # Sicherheitszuschlag 20%
SFTYMARGIN_50 => 50, # Sicherheitszuschlag 50%
STOREFFDEF => 87, # default Batterie Effizienz (https://www.energie-experten.org/erneuerbare-energien/photovoltaik/stromspeicher/wirkungsgrad)
OTPDEADBAND => 10.0, # Smoother Standard OTP Power Schwellenwert für Änderungen
OTPALPHA => 1.0, # Smoother Standard OTP Power Alpha default
TEMPCOEFFDEF => -0.45, # default Temperaturkoeffizient Pmpp (%/°C) lt. Datenblatt Solarzelle
@@ -1442,7 +1447,7 @@ my %hef = (
"noSchedule" => { f => 1.00, m => 1.00, l => 1.00, mt => DEFMINTIME },
);
my %hcsr = ( # Funktiontemplate zur Erstellung optionaler Statistikreadings
my %hcsr = ( # Funktiontemplate zur Erstellung optionaler Statistikreadings
currentAPIinterval => { fnr => 1, fn => \&StatusAPIVal, par => '', par1 => '', unit => '', def => 0 }, # par = Parameter zur spezifischen Verwendung
lastretrieval_time => { fnr => 1, fn => \&StatusAPIVal, par => '', par1 => '', unit => '', def => '-' },
lastretrieval_timestamp => { fnr => 1, fn => \&StatusAPIVal, par => '', par1 => '', unit => '', def => '-' },
@@ -1464,6 +1469,7 @@ my %hcsr = (
BatPowerIn_Sum => { fnr => 5, fn => \&CurrentVal, par => 'batpowerinsum', par1 => '', unit => ' W', def => '-' },
BatPowerOut_Sum => { fnr => 5, fn => \&CurrentVal, par => 'batpoweroutsum', par1 => '', unit => ' W', def => '-' },
BatWeightedTotalSOC => { fnr => 2, fn => \&CurrentVal, par => 'batsoctotal', par1 => '', unit => ' %', def => 0 },
BatRatio => { fnr => 5, fn => \&CurrentVal, par => 'batRatio', par1 => '', unit => '', def => '-' },
SunHours_Remain => { fnr => 5, fn => \&CurrentVal, par => '', par1 => '', unit => '', def => 0 }, # fnr => 3 -> Custom Calc
SunMinutes_Remain => { fnr => 5, fn => \&CurrentVal, par => '', par1 => '', unit => '', def => 0 },
dayAfterTomorrowPVforecast => { fnr => 5, fn => \&CurrentVal, par => 'dayAfterTomorrowPVfc', par1 => '', unit => ' Wh', def => 0 },
@@ -3202,7 +3208,7 @@ sub __solCast_ApiResponse {
my $caller = $paref->{caller};
my $string = $paref->{string};
my $allstrings = $paref->{allstrings};
my $stc = $paref->{stc}; # Startzeit API Abruf
my $stc = $paref->{stc}; # Startzeit API Abruf
my $lang = $paref->{lang};
my $debug = $paref->{debug};
my $type = $paref->{type};
@@ -3211,8 +3217,33 @@ sub __solCast_ApiResponse {
my $msg;
my $hash = $defs{$name};
my $sta = [gettimeofday]; # Start Response Verarbeitung
my $sta = [gettimeofday]; # Start Response Verarbeitung
my $head = $paref->{httpheader} // 'empty header';
if ($head !~ /200.OK/ixs) { # Auswertung Header
___setSolCastAPIcallKeyData ($paref);
$data{$name}{statusapi}{SolCast}{'?All'}{response_message} = $head;
if ($head =~ /429.Too.Many.Requests/xs) {
$data{$name}{statusapi}{SolCast}{'?All'}{todayRemainingAPIrequests} = 0;
}
singleUpdateState ( {hash => $hash, state => $msg, evt => 1} );
$data{$name}{current}{runTimeLastAPIProc} = sprintf "%.4f", tv_interval($sta); # Verarbeitungszeit ermitteln
$data{$name}{current}{runTimeLastAPIAnswer} = sprintf "%.4f", (tv_interval($stc) - tv_interval($sta)); # API Laufzeit ermitteln
if ($debug =~ /apiProcess|apiCall/x) {
my $apimaxreq = AttrVal ($name, 'ctrlSolCastAPImaxReq', SOLCMAXREQDEF);
Log3 ($name, 1, "$name DEBUG> SolCast API Call - Header response content: ".$head);
Log3 ($name, 1, "$name DEBUG> SolCast API Call - todayRemainingAPIrequests: ".StatusAPIVal ($hash, 'SolCast', '?All', 'todayRemainingAPIrequests', $apimaxreq));
}
return;
}
if ($err ne "") {
$msg = 'SolCast API server response: '.$err;
@@ -3221,12 +3252,12 @@ sub __solCast_ApiResponse {
$data{$name}{statusapi}{SolCast}{'?All'}{response_message} = $err;
singleUpdateState ( {hash => $hash, state => $msg, evt => 1} );
$data{$name}{current}{runTimeLastAPIProc} = sprintf "%.4f", tv_interval($sta); # Verarbeitungszeit ermitteln
$data{$name}{current}{runTimeLastAPIAnswer} = sprintf "%.4f", (tv_interval($stc) - tv_interval($sta)); # API Laufzeit ermitteln
$data{$name}{current}{runTimeLastAPIProc} = sprintf "%.4f", tv_interval($sta); # Verarbeitungszeit ermitteln
$data{$name}{current}{runTimeLastAPIAnswer} = sprintf "%.4f", (tv_interval($stc) - tv_interval($sta)); # API Laufzeit ermitteln
return;
}
elsif ($myjson ne "") { # Evaluiere ob Daten im JSON-Format empfangen wurden
elsif ($myjson ne "") { # Evaluiere ob Daten im JSON-Format empfangen wurden
my ($success) = evaljson ($hash, $myjson);
if (!$success) {
@@ -3341,7 +3372,7 @@ sub __solCast_ApiResponse {
$k++;
}
}
}
Log3 ($name, 4, qq{$name - SolCast API answer received for string "$string"});
@@ -3425,7 +3456,7 @@ sub ___setSolCastAPIcallKeyData {
$data{$name}{statusapi}{SolCast}{'?All'}{lastretrieval_time} = (timestampToTimestring ($t, $lang))[3]; # letzte Abrufzeit
$data{$name}{statusapi}{SolCast}{'?All'}{lastretrieval_timestamp} = $t; # letzter Abrufzeitstempel
my $apimaxreq = AttrVal ($name, 'ctrlSolCastAPImaxReq', SOLCMAXREQDEF);
my $apimaxreq = AttrVal ($name, 'ctrlSolCastAPImaxReq', SOLCMAXREQDEF);
my $mpl = StatusAPIVal ($hash, 'SolCast', '?All', 'solCastAPIcallMultiplier', 1);
my $ddc = StatusAPIVal ($hash, 'SolCast', '?All', 'todayDoneAPIcalls', 0);
@@ -7736,6 +7767,7 @@ sub _attrBatSocManagement { ## no critic "not used"
}
else {
deleteReadingspec ($hash, 'Battery_.*');
$data{$name}{current}{'batRatio'.$bn};
}
delete $data{$name}{circular}{99}{'lastTsMaxSocRchd'.$bn};
@@ -8386,7 +8418,7 @@ sub delConsumerFromMem {
my $hash = $defs{$name};
my $calias = ConsumerVal ($hash, $c, 'alias', '');
for my $d (1..31) {
for my $d (1..31) { # Consumer aus phHistory entfernen
$d = sprintf("%02d", $d);
delete $data{$name}{pvhist}{$d}{99}{"csme${c}"};
delete $data{$name}{pvhist}{$d}{99}{"cyclescsm${c}"};
@@ -8400,8 +8432,14 @@ sub delConsumerFromMem {
delete $data{$name}{pvhist}{$d}{$i}{"minutescsm${c}"};
}
}
for my $ridx (sort keys %{ $data{$name}{aidectree}{airaw} // {} }) { # Consumer aus AI Raw Data löschen
next unless defined $ridx && length $ridx;
delete $data{$name}{consumers}{$c};
delete $data{$name}{aidectree}{airaw}{$ridx}{'csme'.$c};
}
delete $data{$name}{consumers}{$c}; # Consumerhash löschen
Log3 ($name, 2, qq{$name - Consumer "$c - $calias" deleted from memory});
@@ -11571,11 +11609,11 @@ sub _batSocTarget {
## erwartete PV ermitteln & Anteilsfaktor Bat anwenden
########################################################
my $pvfctm = ReadingsNum ($name, 'Tomorrow_PVforecast', 0); # PV Prognose morgen
my $constm = CurrentVal ($name, 'tomorrowConsHoursWithPVGen', 0); # Verbrauch während PV-Erzeugung
my $pvfctd = ReadingsNum ($name, 'RestOfDayPVforecast', 0); # PV Prognose Rest heute
my $pvfctm = ReadingsNum ($name, 'Tomorrow_PVforecast', 0); # PV Prognose morgen
my $constm = CurrentVal ($name, 'tmConFcTillSunset', 0); # Verbrauch nächster Tag bis Sonnenuntergang Wh
my $pvfctd = ReadingsNum ($name, 'RestOfDayPVforecast', 0); # PV Prognose Rest heute
my $surptd = $pvfctd - $tdconsset; # erwarteter (Rest)Überschuß des aktuellen Tages
my $surptm = sprintf "%.0f", ($pvfctm - $constm * 0.5); # anteilig Überschuß am kommenden Tages während PV-Erzeugung -> Platz lassen!
my $surptm = sprintf "%.0f", ($pvfctm - $constm * PERCCONINSOC); # anteilig Verbrauch am kommenden Tages während PV-Erzeugung -> Platz lassen!
my $pvexpraw = $surptm > $surptd ? $surptm : $surptd; # V 1.60.4
$pvexpraw = max ($pvexpraw, 0); # erwartete PV-Leistung inkl. Verbrauchsprognose bis Sonnenuntergang
@@ -11584,8 +11622,10 @@ sub _batSocTarget {
if ($debug =~ /batteryManagement/xs) {
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> Battery share factor of total required load: $sf");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> Expected energy for charging with proportional consumption: $pvexpraw Wh");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> Expected energy for charging after application Share factor: $pvexpect Wh");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> today -> PV fc: $pvfctd Wh, con till sunset: $tdconsset Wh, Surp: $surptd Wh");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> tomorrow -> PV fc: $pvfctm Wh, con till sunset: $constm Wh, Surp: $surptm Wh (".(PERCCONINSOC * 100)."% con)");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> selected energy for charging (the higher positive Surp value from above): $pvexpraw Wh");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - basics -> expected energy for charging after application Share factor: $pvexpect Wh");
Log3 ($name, 1, "$name DEBUG> SoC Step1 Bat $bn - compare with SoC history -> preliminary new Target: $target %");
}
@@ -11623,7 +11663,7 @@ sub _batSocTarget {
$docare = 1; # Zwangsanwendung care SoC
}
$la = "calc care SoC -> docare: $docare, care SoC: $careSoc %, Remaining days until care SoC: $days2care, Target: $target %";
$la = "calc care SoC -> docare: $docare, care SoC: $careSoc %, remain days until care SoC: $days2care, Target: $target %";
}
else {
$la = "calc care SoC -> docare: $docare, care SoC: $careSoc %, use preliminary Target: $target % (new care SoC calc & act postponed to after $nt)";
@@ -11640,18 +11680,14 @@ sub _batSocTarget {
debugLog ($paref, 'batteryManagement', "SoC Step3 Bat $bn - basics -> max SOC so that predicted PV can be stored: $cantarget %, newtarget: $newtarget %");
if ($newtarget > $careSoc) {
$docare = 0; # keine Zwangsanwendung care SoC
}
else {
$newtarget = $careSoc;
}
if ($newtarget > $careSoc) { $docare = 0; } # keine Zwangsanwendung care SoC
else { $newtarget = $careSoc; }
my $logadd = '';
if ($newtarget > $csopt && $t > $delayts) { # Erhöhung des SoC (wird ab delayts angewendet)
$target = $newtarget;
$logadd = "(new target > $csopt % and Sunset has passed)";
$logadd = "(new target > $csopt % and time limit has passed)";
}
elsif ($newtarget > $csopt && $t <= $delayts && !$docare) { # bisheriges Optimum bleibt vorerst
$target = $csopt;
@@ -12364,7 +12400,14 @@ sub __batChargeOptTargetPower {
$achievable = 0;
}
storeReading ('Battery_TargetAchievable_'.$sbn, $achievable) if($nhr eq '00');
if ($nhr eq '00') {
storeReading ('Battery_TargetAchievable_'.$sbn, $achievable);
$ratio = sprintf "%.2f", ___batRatio ($runwhneed, $remainingSurp, $befficiency);
$data{$name}{current}{'batRatio'.$sbn} = $ratio;
$otp->{$sbn}{ratio} = $ratio;
$otp->{$sbn}{remainingSurp} = $remainingSurp;
}
$hsurp->{$hod}{$sbn}{loadrel} = $runwhneed > 0 ? 1 : 0; # Ladefreigabe abhängig von Ziel-SoC Erfüllung
$hsurp->{$hod}{$sbn}{achievelog} = "charging target: $goalwh Wh, E requirement incl. efficiency: ".
@@ -12411,6 +12454,7 @@ sub __batChargeOptTargetPower {
Ereq => $runwhneed,
replacement => $replacement,
achievable => $achievable,
befficiency => $befficiency,
minute => $minute
}
);
@@ -12431,13 +12475,13 @@ sub __batChargeOptTargetPower {
my $pneedmin = $limpower * (1 + $otpMargin / 100); # optPower: Sicherheitsaufschlag
if ($strategy eq 'smartPower') {
($pneedmin) = ___batAdjustPowerByMargin ($limpower, # smartPower: Sicherheitsaufschlag abfallend proportional zum linearen Überschuss
$bpinmax,
$runwhneed,
$otpMargin,
$remainingSurp,
$befficiency
);
$pneedmin = ___batAdjustPowerByMargin ($limpower, # smartPower: Sicherheitsaufschlag abfallend proportional zum linearen Überschuss
$bpinmax,
$runwhneed,
$otpMargin,
$remainingSurp,
$befficiency
);
}
$pneedmin = ___batApplySocAreas ( { name => $name,
@@ -12451,7 +12495,7 @@ sub __batChargeOptTargetPower {
}
);
$pneedmin = ___batAdjustEfficiencyAndLimits ($pneedmin, $befficiency, $bpinmax, 0); # Apply Bat Effizienz und Ladeleistungsbegrenzungen
$pneedmin = ___batAdjustLimits ($pneedmin, $bpinmax, 0); # Ladeleistungsbegrenzungen
$hsurp->{$hod}{$sbn}{pneedmin} = $pneedmin;
@@ -12468,16 +12512,13 @@ sub __batChargeOptTargetPower {
}
if ($strategy eq 'smartPower') { # smartPower: Sicherheitsaufschlag linear absenkend
($target, $ratio) = ___batAdjustPowerByMargin ($limpower, # smartPower: agressivere Ladeleistung, Sicherheitsaufschlag abfallend proportional zum linearen Überschuss
$bpinmax,
$runwhneed,
$otpMargin,
$remainingSurp,
$befficiency
);
$otp->{$sbn}{ratio} = sprintf ("%.2f", $ratio);
$otp->{$sbn}{remainingSurp} = $remainingSurp;
$target = ___batAdjustPowerByMargin ($limpower, # smartPower: agressivere Ladeleistung, Sicherheitsaufschlag abfallend proportional zum linearen Überschuss
$bpinmax,
$runwhneed,
$otpMargin,
$remainingSurp,
$befficiency
);
}
my $gfeedin = CurrentVal ($name, 'gridfeedin', 0); # aktuelle Netzeinspeisung
@@ -12499,7 +12540,7 @@ sub __batChargeOptTargetPower {
}
);
$target = ___batAdjustEfficiencyAndLimits ($target, $befficiency, $bpinmax, $bpinreduced); # Apply Bat Effizienz und Ladeleistungsbegrenzungen
$target = ___batAdjustLimits ($target, $bpinmax, $bpinreduced); # Ladeleistungsbegrenzungen
$otp->{$sbn}{target} = $target;
}
@@ -12525,6 +12566,20 @@ sub __batChargeOptTargetPower {
return ($hsurp, $otp);
}
################################################################
# Ratio zwischen PV-Überschuß und benötigter Ladeenergie
# berechnen
################################################################
sub ___batRatio {
my ($rwh, $surp, $beff) = @_;
return 0 if($surp <= 0.0 || !defined $rwh || $rwh <= 0.0);
my $ratio = $surp * 100.0 * $beff / $rwh; # beff -> Batterie Effizienz als Anteil 0.1 .. 1
return $ratio;
}
################################################################
# Verbleibende Aktivstunden und deren Überschußsumme liefern
################################################################
@@ -12556,12 +12611,10 @@ return ($remainingSurp, \@remaining_hods);
sub ___batAdjustPowerByMargin {
my ($limpower, $pinmax, $runwhneed, $otpMargin, $remainingSurp, $befficiency) = @_;
return $limpower if(!defined $runwhneed || $runwhneed <= 0);
my $pow;
my $ratio = 0;
return ($limpower, $ratio) if(!defined $runwhneed || $runwhneed <= 0);
$ratio = $remainingSurp * 100.0 * $befficiency / $runwhneed ; # befficiency als Anteil 0.1 .. 1
my $ratio = ___batRatio ($runwhneed, $remainingSurp, $befficiency);
my $limWithMargin = $limpower * (1.0 + $otpMargin / 100.0); # Hinweis: das ist bewusst ein permanenter Sicherheitsaufschlag
$limpower = min ($limpower, $pinmax); # limpower !> pinmax um invertierte Interpolation zu vermeiden
$limWithMargin = min ($limWithMargin, $pinmax);
@@ -12571,7 +12624,7 @@ sub ___batAdjustPowerByMargin {
elsif ($ratio >= 100 + $otpMargin) { $pow = $limWithMargin }
else { $pow = $pinmax - ($pinmax - $limWithMargin) * ($ratio - 100.0) / $otpMargin }
return ($pow, $ratio);
return $pow;
}
################################################################
@@ -12637,15 +12690,14 @@ return $ph;
################################################################
# Endbehandlung einer Leistungsvorgabe für Batterieladung
################################################################
sub ___batAdjustEfficiencyAndLimits {
my ($ph, $eff, $max, $min) = @_;
$ph /= $eff;
################################################################
sub ___batAdjustLimits {
my ($ph, $max, $min) = @_;
$ph = min ($ph, $max); # Begrenzung auf max. mögliche Batterieladeleistung
$ph = max ($ph, $min); # Begrenzung auf min. gewünschte Batterieladeleistung
$ph = sprintf "%.0f", $ph;
return $ph;
}
@@ -12696,6 +12748,7 @@ sub ___batFindMinPhWh {
my $Ereq = $paref->{Ereq};
my $replacement = $paref->{replacement};
my $achievable = $paref->{achievable};
my $befficiency = $paref->{befficiency};
my $minute = $paref->{minute};
my @hods = @$hodsref;
@@ -12704,6 +12757,7 @@ sub ___batFindMinPhWh {
my $eps = 0.5; # minimale Genauigkeit in Wh (1e-3)
my $max_iter = 100; # Zwangsabbruch nach X Durchläufen
my $loop = 0;
$Ereq /= $befficiency;
my $cap;
if (!$achievable) {
@@ -12713,6 +12767,7 @@ sub ___batFindMinPhWh {
} @hods;
$max_cap //= 0;
$max_cap /= $befficiency;
return { ph => (sprintf "%.0f", $max_cap), iterations => $loop, blur => (sprintf "%.4f", 0) };
}
@@ -12729,7 +12784,7 @@ sub ___batFindMinPhWh {
if ($nhr eq '00') { $cap = min ($mid, $hsurp->{$hod}{surplswh}) / 60 * (60 - int $minute) } # Zeitgewichtung aktuelle Stunde
else { $cap = min ($mid, $hsurp->{$hod}{surplswh}) }
$charged += $cap // 0;
}
@@ -12838,12 +12893,6 @@ sub _createSummaries {
$minute = int ($minute) + 1; # Minute Range umsetzen auf 1 bis 60
my $dt = timestringsFromOffset ($t, 86400);
my $tmoday = $dt->{day}; # Tomorrow Day (01..31)
$dt = timestringsFromOffset ($t, 172800);
my $datmoday = $dt->{day}; # Übermorgen Day (01..31)
## Initialisierung
####################
my $next1HoursSum = { "PV" => 0, "Consumption" => 0 };
@@ -12856,11 +12905,15 @@ sub _createSummaries {
my $todaySumFc = { "PV" => 0, "Consumption" => 0 };
my $todaySumRe = { "PV" => 0, "Consumption" => 0 };
my $tdaysset = CurrentVal ($name, 'sunsetTodayTs', 0); # Timestamp Sonneuntergang am aktuellen Tag
my $dtsset = timestringsFromOffset ($tdaysset, 0);
my $tmorsset = CurrentVal ($name, 'sunsetTomorrowTs', 0); # Timestamp Sonneuntergang kommenden Tag
my $htmsset = timestringsFromOffset ($tmorsset, 0);
my $tdaysset = CurrentVal ($name, 'sunsetTodayTs', 0); # Timestamp Sonneuntergang am aktuellen Tag
my $dtsset = timestringsFromOffset ($tdaysset, 0);
my $tdConFcTillSunset = 0;
my $remainminutes = 60 - $minute; # verbleibende Minuten der aktuellen Stunde
my $tdConFcTillSunset = 0;
my $tmConFcTillSunset = 0;
my $tmConInHrWithPVGen = 0;
my $remainminutes = 60 - $minute; # verbleibende Minuten der aktuellen Stunde
my $hour00pvfc = NexthoursVal ($name, "NextHour00", 'pvfc', 0) / 60 * $remainminutes;
my $hour00confc = NexthoursVal ($name, "NextHour00", 'confc', 0);
@@ -12933,36 +12986,28 @@ sub _createSummaries {
$next4HoursSum->{Consumption} += $confc / 60 * $minute if($h == 4);
}
if ($istdy) {
if ($fd == 0) {
$restOfDaySum->{PV} += $pvfc;
$restOfDaySum->{Consumption} += $confc;
$tdConFcTillSunset += $confc if($don);
$tdConFcTillSunset += $confc if(int ($hod) < int ($dtsset->{hour}) + 1);
if (int ($hod) == int ($dtsset->{hour}) + 1) { # wenn die berücksichtigte Stunde die Stunde des Sonnenuntergangs ist
my $diflasth = 60 - int ($dtsset->{minute}) + 1; # fehlende Minuten zur vollen Stunde in der Stunde des Sunset
if (int ($hod) == int ($dtsset->{hour}) + 1) { # wenn die berücksichtigte Stunde die Stunde des Sonnenuntergangs ist
my $diflasth = 60 - int ($dtsset->{minute}) + 1; # fehlende Minuten zur vollen Stunde in der Stunde des Sunset
$tdConFcTillSunset -= ($confc / 60) * $diflasth;
}
}
elsif ($nhday eq $tmoday) {
elsif ($fd == 1) {
$tomorrowSum->{PV} += $pvfc;
$tmConFcTillSunset += $confc if(int ($hod) <= int ($htmsset->{hour}) + 1); # Verbrauch kommender Tag bis inkl. Stunde des Sonnenuntergangs
if ($pvfc) { # Summe Verbrauch der Stunden mit PV-Erzeugung am kommenden Tag
$tmConInHrWithPVGen += $confc;
}
}
elsif ($nhday eq $datmoday) {
elsif ($fd == 2) {
$daftertomSum->{PV} += $pvfc;
$daftertomSum->{Consumption} += $confc;
}
## Summe Verbrauch der Stunden mit PV-Erzeugung am kommenden Tag
################################################################## # V 1.60.4
if ($fd == 1) { # für den nächsten Tag
if ($fh == 0) {
delete $data{$name}{current}{tomorrowConsHoursWithPVGen}; # alte Summe bereinigen
}
else {
if ($pvfc) {
$data{$name}{current}{tomorrowConsHoursWithPVGen} += $confc;
}
}
}
}
for my $th (1..24) {
@@ -13056,6 +13101,8 @@ sub _createSummaries {
$data{$name}{current}{selfconsumptionrate} = $selfconsumptionrate;
$data{$name}{current}{autarkyrate} = $autarkyrate;
$data{$name}{current}{tdConFcTillSunset} = sprintf "%.0f", $tdConFcTillSunset;
$data{$name}{current}{tmConFcTillSunset} = $tmConFcTillSunset;
$data{$name}{current}{tmConInHrWithPVGen} = $tmConInHrWithPVGen;
$data{$name}{current}{surplus} = $surplus;
$data{$name}{current}{dayAfterTomorrowPVfc} = $daftertomSum->{PV};
$data{$name}{current}{dayAfterTomorrowConfc} = $daftertomSum->{Consumption};
@@ -13199,7 +13246,7 @@ sub _manageConsumerData {
if (!$paread){
my $timespan = $t - ConsumerVal ($hash, $c, "old_etottime", $t);
my $delta = $etot - ConsumerVal ($hash, $c, "old_etotal", $etot);
$pcurr = sprintf "%.6f", $delta / (3600 * $timespan) if($delta); # Einheitenformel beachten !!: W = Wh / (3600 * s)
$pcurr = sprintf "%.6f", ($delta / 3600 * $timespan) if($delta); # Einheitenformel beachten !!: W = Wh / (3600 * s)
$data{$name}{consumers}{$c}{old_etotal} = $etot;
$data{$name}{consumers}{$c}{old_etottime} = $t;
@@ -13222,7 +13269,7 @@ sub _manageConsumerData {
Log3 ($name, $vl, "$name $pre The calculated Energy consumption of >$consumer< is negative. This appears to be an error and the energy consumption of the consumer for the current hour is set to '0'.");
}
$paref->{val} = $consumerco; # Verbrauch des Consumers aktuelle Stunde
$paref->{val} = sprintf "%.2f", $consumerco; # Verbrauch des Consumers aktuelle Stunde
$paref->{histname} = "csme${c}";
setPVhistory ($paref);
@@ -13368,8 +13415,7 @@ sub __calcEnergyPieces {
my $name = $paref->{name};
my $c = $paref->{consumer};
my $hash = $defs{$name};
my $etot = HistoryVal ($hash, $paref->{day}, sprintf("%02d",$paref->{nhour}), "csmt${c}", 0);
my $etot = HistoryVal ($name, $paref->{day}, sprintf("%02d",$paref->{nhour}), "csmt${c}", 0);
if ($etot) {
$paref->{etot} = $etot;
@@ -13380,7 +13426,7 @@ sub __calcEnergyPieces {
delete $data{$name}{consumers}{$c}{epiecAVG};
delete $data{$name}{consumers}{$c}{epiecAVG_hours};
delete $data{$name}{consumers}{$c}{epiecStartEtotal};
delete $data{$name}{consumers}{$c}{epiecHist};
delete $data{$name}{consumers}{$c}{epiecActive};
delete $data{$name}{consumers}{$c}{epiecHour};
for my $h (1..EPIECMAXCYCLES) {
@@ -13391,7 +13437,7 @@ sub __calcEnergyPieces {
delete $data{$name}{consumers}{$c}{epieces};
my $cotype = ConsumerVal ($hash, $c, 'type', DEFCTYPE);
my $cotype = ConsumerVal ($name, $c, 'type', DEFCTYPE);
my ($err, $mintime) = getConsumerMintime ( { name => $name,
c => $c,
nolog => 1,
@@ -13405,13 +13451,14 @@ sub __calcEnergyPieces {
return;
}
my $hours = ceil ($mintime / 60); # Einplanungsdauer in h
my $ctote = ConsumerVal ($hash, $c, "avgenergy", undef); # gemessener durchschnittlicher Energieverbrauch pro Stunde (Wh)
$ctote = $ctote ? $ctote :
ConsumerVal ($hash, $c, "power", 0); # alternativer nominaler Energieverbrauch in W (bzw. Wh bezogen auf 1 h)
my $hours = ceil ($mintime / 60); # Einplanungsdauer in h
my $ctote = ConsumerVal ($name, $c, "avgenergy", undef); # gemessener durchschnittlicher Energieverbrauch pro Stunde (Wh)
$ctote = $ctote
? $ctote
: ConsumerVal ($name, $c, "power", 0); # alternativer nominaler Energieverbrauch in W (bzw. Wh bezogen auf 1 h)
if (int($hef{$cotype}{f}) == 1) { # bei linearen Verbrauchertypen die nominale Leistungsangabe verwenden statt Durchschnitt
$ctote = ConsumerVal ($hash, $c, "power", 0);
$ctote = ConsumerVal ($name, $c, "power", 0);
}
my $epiecef = $ctote * $hef{$cotype}{f}; # Gewichtung erste Laufstunde
@@ -13425,7 +13472,7 @@ sub __calcEnergyPieces {
$he = $epiecem if($h > 1 && $h < $hours); # kalk. Energieverbrauch Folgestunde(n)
$he = $epiecel if($h == $hours ); # kalk. Energieverbrauch letzte Stunde
$data{$name}{consumers}{$c}{epieces}{${h}} = sprintf('%.2f', $he);
$data{$name}{consumers}{$c}{epieces}{${h}} = sprintf ('%.2f', $he);
}
return;
@@ -13436,10 +13483,10 @@ return;
#
# EPIECMAXCYCLES => gibt an wie viele Zyklen betrachtet werden
# sollen
# epiecHist => ist die Nummer x des Zyklus der aktuell
# epiecActive => ist die Nummer x des Zyklus der aktuell
# beschrieben wird (epiecHist_x).
# epiecStartTime => Start der letzten neuen Aufzeichnung
# epiecHour => aktuelle Anzahl der Betriebsstunden nach 'epiecStartTime'
# epiecSwitchTime => Start der letzten neuen Aufzeichnung
# epiecHour => aktuelle Anzahl der Betriebsstunden nach 'epiecSwitchTime'
# oder Cycle Switch
# epiecHist_x => 1=.. 2=.. 3=.. 4=.. epieces eines Zyklus
# epiecHist_x_hours => Stunden des Durchlauf bzw. wie viele
@@ -13458,7 +13505,17 @@ sub ___csmSpecificEpieces {
my $etot = $paref->{etot};
my $t = $paref->{t};
if (ConsumerVal ($name, $c, 'onoff', 'off') eq 'on') { # Status "Aus" verzögern um Pausen im Waschprogramm zu überbrücken
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !!
########################################################################################################################
if (defined $data{$name}{consumers}{$c}{epiecHist}) { # 15.11.2025
$data{$name}{consumers}{$c}{epiecActive} = delete $data{$name}{consumers}{$c}{epiecHist};
}
if (defined $data{$name}{consumers}{$c}{epiecStartTime}) { # 15.11.2025
$data{$name}{consumers}{$c}{epiecSwitchTime} = delete $data{$name}{consumers}{$c}{epiecStartTime};
}
########################################################################################################################
if (ConsumerVal ($name, $c, 'onoff', 'off') eq 'on') { # Status "Aus" verzögern um Pausen im Waschprogramm zu überbrücken
$data{$name}{consumers}{$c}{lastOnTime} = $t;
}
@@ -13466,91 +13523,94 @@ sub ___csmSpecificEpieces {
$t - $data{$name}{consumers}{$c}{lastOnTime} :
0;
my $curr_epiecHour = ConsumerVal ($name, $c, 'epiecHour', 0);
my $curr_epiecHour = ConsumerVal ($name, $c, 'epiecHour', 0);
my $hourSinceSwitch = int (($t - ConsumerVal ($name, $c, 'epiecSwitchTime', $t)) / 3600) + 1; # aktuelle Betriebsstunde ermitteln
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - time since last Switch Off (tsloff): $tsloff seconds});
if ($tsloff < 300 && $curr_epiecHour <= EPIECMAXOPHRS) { # neuen epiec-Zyklus starten: nach OFF >= X Sekunden oder mehr als EPIECMAXOPHRS ununterbrochenen Betriebsstunden
if (($tsloff < 300.0 && $hourSinceSwitch < EPIECMAXOPHRS + 1)) { # aktuellen Zyklus beschreiben
my $ecycle = q{};
my $epiecHist_hours = q{};
my $epiecActive = ConsumerVal ($name, $c, 'epiecActive', 0);
if ($curr_epiecHour < 0) { # neue Aufzeichnung
my $histActiveNew = $epiecActive + 1;
$data{$name}{consumers}{$c}{epiecSwitchTime} = $t;
if ($histActiveNew > EPIECMAXCYCLES) { $data{$name}{consumers}{$c}{epiecActive} = 1 }
else { $data{$name}{consumers}{$c}{epiecActive} = $histActiveNew }
if ($curr_epiecHour < 0) { # neue Aufzeichnung
$data{$name}{consumers}{$c}{epiecStartTime} = $t;
$data{$name}{consumers}{$c}{epiecHist} += 1;
$data{$name}{consumers}{$c}{epiecHist} = 1 if(ConsumerVal ($name, $c, 'epiecHist', 0) > EPIECMAXCYCLES);
$ecycle = 'epiecHist_'.ConsumerVal ($name, $c, 'epiecHist', 0);
delete $data{$name}{consumers}{$c}{$ecycle}; # Löschen, wird neu erfasst
$ecycle = 'epiecHist_'.$data{$name}{consumers}{$c}{epiecActive};
delete $data{$name}{consumers}{$c}{$ecycle}; # Löschen, wird neu erfasst
}
$ecycle = 'epiecHist_'.ConsumerVal ($name, $c, 'epiecHist', 0); # Zyklusnummer für Namen
$epiecHist_hours = 'epiecHist_'.ConsumerVal ($name, $c, 'epiecHist', 0).'_hours';
my $epiecHour = floor (($t - ConsumerVal ($name, $c, 'epiecStartTime', $t)) / 60 / 60) + 1; # aktuelle Betriebsstunde ermitteln, ( / 60min) mögliche wäre auch durch 15min /Minute /Stunde
$epiecActive = ConsumerVal ($name, $c, 'epiecActive', 0);
$ecycle = 'epiecHist_'.$epiecActive; # Zyklusnummer für Namen
$epiecHist_hours = 'epiecHist_'.$epiecActive.'_hours';
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - current cycle number (ecycle): $ecycle});
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - Operating hours after switch on or cycle switch: $epiecHour});
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - current operating hour after switch on or cycle switch: $hourSinceSwitch});
if ($curr_epiecHour != $epiecHour) { # Betriebsstundenwechsel ? Differenz von etot noch auf die vorherige Betriebsstunde anrechnen
my $epiecHour_last = $epiecHour - 1;
if ($curr_epiecHour != $hourSinceSwitch) { # Betriebsstundenwechsel ? Differenz von etot noch auf die vorherige Betriebsstunde anrechnen
my $epiecHour_last = $hourSinceSwitch - 1;
$data{$name}{consumers}{$c}{$ecycle}{$epiecHour_last} = sprintf '%.2f', ($etot - ConsumerVal ($name, $c, "epiecStartEtotal", 0)) if($epiecHour > 1);
$data{$name}{consumers}{$c}{$ecycle}{$epiecHour_last} = sprintf '%.2f', ($etot - ConsumerVal ($name, $c, 'epiecStartEtotal', 0)) if($hourSinceSwitch > 1);
$data{$name}{consumers}{$c}{epiecStartEtotal} = $etot;
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - Operating hours change - new etotal (epiecStartEtotal): $etot});
}
my $ediff = $etot - ConsumerVal ($name, $c, "epiecStartEtotal", 0);
$ediff = sprintf ('%.2f', $ediff);
$data{$name}{consumers}{$c}{$ecycle}{$epiecHour} = $ediff;
$data{$name}{consumers}{$c}{epiecHour} = $epiecHour;
$data{$name}{consumers}{$c}{$epiecHist_hours} = $ediff ? $epiecHour : $epiecHour - 1; # wenn mehr als 1 Wh verbraucht wird die Stunde gezählt
my $ediff = $etot - ConsumerVal ($name, $c, "epiecStartEtotal", 0);
$ediff = sprintf ('%.2f', $ediff);
$data{$name}{consumers}{$c}{$ecycle}{$hourSinceSwitch} = $ediff;
$data{$name}{consumers}{$c}{epiecHour} = $hourSinceSwitch;
$data{$name}{consumers}{$c}{$epiecHist_hours} = $ediff > 0.0 ? $hourSinceSwitch : $hourSinceSwitch - 1; # Stunde akzeptieren wenn mehr als 1 Wh verbraucht
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - energy consumption in operating hour $epiecHour (ediff): $ediff Wh});
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - energy consumption in operating hour $hourSinceSwitch (ediff): $ediff Wh});
}
else { # Off-Status länger als 300 Sek. her Durchschnitt ermitteln
else { # neuen epiec-Zyklus starten: nach OFF >= X Sekunden oder mehr als EPIECMAXOPHRS ununterbrochenen Betriebsstunden
if ($curr_epiecHour > 0) {
my $hours = 0;
my $operhours = 0;
for my $h (1..EPIECMAXCYCLES) { # durchschnittliche Betriebsstunden über alle epieces ermitteln und aufrunden
$hours += ConsumerVal ($name, $c, 'epiecHist_'.$h.'_hours', 0);
for my $h (1..EPIECMAXCYCLES) { # durchschnittliche Betriebsstunden über alle epieces ermitteln
$operhours += ConsumerVal ($name, $c, 'epiecHist_'.$h.'_hours', 0);
}
my $avghours = ceil ($hours / EPIECMAXCYCLES);
$data{$name}{consumers}{$c}{epiecAVG_hours} = $avghours; # durchschnittliche Betriebsstunden pro Zyklus
my $avghours = ceil ($operhours / EPIECMAXCYCLES);
$data{$name}{consumers}{$c}{epiecAVG_hours} = $avghours; # durchschnittliche Betriebsstunden pro Zyklus
delete $data{$name}{consumers}{$c}{epiecAVG}; # Durchschnitt für epics neu ermitteln
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - Average operating hours per cycle (epiecAVG_hours): $avghours});
for my $hour (1..$avghours) {
my $hoursE = 0;
my $hsum;
delete $data{$name}{consumers}{$c}{epiecAVG}; # Durchschnitt für epics ermitteln
for my $hour (1..$avghours) { # jede Stunde durchlaufen
my $hoursE = 1;
for my $h (1..EPIECMAXCYCLES) { # jedes epiec durchlaufen
for my $h (1..EPIECMAXCYCLES) {
my $ecycle = 'epiecHist_'.$h;
if (defined $data{$name}{consumers}{$c}{$ecycle}{$hour}) {
if ($data{$name}{consumers}{$c}{$ecycle}{$hour} > 5) {
$data{$name}{consumers}{$c}{epiecAVG}{$hour} += $data{$name}{consumers}{$c}{$ecycle}{$hour};
$hoursE += 1;
my $pth = ConsumerVal ($name, $c, 'powerthreshold', 0);
if ($data{$name}{consumers}{$c}{$ecycle}{$hour} > $pth) {
$hsum += $data{$name}{consumers}{$c}{$ecycle}{$hour};
$hoursE++;
}
}
}
my $eavg = defined $data{$name}{consumers}{$c}{epiecAVG}{$hour} ?
$data{$name}{consumers}{$c}{epiecAVG}{$hour} :
0;
my $ahval = sprintf '%.2f', $eavg / $hoursE; # Durchschnitt ermittelt und speichern
my $ahval;
$ahval = sprintf '%.2f', ($hsum / $hoursE) if($hoursE > 0); # Durchschnitt ermittelt und speichern
$data{$name}{consumers}{$c}{epiecAVG}{$hour} = $ahval;
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - Average epiece of operating hour $hour: $ahval});
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - Average epiece of operating hour $hour: }.(defined $ahval ? $ahval : 'undef'));
}
debugLog ($paref, 'epiecesCalc', qq{specificEpieces -> consumer "$c" - Average operating hours per cycle (epiecAVG_hours): $avghours});
}
$data{$name}{consumers}{$c}{epiecHour} = -1; # epiecHour bei nächsten Durchlauf erhöhen
delete $data{$name}{consumers}{$c}{epiecSwitchTime};
$data{$name}{consumers}{$c}{epiecHour} = -1; # epiecHour bei nächsten Durchlauf erhöhen
}
return;
@@ -14617,31 +14677,31 @@ sub __getCyclesAndRuntime {
my ($starthour, $startday);
if (isConsumerLogOn ($hash, $c, $pcurr)) { # Verbraucher ist logisch "an"
if (ConsumerVal ($hash, $c, 'onoff', 'off') eq 'off') { # Status im letzen Zyklus war "off"
if (ConsumerVal ($name, $c, 'onoff', 'off') eq 'off') { # Status im letzen Zyklus war "off"
$data{$name}{consumers}{$c}{onoff} = 'on';
$data{$name}{consumers}{$c}{startTime} = $t; # startTime ist nicht von "Automatic" abhängig -> nicht identisch mit planswitchon !!!
$data{$name}{consumers}{$c}{cycleStarttime} = $t;
$data{$name}{consumers}{$c}{cycleTime} = 0;
$data{$name}{consumers}{$c}{lastMinutesOn} = ConsumerVal ($hash, $c, 'minutesOn', 0);
$data{$name}{consumers}{$c}{lastMinutesOn} = ConsumerVal ($name, $c, 'minutesOn', 0);
$data{$name}{consumers}{$c}{cycleDayNum}++; # Anzahl der On-Schaltungen am Tag
}
else {
$data{$name}{consumers}{$c}{cycleTime} = (($t - ConsumerVal ($hash, $c, 'cycleStarttime', $t)) / 60); # Minuten
$data{$name}{consumers}{$c}{cycleTime} = sprintf "%.2f", ($t - ConsumerVal ($name, $c, 'cycleStarttime', $t)) / 60; # Minuten
}
$starthour = strftime "%H", localtime(ConsumerVal ($hash, $c, 'startTime', $t));
$startday = strftime "%d", localtime(ConsumerVal ($hash, $c, 'startTime', $t)); # aktueller Tag (range 01 to 31)
$starthour = strftime "%H", localtime(ConsumerVal ($name, $c, 'startTime', $t));
$startday = strftime "%d", localtime(ConsumerVal ($name, $c, 'startTime', $t)); # aktueller Tag (range 01 to 31)
if ($chour eq $starthour) {
my $runtime = (($t - ConsumerVal ($hash, $c, 'startTime', $t)) / 60); # in Minuten ! (gettimeofday sind ms !)
$data{$name}{consumers}{$c}{minutesOn} = ConsumerVal ($hash, $c, 'lastMinutesOn', 0) + $runtime;
my $runtime = sprintf "%.2f", ($t - ConsumerVal ($name, $c, 'startTime', $t)) / 60; # in Minuten ! (gettimeofday sind ms !)
$data{$name}{consumers}{$c}{minutesOn} = ConsumerVal ($name, $c, 'lastMinutesOn', 0) + $runtime;
}
else { # Stundenwechsel
if (ConsumerVal ($hash, $c, 'onoff', 'off') eq 'on') { # Status im letzen Zyklus war "on"
if (ConsumerVal ($name, $c, 'onoff', 'off') eq 'on') { # Status im letzen Zyklus war "on"
my $newst = timestringToTimestamp ($date.' '.sprintf("%02d", $chour).':00:00');
$data{$name}{consumers}{$c}{startTime} = $newst;
$data{$name}{consumers}{$c}{minutesOn} = ($t - ConsumerVal ($hash, $c, 'startTime', $newst)) / 60; # in Minuten ! (gettimeofday sind ms !)
$data{$name}{consumers}{$c}{minutesOn} = ($t - ConsumerVal ($name, $c, 'startTime', $newst)) / 60; # in Minuten ! (gettimeofday sind ms !)
$data{$name}{consumers}{$c}{lastMinutesOn} = 0;
if ($day ne $startday) { # Tageswechsel
@@ -14651,8 +14711,8 @@ sub __getCyclesAndRuntime {
}
}
else { # Verbraucher soll nicht aktiv sein
$starthour = strftime "%H", localtime(ConsumerVal ($hash, $c, 'startTime', 1));
$startday = strftime "%d", localtime(ConsumerVal ($hash, $c, 'startTime', 1)); # aktueller Tag (range 01 to 31)
$starthour = strftime "%H", localtime (ConsumerVal ($name, $c, 'startTime', 1));
$startday = strftime "%d", localtime (ConsumerVal ($name, $c, 'startTime', 1)); # aktueller Tag (range 01 to 31)
if ($chour ne $starthour) { # Stundenwechsel
$data{$name}{consumers}{$c}{minutesOn} = 0;
@@ -14667,25 +14727,25 @@ sub __getCyclesAndRuntime {
if ($debug =~ /consumerSwitching${c}/xs) {
my $sr = 'still running';
my $son = isConsumerLogOn ($hash, $c, $pcurr) ? $sr : ConsumerVal ($hash, $c, 'cycleTime', 0) * 60; # letzte Cycle-Zeitdauer in Sekunden
my $cst = ConsumerVal ($hash, $c, 'cycleStarttime', 0);
my $son = isConsumerLogOn ($hash, $c, $pcurr) ? $sr : ConsumerVal ($name, $c, 'cycleTime', 0) * 60; # letzte Cycle-Zeitdauer in Sekunden
my $cst = ConsumerVal ($name, $c, 'cycleStarttime', 0);
$son = $son && $son ne $sr ? timestampToTimestring ($cst + $son, $paref->{lang}) :
$son eq $sr ? $sr :
'-';
$cst = $cst ? timestampToTimestring ($cst, $paref->{lang}) : '-';
Log3 ($name, 1, qq{$name DEBUG> consumer "$c" - cycleDayNum: }.ConsumerVal ($hash, $c, 'cycleDayNum', 0));
Log3 ($name, 1, qq{$name DEBUG> consumer "$c" - cycleDayNum: }.ConsumerVal ($name, $c, 'cycleDayNum', 0));
Log3 ($name, 1, qq{$name DEBUG> consumer "$c" - last cycle start time: $cst});
Log3 ($name, 1, qq{$name DEBUG> consumer "$c" - last cycle end time: $son \n});
}
## History schreiben
######################
$paref->{val} = ConsumerVal ($hash, $c, "cycleDayNum", 0); # Anzahl Tageszyklen des Verbrauchers speichern
$paref->{val} = ConsumerVal ($name, $c, "cycleDayNum", 0); # Anzahl Tageszyklen des Verbrauchers speichern
$paref->{histname} = "cyclescsm${c}";
setPVhistory ($paref);
$paref->{val} = ceil ConsumerVal ($hash, $c, "minutesOn", 0); # Verbrauchsminuten akt. Stunde des Consumers speichern
$paref->{val} = ceil ConsumerVal ($name, $c, "minutesOn", 0); # Verbrauchsminuten akt. Stunde des Consumers speichern
$paref->{histname} = "minutescsm${c}";
setPVhistory ($paref);
@@ -15656,6 +15716,7 @@ sub _genSpecialReadings {
readingsDelete ($hash, $prpo.'_'.$item);
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'todayConsumptionForecast');
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'tomorrowConsumptionForecast');
deleteReadingspec ($hash, $prpo.'_'.$item.'_.*') if($item eq 'BatRatio');
}
return if(!@csr);
@@ -15711,6 +15772,14 @@ sub _genSpecialReadings {
storeReading ($prpo.'_'.$kpi, $bsum);
}
elsif ($kpi eq 'BatRatio') {
for my $bn (1..MAXBATTERIES) { # für jede Batterie
$bn = sprintf "%02d", $bn;
my $ratio = &{$hcsr{$kpi}{fn}} ($name, $hcsr{$kpi}{par}.$bn, $def);
storeReading ($prpo.'_'.$kpi.'_'.$bn, sprintf ("%.0f", $ratio)) if($ratio ne '-');
}
}
elsif ($kpi =~ /daysUntilBatteryCare_/xs) {
my $bn = (split "_", $kpi)[1]; # Batterienummer extrahieren
my $d2c = &{$hcsr{$kpi}{fn}} ($hash, $hcsr{$kpi}{par}, 'days2care'.$bn, $def);
@@ -16637,16 +16706,6 @@ sub _parseShowdiffModes {
my $mo = CurrentVal ($name, 'showDiff', '');
### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !! 03.07.
###########################################################################################
if ($mo) {
$mo = $mo eq 'no' ? qq{1:'',2:'',3:''} :
$mo eq 'top' ? qq{1:top,2:top,3:top} :
$mo eq 'bottom' ? qq{1:bottom,2:bottom,3:bottom} :
$mo;
}
##########################################################################################
if ($mo) {
my @moa = split ',', $mo;
@@ -21266,7 +21325,7 @@ sub aiAddRawData {
last if(int $pvd > int $day);
if (!$ood) { # V 1.47.2 -> für manuelles Auffüllen mit Setter
$dayname = HistoryVal ($hash, $pvd, 99, 'dayname', undef);
$dayname = HistoryVal ($name, $pvd, 99, 'dayname', undef);
}
for my $hod (sort keys %{$data{$name}{pvhist}{$pvd}}) {
@@ -21274,17 +21333,17 @@ sub aiAddRawData {
my $ridx = _aiMakeIdxRaw ($pvd, $hod, $paref->{yt});
my $temp = HistoryVal ($hash, $pvd, $hod, 'temp', undef);
my $sunalt = HistoryVal ($hash, $pvd, $hod, 'sunalt', 0);
my $sunaz = HistoryVal ($hash, $pvd, $hod, 'sunaz', 0);
my $con = HistoryVal ($hash, $pvd, $hod, 'con', undef);
my $temp = HistoryVal ($name, $pvd, $hod, 'temp', undef);
my $sunalt = HistoryVal ($name, $pvd, $hod, 'sunalt', 0);
my $sunaz = HistoryVal ($name, $pvd, $hod, 'sunaz', 0);
my $con = HistoryVal ($name, $pvd, $hod, 'con', undef);
my $gcons = HistoryVal ($name, $pvd, $hod, 'gcons', undef);
my $wcc = HistoryVal ($hash, $pvd, $hod, 'wcc', undef);
my $wid = HistoryVal ($hash, $pvd, $hod, 'weatherid', undef); # Wetter ID
my $rr1c = HistoryVal ($hash, $pvd, $hod, 'rr1c', undef);
my $rad1h = HistoryVal ($hash, $pvd, $hod, 'rad1h', undef);
my $pvrlvd = HistoryVal ($hash, $pvd, $hod, 'pvrlvd', 1); # PV Generation valide?
my $pvrl = HistoryVal ($hash, $pvd, $hod, 'pvrl', undef);
my $wcc = HistoryVal ($name, $pvd, $hod, 'wcc', undef);
my $wid = HistoryVal ($name, $pvd, $hod, 'weatherid', undef); # Wetter ID
my $rr1c = HistoryVal ($name, $pvd, $hod, 'rr1c', undef);
my $rad1h = HistoryVal ($name, $pvd, $hod, 'rad1h', undef);
my $pvrlvd = HistoryVal ($name, $pvd, $hod, 'pvrlvd', 1); # PV Generation valide?
my $pvrl = HistoryVal ($name, $pvd, $hod, 'pvrl', undef);
$data{$name}{aidectree}{airaw}{$ridx}{sunalt} = $sunalt;
$data{$name}{aidectree}{airaw}{$ridx}{sunaz} = $sunaz;
@@ -21300,6 +21359,13 @@ sub aiAddRawData {
$data{$name}{aidectree}{airaw}{$ridx}{pvrl} = $pvrl if(defined $pvrl && $pvrl > 0);
$data{$name}{aidectree}{airaw}{$ridx}{pvrlvd} = $pvrlvd;
for my $c (1..MAXCONSUMER) {
$c = sprintf "%02d", $c;
my $csme = HistoryVal ($name, $pvd, $hod, 'csme'.$c, undef);
if (defined $csme) { $data{$name}{aidectree}{airaw}{$ridx}{'csme'.$c} = sprintf ("%.0f", $csme) }
}
$dosave++;
debugLog ($paref, 'aiProcess', "AI raw add - idx: $ridx, day: $pvd, hod: $hod, sunalt: $sunalt, sunaz: $sunaz, rad1h: ".(defined $rad1h ? $rad1h : '-').", pvrl: ".(defined $pvrl ? $pvrl : '-').", con: ".(defined $con ? $con : '-').", wcc: ".(defined $wcc ? $wcc : '-').", rr1c: ".(defined $rr1c ? $rr1c : '-').", temp: ".(defined $temp ? $temp : '-'), 4);
@@ -22474,10 +22540,23 @@ sub _listDataPoolAiRawData {
my $nod = AiRawdataVal ($name, $idx, 'dayname', '-');
my $con = AiRawdataVal ($name, $idx, 'con', '-');
my $gcons = AiRawdataVal ($name, $idx, 'gcons', '-');
my $csm;
for my $c (1..MAXCONSUMER) { # + alle Consumer
$c = sprintf "%02d", $c;
my $csme = AiRawdataVal ($name, $idx, 'csme'.$c, undef);
if (defined $csme) {
$csm .= ", " if($csm);
$csm .= "csme${c}: $csme";
}
}
$sq .= "\n";
$sq .= "$idx => hod: $hod, nod: $nod, sunaz: $sunaz, sunalt: $sunalt, rad1h: $rad1h, ";
$sq .= "wcc: $wcc, wid: $wid, rr1c: $rr1c, pvrl: $pvrl, pvrlvd: $pvrlvd, con: $con, gcons: $gcons, temp: $temp";
if (defined $csm) { $sq .= "\n "; $sq .= $csm; }
}
return $sq;
@@ -24291,23 +24370,24 @@ sub isConsumerLogOn {
return 0;
}
if (isConsumerPhysOff ($hash, $c)) { # Device ist physisch ausgeschaltet
return 0;
}
my $type = $hash->{TYPE};
my $nompower = ConsumerVal ($name, $c, "power", 0); # nominale Leistung lt. Typenschild
my $rpcurr = ConsumerVal ($name, $c, "rpcurr", ""); # Reading für akt. Verbrauch angegeben ?
my $pthreshold = ConsumerVal ($name, $c, "powerthreshold", 0); # Schwellenwert (W) ab der ein Verbraucher als aktiv gewertet wird
if (!$rpcurr && isConsumerPhysOn ($hash, $c)) { # Workaround wenn Verbraucher ohne Leistungsmessung
$pcurr = $nompower;
if (!$rpcurr) { # Workaround wenn Verbraucher ohne Leistungsmessung
if (isConsumerPhysOn ($hash, $c)) { $pcurr = $nompower }
else { $pcurr = 0 }
}
my $currpowerpercent = $pcurr;
$currpowerpercent = ($pcurr / $nompower) * 100 if($nompower > 0);
my $currpowerpercent;
if ($nompower > 0) { $currpowerpercent = sprintf ('%.2f', $pcurr / $nompower * 100) }
else { $currpowerpercent = 0 }
$data{$name}{consumers}{$c}{currpowerpercent} = $currpowerpercent;
if (isConsumerPhysOff ($hash, $c)) { # Device ist physisch ausgeschaltet
return 0;
}
if ($pcurr > $pthreshold || (!$pthreshold && $currpowerpercent > DEFPOPERCENT)) { # Verbraucher ist logisch aktiv
return 1;
@@ -28103,6 +28183,7 @@ to ensure that the system configuration is correct.
<colgroup> <col width="27%"> <col width="73%"> </colgroup>
<tr><td> <b>BatPowerIn_Sum</b> </td><td>the sum of the current battery charging power of all defined battery devices </td></tr>
<tr><td> <b>BatPowerOut_Sum</b> </td><td>the sum of the current battery discharge power of all defined battery devices </td></tr>
<tr><td> <b>BatRatio</b> </td><td>The ratio of PV surplus/required charging energy to the battery's charging target (loadTarget) </td></tr>
<tr><td> <b>BatWeightedTotalSOC</b> </td><td>the resulting (weighted) SOC across all installed batteries in % </td></tr>
<tr><td> <b>allStringsFullfilled</b> </td><td>Fulfillment status of error-free generation of all strings </td></tr>
<tr><td> <b>conForecastComingNight</b> </td><td>Consumption forecast from the coming sunset to the coming sunrise. If the sunset has already passed, </td></tr>
@@ -28869,7 +28950,7 @@ to ensure that the system configuration is correct.
<tr><td> <b>pvOut</b> </td><td>A reading that provides the current power from PV generation that is supplied to the battery(ies) or to a battery inverter. </td></tr>
<tr><td> </td><td>A positive numerical value is expected. </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>etotal</b> </td><td>The Reading which provides the total PV energy generated (a steadily increasing counter). </td></tr>
<tr><td> <b>etotal</b> </td><td>The reading, which provides the total PV energy generated by the inverter as a continuously increasing counter. </td></tr>
<tr><td> </td><td>If the reading violates the specification of a continuously rising counter, </td></tr>
<tr><td> </td><td>SolarForecast handles this error and reports the situation by means of a log message. </td></tr>
<tr><td> </td><td> </td></tr>
@@ -30887,6 +30968,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<colgroup> <col width="27%"> <col width="73%"> </colgroup>
<tr><td> <b>BatPowerIn_Sum</b> </td><td>die Summe der momentanen Batterieladeleistung aller definierten Batterie Geräte </td></tr>
<tr><td> <b>BatPowerOut_Sum</b> </td><td>die Summe der momentanen Batterieentladeleistung aller definierten Batterie Geräte </td></tr>
<tr><td> <b>BatRatio</b> </td><td>das Verhältnis (Ratio) von PV-Überschuß / benötigter Ladeenergie zum Ladeziel (loadTarget) der Batterie(n) </td></tr>
<tr><td> <b>BatWeightedTotalSOC</b> </td><td>der resultierende (gewichtete) SOC über alle installierten Batterien in % </td></tr>
<tr><td> <b>allStringsFullfilled</b> </td><td>Erfüllungsstatus der fehlerfreien Generierung aller Strings </td></tr>
<tr><td> <b>conForecastComingNight</b> </td><td>Verbrauchsprognose vom kommenden Sonnenuntergang bis zum kommenden Sonnenaufgang. Ist der Sonnenuntergang </td></tr>
@@ -31639,7 +31721,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> <b>pvOut</b> </td><td>Ein Reading, welches die aktuelle Leistung aus PV-Erzeugung, die an das Hausnetz oder öffentliche Netz </td></tr>
<tr><td> </td><td>geliefert wird, bereitstellt. Es wird ein positiver numerischer Wert erwartet. </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>etotal</b> </td><td>Das Reading, welches die gesamte erzeugte PV-Energie liefert (ein stetig aufsteigender Zähler). </td></tr>
<tr><td> <b>etotal</b> </td><td>Das Reading, welches die gesamte erzeugte PV-Energie des Wechselrichters als stetig aufsteigenden Zähler liefert. </td></tr>
<tr><td> </td><td>Sollte des Reading die Vorgabe eines stetig aufsteigenden Zählers verletzen, behandelt </td></tr>
<tr><td> </td><td>SolarForecast diesen Fehler und meldet die aufgetretene Situation durch einen Logeintrag. </td></tr>
<tr><td> </td><td> </td></tr>

View File

@@ -1,6 +1,6 @@
REV 30528
REV 30550
DIR unused
UPD 2025-11-14_07:45:03 450791 ./CHANGED
UPD 2025-11-23_07:45:17 450975 ./CHANGED
UPD 2020-10-26_19:49:05 18092 ./GPL_V2.txt
UPD 2025-09-12_07:45:04 47218 ./MAINTAINER.txt
UPD 2025-03-18_07:45:03 47176 ./configDB.pm
@@ -382,7 +382,7 @@ UPD 2017-09-27_07:45:02 51988 FHEM/71_YAMAHA_BD.pm
UPD 2021-01-17_07:45:02 273182 FHEM/71_YAMAHA_MC.pm
UPD 2019-07-13_07:45:02 131256 FHEM/71_YAMAHA_NP.pm
UPD 2019-11-07_07:45:03 19531 FHEM/71_ZM_Monitor.pm
UPD 2025-09-10_07:45:04 44506 FHEM/72_FBTAM.pm
UPD 2025-11-21_07:45:03 44609 FHEM/72_FBTAM.pm
UPD 2021-11-29_07:45:03 89494 FHEM/72_FB_CALLLIST.pm
UPD 2023-11-15_07:45:03 127780 FHEM/72_FB_CALLMONITOR.pm
UPD 2025-11-05_07:45:03 885770 FHEM/72_FRITZBOX.pm
@@ -422,7 +422,7 @@ UPD 2016-08-22_07:45:11 9037 FHEM/76_MSGFile.pm
UPD 2016-12-08_07:45:12 17663 FHEM/76_MSGMail.pm
UPD 2022-11-02_07:45:02 77314 FHEM/76_SMAEVCharger.pm
UPD 2025-06-03_07:45:03 173445 FHEM/76_SMAInverter.pm
UPD 2025-11-14_07:45:03 1806487 FHEM/76_SolarForecast.pm
UPD 2025-11-23_07:45:17 1813204 FHEM/76_SolarForecast.pm
UPD 2025-01-21_07:45:03 43252 FHEM/76_msgDialog.pm
UPD 2021-10-29_07:45:03 57317 FHEM/77_SMAEM.pm
UPD 2016-07-19_07:45:16 23026 FHEM/77_SMASTP.pm
@@ -764,12 +764,12 @@ UPD 2016-07-21_07:45:27 24829 docs/HOWTO_DE.html
UPD 2015-07-28_14:05:35 46151 docs/IMG_0483.jpg
UPD 2017-06-30_07:45:02 37394 docs/Landis-Gyr-E350-meter.jpg
UPD 2015-07-28_14:05:35 14548 docs/ccc.jpg
UPD 2025-11-14_07:45:10 5384172 docs/commandref.html
UPD 2025-11-14_07:45:14 3393281 docs/commandref_DE.html
UPD 2025-11-23_07:45:24 5384377 docs/commandref.html
UPD 2025-11-23_07:45:28 3393478 docs/commandref_DE.html
UPD 2025-05-03_07:45:04 86553 docs/commandref_frame.html
UPD 2025-05-03_07:45:04 97225 docs/commandref_frame_DE.html
UPD 2025-11-15_07:45:16 326323 docs/commandref_modular.html
UPD 2025-11-15_07:45:17 338159 docs/commandref_modular_DE.html
UPD 2025-11-25_07:45:16 326323 docs/commandref_modular.html
UPD 2025-11-25_07:45:17 338159 docs/commandref_modular_DE.html
UPD 2015-07-28_14:05:35 4778 docs/cul_rfr.jpg
UPD 2015-07-28_14:05:35 19949 docs/faq.html
UPD 2015-07-28_14:05:35 938 docs/fhemdoc.js