33 Commits

Author SHA1 Message Date
3bed304493 WS3600: readingFnAttributes 2025-11-28 22:52:02 +01:00
Beta-User
5dbd526d0f MYSENSORS_DEVICE: fix commandref
git-svn-id: https://svn.fhem.de/fhem/trunk@30561 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-27 15:20:41 +00:00
Beta-User
83fe0a32c6 MAINTAINER.txt: fix missing .pm's for pre-commit
git-svn-id: https://svn.fhem.de/fhem/trunk@30560 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-27 15:20:27 +00:00
fhemupdate
d9c01cf0e4 controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30559 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-27 06:45:17 +00:00
Beta-User
7c7985fe24 FULLY: maintainer change + commandref update
git-svn-id: https://svn.fhem.de/fhem/trunk@30558 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-26 21:33:54 +00:00
jowiemann
bfbb104025 72_FRITZBOX.pm: Version 08.20.08c
git-svn-id: https://svn.fhem.de/fhem/trunk@30557 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-26 13:15:15 +00:00
jowiemann
0978cc7368 72_FRITZBOX.pm: Version 08.20.08b
git-svn-id: https://svn.fhem.de/fhem/trunk@30556 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-26 11:51:57 +00:00
jowiemann
b70d0bcd04 CHANGED: 72_FRITZBOX.pm
git-svn-id: https://svn.fhem.de/fhem/trunk@30555 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-26 11:51:05 +00:00
fhemupdate
df916eff0f controls_fhem.txt: fhemupdate checkin
git-svn-id: https://svn.fhem.de/fhem/trunk@30554 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2025-11-26 06:45:17 +00: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
10 changed files with 2324 additions and 1465 deletions

View File

@@ -1,5 +1,13 @@
# 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: Fehlerkorrektur Reading shdevice<id>_holidayActive
commadRef
- 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

@@ -1345,7 +1345,7 @@ __END__
<a id="MYSENSORS_DEVICE-define"></a>
<h4>Define</h4>
<p><code>define &lt;name&gt; MYSENSORS_DEVICE &lt;Sensor-type&gt; &lt;node-id&gt;</code>
<p><code>define &lt;name&gt; MYSENSORS_DEVICE &lt;Sensor-type&gt; &lt;node-id&gt;</code></p>
<p>Specifies the MYSENSOR_DEVICE device.</p>
<a id="MYSENSORS_DEVICE-set"></a>

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

File diff suppressed because it is too large Load Diff

View File

@@ -41,7 +41,7 @@ FHEM/00_Neuron.pm klausw Sonstige Systeme
FHEM/00_OW2S0SMSGUARD.pm wzut 1Wire
FHEM/00_OWX.pm pahenning 1Wire
FHEM/00_OWX_ASYNC ntruchsess 1Wire
FHEM/00_RPII2C klausw Einplatinencomputer
FHEM/00_RPII2C.pm klausw Einplatinencomputer
FHEM/00_SIGNALduino.pm Sidey Sonstige Systeme
FHEM/00_SONOS.pm Reinerlein Multimedia
FHEM/00_TCM.pm klaus-schauer EnOcean
@@ -61,7 +61,7 @@ FHEM/09_CUL_FHTTK.pm matscher SlowRF
FHEM/09_USF1000.pm neubert SlowRF
FHEM/10_CUL_HM.pm martinp876 HomeMatic
FHEM/10_CUL_IR.pm odroegehorn SlowRF
FHEM/10_DUOFERNSTICK telekatz Sonstige Systeme
FHEM/10_DUOFERNSTICK.pm telekatz Sonstige Systeme
FHEM/10_EnOcean.pm klaus-schauer EnOcean
FHEM/10_EQ3BT.pm dominikkarall Sonstige Systeme
FHEM/10_FBDECT.pm rudolfkoenig FRITZ!Box
@@ -70,15 +70,15 @@ FHEM/10_FS20.pm rudolfkoenig SlowRF
FHEM/10_GFPROBT.pm dominik Sonstige Systeme
FHEM/10_HXBDevice.pm neubert Sonstige Systeme
FHEM/10_IT.pm Ralf9/KoelnSolar InterTechno
FHEM/10_Itach_IR ulimaass Sonstige Systeme
FHEM/10_Itach_IR.pm ulimaass Sonstige Systeme
FHEM/10_KNX.pm erwin KNX/EIB (Forum #122582) https://forum.fhem.de/index.php/topic,122582.0.html
FHEM/10_KOPP_FC.pm raspii Sonstige Systeme
FHEM/10_MAX.pm Wzut MAX
FHEM/10_MQTT2_DEVICE.pm rudolfkoenig MQTT
FHEM/10_MQTT_BRIDGE hexenmeister MQTT
FHEM/10_MQTT_DEVICE hexenmeister MQTT
FHEM/10_MQTT_GENERIC_BRIDGE hexenmeister MQTT
FHEM/10_MYSENSORS_DEVICE Beta-User Bastelecke/MySensors
FHEM/10_MQTT_BRIDGE.pm hexenmeister MQTT
FHEM/10_MQTT_DEVICE.pm hexenmeister MQTT
FHEM/10_MQTT_GENERIC_BRIDGE.pm hexenmeister MQTT
FHEM/10_MYSENSORS_DEVICE.pm Beta-User Bastelecke/MySensors
FHEM/10_NeuronPin.pm klausw Sonstige Systeme
FHEM/10_OWServer.pm neubert/mfr69bs 1Wire
FHEM/10_pilight_ctrl.pm risiko Sonstige Systeme
@@ -139,9 +139,9 @@ FHEM/20_N4HBUS.pm okoerber Sonstige Systeme
FHEM/20_PET.pm loredo Automatisierung
FHEM/20_ROOMMATE.pm loredo Automatisierung
FHEM/20_X10.pm neubert SlowRF
FHEM/21_HEOSGroup CoolTux Multimedia
FHEM/21_HEOSMaster CoolTux Multimedia
FHEM/21_HEOSPlayer CoolTux Multimedia
FHEM/21_HEOSGroup.pm CoolTux Multimedia
FHEM/21_HEOSMaster.pm CoolTux Multimedia
FHEM/21_HEOSPlayer.pm CoolTux Multimedia
FHEM/21_N4HMODULE.pm okoerber Sonstige Systeme
FHEM/21_OWAD.pm pahenning 1Wire
FHEM/21_OWCOUNT.pm pahenning 1Wire
@@ -151,7 +151,7 @@ FHEM/21_OWMULTI.pm pahenning 1Wire
FHEM/21_OWSWITCH.pm pahenning 1Wire
FHEM/21_OWTHERM.pm pahenning 1Wire
FHEM/21_OWVAR.pm pahenning 1Wire
FHEM/21_SONOSPLAYER Reinerlein Multimedia
FHEM/21_SONOSPLAYER.pm Reinerlein Multimedia
FHEM/21_VBUSDEV.pm Tobias/pejonp Sonstige Systeme
FHEM/22_HOMEMODE.pm DeeSPe Automatisierung
FHEM/23_KOSTALPIKO.pm rudolfkoenig/orphan CodeSchnipsel
@@ -161,7 +161,7 @@ FHEM/24_NetIO230B.pm rudolfkoenig/orphan Sonstiges
FHEM/24_TPLinkHS110.pm VolkerKettenbach Sonstige Systeme
FHEM/26_KM273.pm mike3436 Heizungssteuerung/Raumklima
FHEM/26_tahoma.pm mike3436 Sonstige Systeme
FHEM/30_DUOFERN telekatz Sonstige Systeme
FHEM/30_DUOFERN.pm telekatz Sonstige Systeme
FHEM/30_ENECSYSGW.pm akw Sonstige Systeme
FHEM/30_HUEBridge.pm justme1968 Zigbee
FHEM/30_LIGHTIFY.pm justme1968 Zigbee
@@ -285,23 +285,23 @@ FHEM/51_MOBILEALERTS.pm MarkusF Sonstige Systeme
FHEM/51_Netzer.pm klausw Sonstige Systeme
FHEM/51_RPI_GPIO.pm klausw Einplatinencomputer
FHEM/52_I2C_ADS1x1x Adimarantis Sonstige Systeme
FHEM/52_I2C_BME280 klausw Sonstige Systeme
FHEM/52_I2C_DS1307 ntruchsess Sonstige Systeme
FHEM/52_I2C_BME280.pm klausw Sonstige Systeme
FHEM/52_I2C_DS1307.pm ntruchsess Sonstige Systeme
FHEM/52_I2C_EEPROM.pm klausw Sonstige Systeme
FHEM/52_I2C_EMC1001.pm eisler Sonstige Systeme
FHEM/52_I2C_HDC1008.pm yoda_gh Sonstige Systeme
FHEM/52_I2C_K30 yoda_gh Sonstige Systeme
FHEM/52_I2C_LCD ntruchsess Sonstige Systeme
FHEM/52_I2C_LM75A clumsy Sonstige Systeme
FHEM/52_I2C_MCP23008 klausw Sonstige Systeme
FHEM/52_I2C_MCP23017 klausw Sonstige Systeme
FHEM/52_I2C_MCP342x klausw Sonstige Systeme
FHEM/52_I2C_MMA845X jensb Sonstige Systeme
FHEM/52_I2C_PCA9532 klausw Sonstige Systeme
FHEM/52_I2C_PCA9685 klausw Sonstige Systeme
FHEM/52_I2C_PCF8574 klausw Sonstige Systeme
FHEM/52_I2C_SHT21 klausw Sonstige Systeme
FHEM/52_I2C_SHT3x macs Sonstige Systeme
FHEM/52_I2C_K30.pm yoda_gh Sonstige Systeme
FHEM/52_I2C_LCD.pm ntruchsess Sonstige Systeme
FHEM/52_I2C_LM75A.pm clumsy Sonstige Systeme
FHEM/52_I2C_MCP23008.pm klausw Sonstige Systeme
FHEM/52_I2C_MCP23017.pm klausw Sonstige Systeme
FHEM/52_I2C_MCP342x.pm klausw Sonstige Systeme
FHEM/52_I2C_MMA845X.pm jensb Sonstige Systeme
FHEM/52_I2C_PCA9532.pm klausw Sonstige Systeme
FHEM/52_I2C_PCA9685.pm klausw Sonstige Systeme
FHEM/52_I2C_PCF8574.pm klausw Sonstige Systeme
FHEM/52_I2C_SHT21.pm klausw Sonstige Systeme
FHEM/52_I2C_SHT3x.pm macs Sonstige Systeme
FHEM/53_GHoma.pm klausw Sonstige Systeme
FHEM/55_DWD_OpenData.pm DS_Starter/orphan Unterstützende Dienste/Wettermodule
FHEM/55_InfoPanel.pm betateilchen Sonstiges
@@ -313,7 +313,7 @@ FHEM/57_SSCal.pm DS_Starter Unterstützende Dienste/Kalend
FHEM/58_HVAC_DaikinAC.pm roelb Heizungssteuerung/Raumklima (preferably in English and a copy as PM)
FHEM/58_RPI_1Wire.pm Adimarantis Einplatinencomputer https://forum.fhem.de/index.php/topic,123499.0.html
FHEM/59_HCS.pm hjr Automatisierung (oder auch PM)
FHEM/59_LuftdatenInfo rudolfkoenig/orphan Bastelecke
FHEM/59_LuftdatenInfo.pm rudolfkoenig/orphan Bastelecke
FHEM/59_OPENWEATHER.pm tupol Unterstützende Dienste/Wettermodule (Link als PM an tupol)
FHEM/59_PROPLANTA.pm tupol Unterstützende Dienste/Wettermodule (Link als PM an tupol)
FHEM/59_Twilight.pm Beta-User/orphan Unterstützende Dienste/Wettermodule (Forum Thread #114061) https://forum.fhem.de/index.php/topic,114061.0.html
@@ -400,13 +400,13 @@ FHEM/73_AutoShuttersControl.pm CoolTux Automatisierung
FHEM/73_DoorBird.pm Sailor Sonstige Systeme https://forum.fhem.de/index.php/topic,100758
FHEM/73_ElectricityCalculator.pm Sailor Unterstützende Dienste https://forum.fhem.de/index.php/topic,57106.0.html
FHEM/73_GardenaSmartBridge.pm CoolTux Sonstige Systeme
FHEM/73_GasCalculator Sailor Unterstützende Dienste https://forum.fhem.de/index.php/topic,47909.0.html
FHEM/73_GasCalculator.pm Sailor Unterstützende Dienste https://forum.fhem.de/index.php/topic,47909.0.html
FHEM/73_km200.pm Sailor Heizungssteuerung/Raumklima https://forum.fhem.de/index.php/topic,25540.0.html
FHEM/73_MPD.pm Wzut/Beta-User Multimedia
FHEM/73_NUKIBridge.pm CoolTux Sonstige Systeme
FHEM/73_PRESENCE.pm JoWiemann Unterstützende Dienste
FHEM/73_PRESENCE2.pm JoWiemann Unterstützende Dienste cover version
FHEM/73_WaterCalculator Sailor Unterstützende Dienste https://forum.fhem.de/index.php/topic,58579.0.html
FHEM/73_WaterCalculator.pm Sailor Unterstützende Dienste https://forum.fhem.de/index.php/topic,58579.0.html
FHEM/74_AMADDevice.pm CoolTux Sonstige Systeme
FHEM/74_AutomowerConnect.pm Ellert Sonstige Systeme https://forum.fhem.de/index.php/topic,131661.0.html
FHEM/74_GardenaSmartDevice.pm CoolTux Sonstige Systeme
@@ -455,7 +455,7 @@ FHEM/88_xs1Dev.pm HomeAuto_User Sonstige Systeme (Link als PM
FHEM/89_AndroidDB.pm zap Multimedia
FHEM/89_AndroidDBHost.pm zap Multimedia
FHEM/89_ESPEInk.pm eki Sonstige Systeme
FHEM/89_FULLY.pm zap Frontends
FHEM/89_FULLY.pm Beta-User Frontends https://forum.fhem.de/index.php?topic=143143.0
FHEM/89_HEATRONIC.pm heikoranft Sonstige Systeme
FHEM/89_VCLIENT.pm andies Heizungssteuerung/Raumklima
FHEM/89_VCONTROL.pm adamwit Heizungssteuerung/Raumklima
@@ -514,13 +514,13 @@ FHEM/98_DOIF.pm damian-s Automatisierung/DOIF
FHEM/98_DOIFtools.pm Ellert Automatisierung/DOIF https://forum.fhem.de/index.php/topic,63938.0.html
FHEM/98_Dooya.pm Jarnsen/ralf9/darkmission Sonstige Systeme
FHEM/98_dummy.pm rudolfkoenig Automatisierung
FHEM/98_DSBMobile rudolfkoenig/orphan Codeschnipsel https://forum.fhem.de/index.php/topic,107104.0.html
FHEM/98_DSBMobile.pm rudolfkoenig/orphan Codeschnipsel https://forum.fhem.de/index.php/topic,107104.0.html
FHEM/98_expandJSON.pm dev0 Unterstützende Dienste
FHEM/98_feels_like.pm hotbso Wettermodule
FHEM/98_fhemdebug.pm rudolfkoenig Sonstiges
FHEM/98_FhemTestUtils.pm rudolfkoenig Development
FHEM/98_fheminfo.pm betateilchen Sonstiges
FHEM/98_freezemon rudolfkoenig/orphan Unterstützende Dienste
FHEM/98_freezemon.pm rudolfkoenig/orphan Unterstützende Dienste
FHEM/98_FReplacer.pm StefanStrobel Sonstiges
FHEM/98_GAEBUS.pm jamesgo Heizungssteuerung/Raumklima
FHEM/98_GEOFANCY.pm loredo Unterstützende Dienste
@@ -554,7 +554,7 @@ FHEM/98_notice.pm mfr69bs Sonstiges
FHEM/98_PHC.pm StefanStrobel Sonstiges
FHEM/98_PID20.pm betateilchen Sonstiges
FHEM/98_pilight.pm andreas-fey Unterstützende Dienste
FHEM/98_ping mattwire Sonstiges
FHEM/98_ping.pm mattwire Sonstiges
FHEM/98_powerMap rudolfkoenig/orphan Unterstützende Dienste
FHEM/98_QRCode.pm Benni Unterstützende Dienste
FHEM/98_rain.pm baumrasen Sonstiges

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,8 +1,8 @@
REV 30528
REV 30558
DIR unused
UPD 2025-11-14_07:45:03 450791 ./CHANGED
UPD 2025-11-27_07:45:03 451260 ./CHANGED
UPD 2020-10-26_19:49:05 18092 ./GPL_V2.txt
UPD 2025-09-12_07:45:04 47218 ./MAINTAINER.txt
UPD 2025-11-27_07:45:03 47265 ./MAINTAINER.txt
UPD 2025-03-18_07:45:03 47176 ./configDB.pm
UPD 2023-05-29_07:45:03 21936 ./fhem.cfg.demo
UPD 2025-09-21_07:45:17 175157 ./fhem.pl
@@ -382,10 +382,10 @@ 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
UPD 2025-11-27_07:45:03 910429 FHEM/72_FRITZBOX.pm
UPD 2022-02-07_07:45:02 29303 FHEM/72_TA_CMI_JSON.pm
UPD 2022-10-10_07:45:03 15950 FHEM/72_UBUS_CALL.pm
UPD 2023-10-02_07:45:03 17311 FHEM/72_UBUS_CLIENT.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
@@ -449,7 +449,7 @@ UPD 2022-03-09_07:45:03 22906 FHEM/88_xs1Dev.pm
UPD 2022-03-31_07:45:02 29550 FHEM/89_AndroidDB.pm
UPD 2022-03-31_07:45:02 15486 FHEM/89_AndroidDBHost.pm
UPD 2021-10-08_07:45:09 132761 FHEM/89_ESPEInk.pm
UPD 2022-01-21_07:45:03 35785 FHEM/89_FULLY.pm
UPD 2025-11-27_07:45:03 41580 FHEM/89_FULLY.pm
UPD 2016-01-05_07:45:12 44169 FHEM/89_HEATRONIC.pm
UPD 2019-05-27_07:45:02 53160 FHEM/89_VCLIENT.pm
UPD 2016-07-11_07:45:14 62016 FHEM/89_VCONTROL.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-27_07:45:10 5388231 docs/commandref.html
UPD 2025-11-27_07:45:14 3395202 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-27_07:45:16 327112 docs/commandref_modular.html
UPD 2025-11-27_07:45:17 338948 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