mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 00:36:25 +00:00
76_SolarForecast: consumer device may have specified an own alias
git-svn-id: https://svn.fhem.de/fhem/trunk@29559 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
d04d74bb5a
commit
33735a1418
@ -1,5 +1,6 @@
|
||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||
# Do not insert empty lines here, update check depends on it
|
||||
- feature: 76_SolarForecast: consumer device may have specified an own alias
|
||||
- feature: 73_AutoShuttersControl:
|
||||
https://forum.fhem.de/index.php?topic=136510.0
|
||||
- feature: 76_SolarForecast: add temporary Migrate Getter x_migrate,
|
||||
|
@ -104,6 +104,8 @@ BEGIN {
|
||||
getAllSets
|
||||
HttpUtils_NonblockingGet
|
||||
HttpUtils_BlockingGet
|
||||
GetFileFromURL
|
||||
GetHttpFile
|
||||
init_done
|
||||
InternalTimer
|
||||
InternalVal
|
||||
@ -157,6 +159,8 @@ BEGIN {
|
||||
|
||||
# Versions History intern
|
||||
my %vNotesIntern = (
|
||||
"1.44.1" => "20.01.2025 Notification system: minor fixes, integration of controls_solarforecast_messages_test/prod ".
|
||||
"Define: random start of Timer subs, consumerXX: consumer device may have specified an own alias ",
|
||||
"1.44.0" => "19.01.2025 _listDataPoolCircular: may select a dedicated hour, add temporary Migrate funktion x_migrate ".
|
||||
"fix interruptable key check in consumer attr Forum:https://forum.fhem.de/index.php?msg=1331073 ".
|
||||
"set prdef to 1.0, Implementation of a Messaging System ",
|
||||
@ -423,6 +427,7 @@ my $calcmaxd = 30;
|
||||
my @dweattrmust = qw(TTT Neff RR1c ww SunUp SunRise SunSet); # Werte die im Attr forecastProperties des Weather-DWD_Opendata Devices mindestens gesetzt sein müssen
|
||||
my @draattrmust = qw(Rad1h); # Werte die im Attr forecastProperties des Radiation-DWD_Opendata Devices mindestens gesetzt sein müssen
|
||||
my $whistrepeat = 851; # Wiederholungsintervall Cache File Daten schreiben
|
||||
my $gmfblto = 30; # Timeout Aholen Message File aus contrib
|
||||
|
||||
my $solapirepdef = 3600; # default Abrufintervall SolCast API (s)
|
||||
my $forapirepdef = 900; # default Abrufintervall ForecastSolar API (s)
|
||||
@ -489,10 +494,14 @@ my $actcoldef = 'orange';
|
||||
my $inactcoldef = 'grey'; # default Färbung Icon wenn inaktiv
|
||||
|
||||
my $bPath = 'https://svn.fhem.de/trac/browser/trunk/fhem/contrib/SolarForecast/'; # Basispfad Abruf contrib SolarForecast Files
|
||||
my $pPath = '?format=txt'; # Download Format
|
||||
my $cfile = 'controls_solarforecast.txt'; # Name des Controlfiles
|
||||
|
||||
my $cfile = 'controls_solarforecast.txt'; # Controlfile Update FTUI-Files
|
||||
my $msgfiletest = 'controls_solarforecast_messages_test.txt'; # TEST Input-File Notification System
|
||||
my $msgfileprod = 'controls_solarforecast_messages_prod.txt'; # PRODUKTIVES Input-File Notification System
|
||||
my $pPath = '?format=txt'; # Download Format
|
||||
my $gmfilerepeat = 3000; # Wiederholungsuntervall Aholen Message File aus contrib
|
||||
my $idxlimit = 900000; # Notification System: Indexe > $idxlimit sind reserviert für Steuerungsaufgaben
|
||||
|
||||
my $messagefile = $msgfileprod;
|
||||
# mögliche Debug-Module
|
||||
my @dd = qw( aiProcess
|
||||
aiData
|
||||
@ -803,12 +812,14 @@ my %hqtxt = ( # H
|
||||
DE => qq{heute} },
|
||||
simsg => { EN => qq{Message},
|
||||
DE => qq{Mitteilung} },
|
||||
msgsys => { EN => qq{Messaging system},
|
||||
msgsys => { EN => qq{Notification system},
|
||||
DE => qq{Mitteilungssystem} },
|
||||
msgimp => { EN => qq{Importance},
|
||||
DE => qq{Wichtigkeit} },
|
||||
number => { EN => qq{Number},
|
||||
DE => qq{Nummer} },
|
||||
ludich => { EN => qq{last update Input channels},
|
||||
DE => qq{letzte Aktualisierung Eingangskanäle} },
|
||||
ctnsly => { EN => qq{continuously},
|
||||
DE => qq{fortlaufend} },
|
||||
yday => { EN => qq{yesterday},
|
||||
@ -871,6 +882,8 @@ my %hqtxt = ( # H
|
||||
DE => qq{Oh nein 😢, die Anlagenkonfiguration ist fehlerhaft. Bitte überprüfen Sie die Einstellungen und Hinweise!} },
|
||||
pstate => { EN => qq{Planning status: <pstate><br>Info: <supplmnt><br>Mode: <mode><br>On: <start><br>Off: <stop><br>Remaining lock time: <RLT> seconds},
|
||||
DE => qq{Planungsstatus: <pstate><br>Info: <supplmnt><br>Modus: <mode><br>Ein: <start><br>Aus: <stop><br>verbleibende Sperrzeit: <RLT> Sekunden} },
|
||||
dmgsig => { EN => qq{Read messages are not signaled again until a FHEM restart, but are retained if they are relevant.},
|
||||
DE => qq{Gelesene Mitteilungen werden bis zu einem FHEM Neustart nicht wieder signalisiert, bleiben bei Relevanz jedoch erhalten.} },
|
||||
);
|
||||
|
||||
my %htitles = ( # Hash Hilfetexte (Mouse Over)
|
||||
@ -1301,7 +1314,9 @@ my %hfspvh = (
|
||||
# $data{$name}{dwdcatalog} # temporärer Speicher DWD Stationskatalog
|
||||
# $data{$name}{strings} # temporärer Speicher Stringkonfiguration
|
||||
# $data{$name}{aidectree}{object} # AI Decision Tree Object
|
||||
# $data{$name}{messages} # Speicher Mitteilungssystem
|
||||
# $data{$name}{messages} # Mitteilungssystem - permanent erneuerter Speicher
|
||||
# $data{$name}{filemessages} # Mitteilungssystem - Input vom Message File
|
||||
# $data{$name}{preparedmessages} # Mitteilungssystem - vorbereitete Messages innerhalb des Code
|
||||
|
||||
################################################################
|
||||
# Init Fn
|
||||
@ -1479,9 +1494,10 @@ sub Define {
|
||||
reloadCacheFiles ($params);
|
||||
singleUpdateState ( {hash => $hash, state => 'initialized', evt => 1} );
|
||||
|
||||
$readyfnlist{$name} = $hash; # Registrierung in Ready-Schleife
|
||||
InternalTimer (gettimeofday()+$whistrepeat, "FHEM::SolarForecast::periodicWriteMemcache", $hash, 0); # Einstieg periodisches Schreiben historische Daten
|
||||
|
||||
$readyfnlist{$name} = $hash; # Registrierung in Ready-Schleife
|
||||
InternalTimer (gettimeofday() + $whistrepeat + int(rand(300)), "FHEM::SolarForecast::periodicWriteMemcache", $hash, 0); # Einstieg periodisches Schreiben historische Daten
|
||||
InternalTimer (gettimeofday() + 120 + int(rand(300)), "FHEM::SolarForecast::getMessageFileNonBlocking", $hash, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4661,7 +4677,7 @@ sub _getoutputMessages { ## no critic "not used"
|
||||
my $out = outputMessages ($paref);
|
||||
$out = qq{<html>$out</html>};
|
||||
|
||||
$data{$name}{messages}{9999}{RD} = 1; # Lesekennzeichen setzen
|
||||
$data{$name}{messages}{999999}{RD} = 1; # Lesekennzeichen setzen
|
||||
|
||||
## asynchrone Ausgabe
|
||||
#######################
|
||||
@ -5400,21 +5416,10 @@ sub __updPreFile {
|
||||
$err .= "Please check whether the path $path is present and accessible.<br>";
|
||||
$err .= "After installing FTUI, come back and execute the get command again.";
|
||||
return $err;
|
||||
|
||||
#my $ok = mkdir $path;
|
||||
|
||||
#if (!$ok) {
|
||||
# $err = "MKDIR ERROR: $!";
|
||||
# Log3 ($name, 1, "$name - $err");
|
||||
# return $err;
|
||||
#}
|
||||
#else {
|
||||
# Log3 ($name, 3, "$name - MKDIR $path");
|
||||
#}
|
||||
}
|
||||
}
|
||||
|
||||
($err, my $remFile) = __updGetUrl ($name, $bPath.$file.$pPath);
|
||||
($err, my $remFile) = __httpBlockingGet ($name, $bPath.$file.$pPath);
|
||||
|
||||
if ($err) {
|
||||
Log3 ($name, 1, "$name - $err");
|
||||
@ -5446,27 +5451,27 @@ return;
|
||||
###############################################################
|
||||
# File von url holen
|
||||
###############################################################
|
||||
sub __updGetUrl {
|
||||
sub __httpBlockingGet {
|
||||
my $name = shift;
|
||||
my $url = shift;
|
||||
|
||||
$url =~ s/%/%25/g;
|
||||
my %upd_connecthash;
|
||||
my %connecthash;
|
||||
my $unicodeEncoding = 1;
|
||||
|
||||
$upd_connecthash{url} = $url;
|
||||
$upd_connecthash{keepalive} = ($url =~ m/localUpdate/ ? 0 : 1); # Forum #49798
|
||||
$upd_connecthash{forceEncoding} = '' if($unicodeEncoding);
|
||||
$connecthash{url} = $url;
|
||||
$connecthash{keepalive} = ($url =~ m/localUpdate/ ? 0 : 1); # Forum #49798
|
||||
$connecthash{forceEncoding} = '' if($unicodeEncoding);
|
||||
|
||||
my ($err, $dat) = HttpUtils_BlockingGet (\%upd_connecthash);
|
||||
my ($err, $dat) = HttpUtils_BlockingGet (\%connecthash);
|
||||
|
||||
if ($err) {
|
||||
$err = "update ERROR: $err";
|
||||
$err = "GetUrl ERROR: $err";
|
||||
return ($err, '');
|
||||
}
|
||||
|
||||
if (!$dat) {
|
||||
$err = 'update ERROR: empty file received';
|
||||
$err = 'WARNING - empty file received';
|
||||
return ($err, '');
|
||||
}
|
||||
|
||||
@ -7347,7 +7352,7 @@ sub runTask {
|
||||
}
|
||||
|
||||
releaseCentralTask ($hash);
|
||||
centralTask ($hash, 1);
|
||||
centralTask ($hash, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -7363,13 +7368,13 @@ sub runTask {
|
||||
}
|
||||
|
||||
releaseCentralTask ($hash);
|
||||
centralTask ($hash, 1);
|
||||
centralTask ($hash, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete $hash->{HELPER}{S03DONE};
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -7638,6 +7643,7 @@ sub centralTask {
|
||||
setTimeTracking ($hash, $cst, 'runTimeCentralTask'); # Zyklus-Laufzeit ermitteln
|
||||
|
||||
createReadingsFromArray ($hash, $evt); # Readings erzeugen
|
||||
_readSystemMessages ($centpars); # Notification System - System Messages zusammenstellen
|
||||
|
||||
if ($evt) {
|
||||
$centpars->{evt} = $evt;
|
||||
@ -7822,10 +7828,10 @@ sub _collectAllRegConsumers {
|
||||
|
||||
for my $c (1..$maxconsumer) {
|
||||
$c = sprintf "%02d", $c;
|
||||
my ($err, $consumer, $hc) = isDeviceValid ( { name => $name, obj => "consumer${c}", method => 'attr' } );
|
||||
my ($err, $consumer, $hc, $alias) = isDeviceValid ( { name => $name, obj => "consumer${c}", method => 'attr' } );
|
||||
next if($err);
|
||||
|
||||
push @{$data{$name}{current}{consumerdevs}}, $consumer; # alle Consumerdevices in CurrentHash eintragen
|
||||
push @{$data{$name}{current}{consumerdevs}}, $consumer; # alle Consumerdevices in CurrentHash eintragen
|
||||
|
||||
my $dswitch = $hc->{switchdev}; # alternatives Schaltdevice
|
||||
|
||||
@ -7833,13 +7839,13 @@ sub _collectAllRegConsumers {
|
||||
my ($err) = isDeviceValid ( { name => $name, obj => $dswitch, method => 'string' } );
|
||||
next if($err);
|
||||
|
||||
push @{$data{$name}{current}{consumerdevs}}, $dswitch if($dswitch ne $consumer); # Switchdevice zusätzlich in CurrentHash eintragen
|
||||
push @{$data{$name}{current}{consumerdevs}}, $dswitch if($dswitch ne $consumer); # Switchdevice zusätzlich in CurrentHash eintragen
|
||||
}
|
||||
else {
|
||||
$dswitch = $consumer;
|
||||
}
|
||||
|
||||
my $alias = AttrVal ($consumer, 'alias', $consumer);
|
||||
$alias = AttrVal ($consumer, 'alias', $consumer) if(!$alias);
|
||||
|
||||
my ($rtot,$utot,$ethreshold);
|
||||
if (exists $hc->{etotal}) {
|
||||
@ -9912,7 +9918,7 @@ return $sf;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Erstellung Batterie Ladefreigabe
|
||||
# Erstellung Batterie Ladefreigabe + SoC Prognose
|
||||
################################################################
|
||||
sub _batChargeRecmd {
|
||||
my $paref = shift;
|
||||
@ -10046,11 +10052,7 @@ sub _batChargeRecmd {
|
||||
|
||||
$socwh = sprintf "%.0f", $socwh;
|
||||
my $progsoc = sprintf "%.1f", (100 * $socwh / $batinstcap); # Prognose SoC in %
|
||||
|
||||
#$progsoc = $progsoc < $batoptsoc ? $batoptsoc :
|
||||
# $progsoc < $lowSoc ? $lowSoc :
|
||||
# $progsoc;
|
||||
|
||||
|
||||
__createNextHoursSFCReadings ( {name => $name,
|
||||
nhr => $nhr,
|
||||
bn => $bn,
|
||||
@ -12626,65 +12628,6 @@ sub __calcFcQuality {
|
||||
return $hdv;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Berechnen Tag / Stunden Verschieber
|
||||
# aus aktueller Stunde + lfd. Nummer
|
||||
################################################################
|
||||
sub calcDayHourMove {
|
||||
my $chour = shift;
|
||||
my $num = shift;
|
||||
|
||||
my $fh = $chour + $num;
|
||||
my $fd = int ($fh / 24) ;
|
||||
$fh = $fh - ($fd * 24);
|
||||
|
||||
return ($fd, $fh);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Zeit gemäß DWD_OpenData-Format
|
||||
# Berechnen Tag / Stunden Verschieber ab aktuellen Tag
|
||||
# Input: YYYY-MM-DD HH:MM:SS
|
||||
# Output: $fd - 0 (Heute), 1 (Morgen), 2 (Übermorgen), ....
|
||||
# $fh - Stunde von $fd ohne führende Null
|
||||
# Return: fc${fd}_${fh}
|
||||
################################################################
|
||||
sub formatWeatherTimestrg {
|
||||
my $date = shift // return;
|
||||
|
||||
my $cdate = strftime "%Y-%m-%d", localtime(time);
|
||||
my $refts = timestringToTimestamp ($cdate.' 00:00:00'); # Referenztimestring
|
||||
my $datts = timestringToTimestamp ($date);
|
||||
my $fd = int (($datts - $refts) / 86400);
|
||||
my $fh = int ((split /[ :]/, $date)[1]);
|
||||
|
||||
return "fc${fd}_${fh}";
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Spezialfall auflösen wenn Wert von $val2 dem
|
||||
# Redingwert von $val1 entspricht sofern $val1 negativ ist
|
||||
################################################################
|
||||
sub substSpecialCases {
|
||||
my $paref = shift;
|
||||
my $dev = $paref->{dev};
|
||||
my $rdg = $paref->{rdg};
|
||||
my $rdgf = $paref->{rdgf};
|
||||
|
||||
my $val1 = ReadingsNum ($dev, $rdg, 0) * $rdgf;
|
||||
my $val2;
|
||||
|
||||
if($val1 <= 0) {
|
||||
$val2 = abs($val1);
|
||||
$val1 = 0;
|
||||
}
|
||||
else {
|
||||
$val2 = 0;
|
||||
}
|
||||
|
||||
return ($val1,$val2);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Energieverbrauch des Hauses in History speichern
|
||||
################################################################
|
||||
@ -12970,6 +12913,36 @@ sub _genSpecialReadings {
|
||||
return;
|
||||
}
|
||||
|
||||
###################################################################################
|
||||
# Messagefile für Notification System lesen
|
||||
# Filestruktur:
|
||||
# 0|SV|1
|
||||
# 0|DE|Mitteilung ....
|
||||
# 0|EN|Message...
|
||||
# $data{$name}{preparedmessages}{999500}{TS}: Timestamp Stand prepared Messages
|
||||
###################################################################################
|
||||
sub _readSystemMessages {
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
|
||||
delete $data{$name}{preparedmessages};
|
||||
|
||||
my $midx = 0;
|
||||
|
||||
if (!ReadingsVal ($name, '.migrated', 0)) {
|
||||
$midx++;
|
||||
$data{$name}{preparedmessages}{$midx}{SV} = 1;
|
||||
$data{$name}{preparedmessages}{$midx}{DE} = 'Die gespeicherten PV Daten können mit "get ... x_migrate" in ein neues Format umgesetzt werden welches den Median Ansatz bei der PV Prognose aktiviert und nutzt.';
|
||||
$data{$name}{preparedmessages}{$midx}{DE} .= '<br>Mit einem späteren Update des Moduls erfolgt diese Umstellung automatisch.';
|
||||
$data{$name}{preparedmessages}{$midx}{EN} = 'The stored PV data can be converted with “get ... x_migrate” into a new format which activates and uses the median approach in the PV forecast.';
|
||||
$data{$name}{preparedmessages}{$midx}{EN} .= '<br>With a later update of the module, this changeover will take place automatically.';
|
||||
}
|
||||
|
||||
$data{$name}{preparedmessages}{999500}{TS} = time;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# FHEMWEB Fn
|
||||
################################################################
|
||||
@ -13483,7 +13456,7 @@ sub _graphicHeader {
|
||||
|
||||
## Message-Icon
|
||||
#################
|
||||
my ($micon, $midx) = __fillupMessages ($paref);
|
||||
my ($micon, $midx) = fillupMessageSystem ($paref);
|
||||
$img = FW_makeImage ($micon);
|
||||
my $msgicon = $midx ? "<a onClick=$cmdoutmsg>$img</a>" : $img;
|
||||
my $msgtitle = $midx ? $htitles{outpmsg}{$lang} : $htitles{nomsgfo}{$lang};
|
||||
@ -13766,47 +13739,6 @@ sub _graphicHeader {
|
||||
return $header;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Mitteilungssystem füllen
|
||||
# Schweregrad SV:
|
||||
# 0 - keine Mitteilung
|
||||
# 1 - Mitteilung
|
||||
# 2 - Warnung
|
||||
# 3 - Fehler / Problem
|
||||
################################################################
|
||||
sub __fillupMessages {
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
my $lang = $paref->{lang};
|
||||
|
||||
for my $idx (keys %{$data{$name}{messages}}) {
|
||||
next if($idx == 9999);
|
||||
delete $data{$name}{messages}{$idx};
|
||||
}
|
||||
|
||||
my $midx = 0;
|
||||
my $max_sv = 0;
|
||||
|
||||
if (!ReadingsVal ($name, '.migrated', 0)) {
|
||||
$midx++;
|
||||
$data{$name}{messages}{$midx}{SV} = 1;
|
||||
$data{$name}{messages}{$midx}{DE} = 'Die gespeicherten PV Daten können mit "get ... x_migrate" in ein neues Format umgesetzt werden welches den Median Ansatz bei der PV Prognose aktiviert und nutzt.';
|
||||
$data{$name}{messages}{$midx}{DE} .= '<br>Mit einem späteren Update des Moduls erfolgt diese Umstellung automatisch.';
|
||||
$data{$name}{messages}{$midx}{EN} = 'The stored PV data can be converted with “get ... x_migrate” into a new format which activates and uses the median approach in the PV forecast.';
|
||||
$data{$name}{messages}{$midx}{EN} .= '<br>With a later update of the module, this changeover will take place automatically.';
|
||||
}
|
||||
|
||||
if ($midx && !defined $data{$name}{messages}{9999}{RD}) { # RD = Read-Bit
|
||||
my @aidx = map { $_ } (1..$midx); # größte vorhandene Severity finden
|
||||
my @values = map { $data{$name}{messages}{$_}{SV} } @aidx;
|
||||
$max_sv = max(@values);
|
||||
}
|
||||
|
||||
my $max_icon = $svicons{$max_sv}; # ... und das dazugehörige Icon
|
||||
|
||||
return ($max_icon, $midx);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# erstelle Update-Icon
|
||||
################################################################
|
||||
@ -16501,6 +16433,313 @@ sub _addHourAiRawdata {
|
||||
return;
|
||||
}
|
||||
|
||||
###############################################################
|
||||
# Abruf und Einlesen Messagefile nonBlocking
|
||||
###############################################################
|
||||
sub getMessageFileNonBlocking {
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
RemoveInternalTimer ($hash, "FHEM::SolarForecast::getMessageFileNonBlocking");
|
||||
InternalTimer (gettimeofday() + $gmfilerepeat, "FHEM::SolarForecast::getMessageFileNonBlocking", $hash, 0);
|
||||
|
||||
my (undef, $disabled, $inactive) = controller ($name);
|
||||
return if($disabled || $inactive);
|
||||
|
||||
delete $hash->{HELPER}{GMFRUNNING} if(defined $hash->{HELPER}{GMFRUNNING}{pid} && $hash->{HELPER}{GMFRUNNING}{pid} =~ /DEAD/xs);
|
||||
|
||||
if (defined $hash->{HELPER}{GMFRUNNING}{pid}) {
|
||||
Log3 ($name, 3, qq{$name - another Message File Process with PID "$hash->{HELPER}{GMFRUNNING}{pid}" is already running ... get Message File is aborted});
|
||||
return;
|
||||
}
|
||||
|
||||
Log3 ($name, 4, "$name - Notification System - Message file >$messagefile< is retrieved non blocking");
|
||||
|
||||
my $paref = { name => $name,
|
||||
hash => $hash,
|
||||
block => 1
|
||||
};
|
||||
|
||||
$hash->{HELPER}{GMFRUNNING} = BlockingCall ( "FHEM::SolarForecast::_retrieveMessageFile",
|
||||
$paref,
|
||||
"FHEM::SolarForecast::_processMessageFile",
|
||||
$gmfblto,
|
||||
"FHEM::SolarForecast::_abortGetMessageFile",
|
||||
$hash
|
||||
);
|
||||
|
||||
|
||||
if (defined $hash->{HELPER}{GMFRUNNING}) {
|
||||
$hash->{HELPER}{GMFRUNNING}{loglevel} = 3;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
###############################################################
|
||||
# Message File aus contrib abholen
|
||||
###############################################################
|
||||
sub _retrieveMessageFile {
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
my $block = $paref->{block} // 0;
|
||||
|
||||
my $valid = 1;
|
||||
my ($err, $remfile) = __httpBlockingGet ($name, $bPath.$messagefile.$pPath);
|
||||
|
||||
$remfile = q{} if($remfile =~ /No\snode\strunk\/fhem\/contrib\/SolarForecast\//xs);
|
||||
|
||||
if ($err) {
|
||||
$valid = 0;
|
||||
Log3 ($name, 4, "$name - Notification System - retrieve of remote Message File faulty: $err");
|
||||
}
|
||||
|
||||
if (!$remfile) {
|
||||
$valid = 0;
|
||||
Log3 ($name, 4, "$name - Notification System - no remote Message File >$messagefile< found");
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
$err = __updWriteFile ("$root/FHEM/", $messagefile, $remfile);
|
||||
|
||||
if ($err) {
|
||||
$valid = 0;
|
||||
Log3 ($name, 1, "$name - $err");
|
||||
}
|
||||
else {
|
||||
Log3 ($name, 4, "$name - Notification System - new Message File updated to $root/FHEM/$messagefile");
|
||||
}
|
||||
}
|
||||
|
||||
$paref->{valid} = $valid;
|
||||
my $serial = encode_base64 (Serialize ( $paref ), ""); # Serialisierung
|
||||
|
||||
$block ? return ($serial) : return \&_processMessageFile ($serial);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
###############################################################
|
||||
# Folgeroutine nach Message File aus contrib abholen
|
||||
###############################################################
|
||||
sub _processMessageFile {
|
||||
my $serial = decode_base64 (shift);
|
||||
|
||||
my $paref = eval { thaw ($serial) }; # Deserialisierung
|
||||
my $name = $paref->{name};
|
||||
my $valid = $paref->{valid};
|
||||
my $hash = $defs{$name};
|
||||
|
||||
if ($valid) {
|
||||
__readFileMessages ($paref);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Messagefile für Notification System lesen
|
||||
# Filestruktur:
|
||||
# 0|SV|1
|
||||
# 0|DE|Mitteilung ....
|
||||
# 0|EN|Message...
|
||||
# $data{$name}{messages}{999000}{TS}: Timestamp Stand Message File
|
||||
######################################################################
|
||||
sub __readFileMessages {
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
|
||||
my $hash = $defs{$name};
|
||||
|
||||
open (FD, "$root/FHEM/$messagefile") or do { return $! };
|
||||
|
||||
delete $data{$name}{filemessages};
|
||||
|
||||
my @locList = map { $_ =~ s/[\r\n]//; $_ } <FD>;
|
||||
close (FD);
|
||||
|
||||
Log3 ($name, 4, "$name - Notification System - read local Message File >$messagefile< with ".scalar @locList." entries.");
|
||||
|
||||
for my $l (@locList) {
|
||||
next if ($l =~ /^\#/xs);
|
||||
my @l = split /\|/, $l, 3;
|
||||
next if(!isNumeric ($l[0]));
|
||||
next if($l[1] !~ /^(DE|EN|SV)$/xs);
|
||||
|
||||
$data{$name}{filemessages}{$l[0]}{$l[1]} = $l[2];
|
||||
}
|
||||
|
||||
$data{$name}{filemessages}{999000}{TS} = time;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
# Abbruchroutine BlockingCall Timeout
|
||||
####################################################################################################
|
||||
sub _abortGetMessageFile {
|
||||
my $hash = shift;
|
||||
my $cause = shift // "Timeout: process terminated";
|
||||
my $name = $hash->{NAME};
|
||||
my $type = $hash->{TYPE};
|
||||
|
||||
Log3 ($name, 1, "$name -> BlockingCall $hash->{HELPER}{GMFRUNNING}{fn} pid:$hash->{HELPER}{AIBLOCKRUNNING}{pid} aborted: $cause");
|
||||
|
||||
delete $hash->{HELPER}{GMFRUNNING};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# Mitteilungssystem füllen
|
||||
# Schweregrad SV:
|
||||
# 0 - keine Mitteilung
|
||||
# 1 - Mitteilung
|
||||
# 2 - Warnung
|
||||
# 3 - Fehler / Problem
|
||||
#
|
||||
# Statusspeicher:
|
||||
# $data{$name}{messages}{999999}{RD}: 1 - gelesen, 0 - ungelesen
|
||||
# $data{$name}{messages}{999000}{TS}: Timestamp Stand Message File
|
||||
# $data{$name}{messages}{999500}{TS}: Timestamp Stand prepared Messages
|
||||
##########################################################################
|
||||
sub fillupMessageSystem {
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
my $lang = $paref->{lang};
|
||||
|
||||
my $otxt = q{};
|
||||
my $ntxt = q{};
|
||||
my $midx = 0;
|
||||
my $max_sv = 0;
|
||||
|
||||
## Aufnahme Stand für alt/neu Vergleich + Clear Messages
|
||||
##########################################################
|
||||
for my $idx (sort keys %{$data{$name}{messages}}) {
|
||||
next if($idx >= $idxlimit);
|
||||
$otxt .= $data{$name}{messages}{$idx}{SV} if(defined $data{$name}{messages}{$idx}{SV});
|
||||
$otxt .= $data{$name}{messages}{$idx}{DE} if(defined $data{$name}{messages}{$idx}{DE});
|
||||
$otxt .= $data{$name}{messages}{$idx}{EN} if(defined $data{$name}{messages}{$idx}{EN});
|
||||
|
||||
delete $data{$name}{messages}{$idx};
|
||||
}
|
||||
|
||||
## Messages füllen
|
||||
########################################################################
|
||||
# Integration File Messages
|
||||
for my $mfi (sort keys %{$data{$name}{filemessages}}) {
|
||||
next if($mfi >= $idxlimit);
|
||||
$midx++;
|
||||
$data{$name}{messages}{$midx}{SV} = $data{$name}{filemessages}{$mfi}{SV};
|
||||
$data{$name}{messages}{$midx}{DE} = $data{$name}{filemessages}{$mfi}{DE};
|
||||
$data{$name}{messages}{$midx}{EN} = $data{$name}{filemessages}{$mfi}{EN};
|
||||
}
|
||||
|
||||
# Integration prepared Messages
|
||||
for my $smi (sort keys %{$data{$name}{preparedmessages}}) {
|
||||
next if($smi >= $idxlimit);
|
||||
$midx++;
|
||||
$data{$name}{messages}{$midx}{SV} = $data{$name}{preparedmessages}{$smi}{SV};
|
||||
$data{$name}{messages}{$midx}{DE} = $data{$name}{preparedmessages}{$smi}{DE};
|
||||
$data{$name}{messages}{$midx}{EN} = $data{$name}{preparedmessages}{$smi}{EN};
|
||||
}
|
||||
|
||||
$data{$name}{messages}{999000}{TS} = $data{$name}{filemessages}{999000}{TS} // 0;
|
||||
$data{$name}{messages}{999500}{TS} = $data{$name}{preparedmessages}{999500}{TS} // 0;
|
||||
|
||||
########################################################################
|
||||
## Ende Messages auffüllen
|
||||
|
||||
|
||||
## Vergleich auf geänderte Messages
|
||||
#####################################
|
||||
for my $idx (sort keys %{$data{$name}{messages}}) {
|
||||
next if($idx >= $idxlimit);
|
||||
$ntxt .= $data{$name}{messages}{$idx}{SV} if(defined $data{$name}{messages}{$idx}{SV});
|
||||
$ntxt .= $data{$name}{messages}{$idx}{DE} if(defined $data{$name}{messages}{$idx}{DE});
|
||||
$ntxt .= $data{$name}{messages}{$idx}{EN} if(defined $data{$name}{messages}{$idx}{EN});
|
||||
}
|
||||
|
||||
if ($ntxt ne $otxt) { # es gibt neue Post! bzw. Änderungen -> Read-Bit läschen
|
||||
delete $data{$name}{messages}{999999}{RD};
|
||||
}
|
||||
|
||||
|
||||
if ($midx && !defined $data{$name}{messages}{999999}{RD}) { # RD = Read-Bit (undef -> Messages nicht gelesen)
|
||||
my @aidx = map { $_ } (1..$midx); # größte vorhandene Severity finden ...
|
||||
my @values = map { $data{$name}{messages}{$_}{SV} } @aidx;
|
||||
$max_sv = max(@values);
|
||||
}
|
||||
|
||||
my $max_icon = $svicons{$max_sv}; # ... und das dazugehörige Icon
|
||||
|
||||
return ($max_icon, $midx);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Ausgabe des Mitteilungsystems
|
||||
################################################################
|
||||
sub outputMessages {
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
my $lang = $paref->{lang};
|
||||
|
||||
my ($micon, $midx) = fillupMessageSystem ($paref); # Ergebnisse füllen (sind leer wenn Browser nicht refreshed)
|
||||
my $tnf = $data{$name}{messages}{999000}{TS} ?
|
||||
(timestampToTimestring ($data{$name}{messages}{999000}{TS}, $lang))[0] :
|
||||
'n.a.';
|
||||
my $tpm = $data{$name}{messages}{999500}{TS} ?
|
||||
(timestampToTimestring ($data{$name}{messages}{999500}{TS}, $lang))[0] :
|
||||
'n.a.';
|
||||
## Ausgabe
|
||||
############
|
||||
my $out = qq{<html>};
|
||||
$out .= qq{<b>$hqtxt{msgsys}{$lang}</b> <br><br>};
|
||||
$out .= qq{$hqtxt{ludich}{$lang} - <b>File:</b> $tnf, <b>System:</b> $tpm <br>};
|
||||
$out .= qq{($hqtxt{dmgsig}{$lang}) <br><br>};
|
||||
|
||||
$out .= qq{<table class="roomoverview" style="text-align:left; border:1px solid; padding:5px; border-spacing:5px; margin-left:auto; margin-right:auto;">};
|
||||
$out .= qq{<tr style="font-weight:bold;">};
|
||||
$out .= qq{<td style="text-decoration:underline;"> Pos. </td>};
|
||||
$out .= qq{<td> </td>};
|
||||
$out .= qq{<td style="text-decoration:underline;"> $hqtxt{msgimp}{$lang} </td>};
|
||||
$out .= qq{<td> </td>};
|
||||
$out .= qq{<td style="text-decoration:underline;"> $hqtxt{simsg}{$lang} </td>};
|
||||
$out .= qq{</tr>};
|
||||
$out .= qq{<tr></tr>};
|
||||
|
||||
my $hc = 0;
|
||||
|
||||
for my $key (sort keys %{$data{$name}{messages}}) {
|
||||
next if($key >= $idxlimit);
|
||||
|
||||
$hc++;
|
||||
my $enmsg = encode ("utf8", $data{$name}{messages}{$key}{$lang});
|
||||
|
||||
$out .= qq{<tr>};
|
||||
$out .= qq{<td style="padding: 5px; text-align: center"> $key </td>};
|
||||
$out .= qq{<td style="padding: 5px;"> </td>};
|
||||
$out .= qq{<td style="padding: 5px; text-align: center"> $data{$name}{messages}{$key}{SV} </td>};
|
||||
$out .= qq{<td style="padding: 5px;"> </td>};
|
||||
$out .= qq{<td style="padding-right: 5px; text-align: left"> $enmsg </td>};
|
||||
$out .= qq{</tr>};
|
||||
|
||||
if ($hc < $midx) { # Zwischenzeile
|
||||
$out .= qq{<tr>};
|
||||
$out .= qq{<td> </td>};
|
||||
$out .= qq{</tr>};
|
||||
}
|
||||
}
|
||||
|
||||
$out .= qq{</table>};
|
||||
$out .= qq{</html>};
|
||||
|
||||
$out .= "<br>";
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
###############################################################
|
||||
# Eintritt in den KI Train Prozess normal/Blocking
|
||||
###############################################################
|
||||
@ -16688,7 +16927,6 @@ return;
|
||||
sub aiTrain { ## no critic "not used"
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
my $type = $paref->{type};
|
||||
my $block = $paref->{block} // 0;
|
||||
|
||||
my $hash = $defs{$name};
|
||||
@ -18188,63 +18426,6 @@ sub _writeAsCsv {
|
||||
return "The memory structure was written to the file $outfile";
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Ausgabe des Mitteilungsystems
|
||||
################################################################
|
||||
sub outputMessages {
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
my $lang = $paref->{lang};
|
||||
|
||||
my ($micon, $midx) = __fillupMessages ($paref); # Ergebnisse füllen (sind leer wenn Browser nicht refreshed)
|
||||
|
||||
## Ausgabe
|
||||
############
|
||||
my $out = qq{<html>};
|
||||
$out .= qq{<b>}.$hqtxt{msgsys}{$lang}.qq{</b> <br>};
|
||||
$out .= qq{<b>Hinweis:</b> Gelesene Mitteilungen werden bis zu einem FHEM Neustart nicht wieder signalisiert, bleiben jedoch bei Relevanz erhalten. <br><br>};
|
||||
|
||||
$out .= qq{<table class="roomoverview" style="text-align:left; border:1px solid; padding:5px; border-spacing:5px; margin-left:auto; margin-right:auto;">};
|
||||
$out .= qq{<tr style="font-weight:bold;">};
|
||||
$out .= qq{<td style="text-decoration:underline;"> $hqtxt{number}{$lang} </td>};
|
||||
$out .= qq{<td> </td>};
|
||||
$out .= qq{<td style="text-decoration:underline;"> $hqtxt{msgimp}{$lang} </td>};
|
||||
$out .= qq{<td> </td>};
|
||||
$out .= qq{<td style="text-decoration:underline;"> $hqtxt{simsg}{$lang} </td>};
|
||||
$out .= qq{</tr>};
|
||||
$out .= qq{<tr></tr>};
|
||||
|
||||
my $hc = 0;
|
||||
|
||||
for my $key (sort keys %{$data{$name}{messages}}) {
|
||||
next if($key == 9999);
|
||||
|
||||
$hc++;
|
||||
my $enmsg = encode ("utf8", $data{$name}{messages}{$key}{$lang});
|
||||
|
||||
$out .= qq{<tr>};
|
||||
$out .= qq{<td style="padding: 5px; text-align: center"> $key </td>};
|
||||
$out .= qq{<td style="padding: 5px;"> </td>};
|
||||
$out .= qq{<td style="padding: 5px; text-align: center"> $data{$name}{messages}{$key}{SV} </td>};
|
||||
$out .= qq{<td style="padding: 5px;"> </td>};
|
||||
$out .= qq{<td style="padding-right: 5px; text-align: left"> $enmsg </td>};
|
||||
$out .= qq{</tr>};
|
||||
|
||||
if ($hc < $midx) { # Zwischenzeile
|
||||
$out .= qq{<tr>};
|
||||
$out .= qq{<td> </td>};
|
||||
$out .= qq{</tr>};
|
||||
}
|
||||
}
|
||||
|
||||
$out .= qq{</table>};
|
||||
$out .= qq{</html>};
|
||||
|
||||
$out .= "<br>";
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# validiert die aktuelle Anlagenkonfiguration
|
||||
################################################################
|
||||
@ -18986,11 +19167,70 @@ sub medianArray {
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Berechnen Tag / Stunden Verschieber
|
||||
# aus aktueller Stunde + lfd. Nummer
|
||||
################################################################
|
||||
sub calcDayHourMove {
|
||||
my $chour = shift;
|
||||
my $num = shift;
|
||||
|
||||
my $fh = $chour + $num;
|
||||
my $fd = int ($fh / 24) ;
|
||||
$fh = $fh - ($fd * 24);
|
||||
|
||||
return ($fd, $fh);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Zeit gemäß DWD_OpenData-Format
|
||||
# Berechnen Tag / Stunden Verschieber ab aktuellen Tag
|
||||
# Input: YYYY-MM-DD HH:MM:SS
|
||||
# Output: $fd - 0 (Heute), 1 (Morgen), 2 (Übermorgen), ....
|
||||
# $fh - Stunde von $fd ohne führende Null
|
||||
# Return: fc${fd}_${fh}
|
||||
################################################################
|
||||
sub formatWeatherTimestrg {
|
||||
my $date = shift // return;
|
||||
|
||||
my $cdate = strftime "%Y-%m-%d", localtime(time);
|
||||
my $refts = timestringToTimestamp ($cdate.' 00:00:00'); # Referenztimestring
|
||||
my $datts = timestringToTimestamp ($date);
|
||||
my $fd = int (($datts - $refts) / 86400);
|
||||
my $fh = int ((split /[ :]/, $date)[1]);
|
||||
|
||||
return "fc${fd}_${fh}";
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Spezialfall auflösen wenn Wert von $val2 dem
|
||||
# Redingwert von $val1 entspricht sofern $val1 negativ ist
|
||||
################################################################
|
||||
sub substSpecialCases {
|
||||
my $paref = shift;
|
||||
my $dev = $paref->{dev};
|
||||
my $rdg = $paref->{rdg};
|
||||
my $rdgf = $paref->{rdgf};
|
||||
|
||||
my $val1 = ReadingsNum ($dev, $rdg, 0) * $rdgf;
|
||||
my $val2;
|
||||
|
||||
if($val1 <= 0) {
|
||||
$val2 = abs($val1);
|
||||
$val1 = 0;
|
||||
}
|
||||
else {
|
||||
$val2 = 0;
|
||||
}
|
||||
|
||||
return ($val1,$val2);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Timestrings berechnen
|
||||
# gibt Zeitstring in lokaler Zeit zurück
|
||||
################################################################
|
||||
sub timestampToTimestring {
|
||||
sub timestampToTimestring {
|
||||
my $epoch = shift;
|
||||
my $lang = shift // '';
|
||||
|
||||
@ -20027,7 +20267,7 @@ return $is;
|
||||
# reading: Device ist im Reading Value enthalten
|
||||
# attr: Device ist im Attr Value enthalten
|
||||
# string: Device ist im Objekt-Inhalt enthalten
|
||||
# return: $valid - ist die Angabe valide (1)
|
||||
# return: $err - evtl. Fehler
|
||||
# $a->[0] - das extrahierte Device
|
||||
# $h - Hash der geparsten Entität
|
||||
#####################################################################
|
||||
@ -20054,24 +20294,27 @@ sub isDeviceValid {
|
||||
}
|
||||
|
||||
my ($a, $h) = parseParams ($dev);
|
||||
|
||||
my ($dv, $al) = !$a->[0] ? ('', '') :
|
||||
$a->[0] =~ /:/xs ? (split ':', $a->[0]) :
|
||||
($a->[0], ''); # (optionalen) SF-spezifischen Alias abtrennen
|
||||
|
||||
if ($a->[0] && $a->[0] =~ /\@/xs ) { # Remote Device
|
||||
$a->[0] = (split '@', $a->[0])[0];
|
||||
return ($err, $a->[0], $h); # ToDo: $h aus remote Werten anreichern
|
||||
}
|
||||
|
||||
if (!$a->[0] || !$defs{$a->[0]}) {
|
||||
$a->[0] //= '';
|
||||
$err = qq{The device '$a->[0]' doesn't exist or is not a valid device.};
|
||||
$err = qq{There is no device set. Check the syntax with the command reference.} if(!$a->[0]);
|
||||
$err = qq{The device '$a->[0]' doesn't exist anymore! Delete or change the attribute '$obj'.} if(!$defs{$a->[0]} && $method eq 'attr' && $obj =~ /consumer/);
|
||||
if (!$dv || !$defs{$dv}) {
|
||||
$dv //= '';
|
||||
$err = qq{The device '$dv' doesn't exist or is not a valid device.};
|
||||
$err = qq{There is no device set. Check the syntax with the command reference.} if(!$dv);
|
||||
$err = qq{The device '$dv' doesn't exist anymore! Delete or change the attribute '$obj'.} if(!$defs{$dv} && $method eq 'attr' && $obj =~ /consumer/);
|
||||
}
|
||||
|
||||
if ($err) {
|
||||
Log3 ($name, 1, "$name - ERROR - $err");
|
||||
}
|
||||
|
||||
if ($al) { # Leerzeichen im SF-Alias generieren
|
||||
$al =~ s/\+/ /g;
|
||||
}
|
||||
|
||||
return ($err, $a->[0], $h);
|
||||
return ($err, $dv, $h, $al);
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
@ -22619,7 +22862,7 @@ to ensure that the system configuration is correct.
|
||||
<br>
|
||||
|
||||
<a id="SolarForecast-attr-consumer" data-pattern="consumer.*"></a>
|
||||
<li><b>consumerXX <Device Name> type=<type> power=<power> [switchdev=<device>]<br>
|
||||
<li><b>consumerXX <Device>[:<Alias>] type=<type> power=<power> [switchdev=<device>]<br>
|
||||
[mode=<mode>] [icon=<Icon>[@<Color>]] [mintime=<minutes> | SunPath[:<Offset_Sunrise>:<Offset_Sunset>]] <br>
|
||||
[on=<command>] [off=<command>] [swstate=<Readingname>:<on-Regex>:<off-Regex>] [asynchron=<Option>] <br>
|
||||
[notbefore=<Expression>] [notafter=<Expression>] [locktime=<offlt>[:<onlt>]] <br>
|
||||
@ -22628,8 +22871,8 @@ to ensure that the system configuration is correct.
|
||||
[surpmeth=<Option>] [interruptable=<Option>] [noshow=<Option>] [exconfc=<Option>] </b><br>
|
||||
<br>
|
||||
|
||||
Registers a consumer <Device Name> with the SolarForecast Device. In this case, <Device Name>
|
||||
is a consumer device already created in FHEM, e.g. a switchable socket.
|
||||
Registers a consumer <Device> with the SolarForecast Device. An optional alias can be specified. <br>
|
||||
In this case, <Device> is a consumer device already created in FHEM, e.g. a switchable socket.
|
||||
Most of the keys are optional, but are a prerequisite for certain functionalities and are filled with
|
||||
default values. <br>
|
||||
If the dish is defined "auto", the automatic mode in the integrated consumer graphic can be switched with the
|
||||
@ -22664,6 +22907,11 @@ to ensure that the system configuration is correct.
|
||||
<ul>
|
||||
<table>
|
||||
<colgroup> <col width="12%"> <col width="88%"> </colgroup>
|
||||
<tr><td> <b>Device</b> </td><td>Consumer device. In the simple case, the device works both as an energy meter and as a switch. </td></tr>
|
||||
<tr><td> </td><td>In the optional alias, spaces must be replaced by '+' (e.g. 'Ein+toller+Alias'). </td></tr>
|
||||
<tr><td> </td><td>If the consumer consists of different devices/channels (e.g. Homematic), the energy meter is defined as a <Device>. </td></tr>
|
||||
<tr><td> </td><td>The associated switching device is specified with the key 'switchdev'. </td></tr>
|
||||
<tr><td> </td><td> </td></tr>
|
||||
<tr><td> <b>type</b> </td><td>Type of consumer. The following types are allowed: </td></tr>
|
||||
<tr><td> </td><td><b>dishwasher</b> - Consumer is a dishwasher </td></tr>
|
||||
<tr><td> </td><td><b>dryer</b> - Consumer is a tumble dryer </td></tr>
|
||||
@ -25104,7 +25352,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
<br>
|
||||
|
||||
<a id="SolarForecast-attr-consumer" data-pattern="consumer.*"></a>
|
||||
<li><b>consumerXX <Device Name> type=<type> power=<power> [switchdev=<device>]<br>
|
||||
<li><b>consumerXX <Device>[:<Alias>] type=<type> power=<power> [switchdev=<device>]<br>
|
||||
[mode=<mode>] [icon=<Icon>[@<Farbe>]] [mintime=<minutes> | SunPath[:<Offset_Sunrise>:<Offset_Sunset>]] <br>
|
||||
[on=<Kommando>] [off=<Kommando>] [swstate=<Readingname>:<on-Regex>:<off-Regex>] [asynchron=<Option>] <br>
|
||||
[notbefore=<Ausdruck>] [notafter=<Ausdruck>] [locktime=<offlt>[:<onlt>]] <br>
|
||||
@ -25113,8 +25361,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
[surpmeth=<Option>] [interruptable=<Option>] [noshow=<Option>] [exconfc=<Option>] </b><br>
|
||||
<br>
|
||||
|
||||
Registriert einen Verbraucher <Device Name> beim SolarForecast Device. Dabei ist <Device Name>
|
||||
ein in FHEM bereits angelegtes Verbraucher Device, z.B. eine Schaltsteckdose.
|
||||
Registriert einen Verbraucher <Device> beim SolarForecast Device. Ein optionaler Alias kann angegeben werden. <br>
|
||||
Dabei ist <Device> ein in FHEM bereits angelegtes Verbraucher Device, z.B. eine Schaltsteckdose.
|
||||
Die meisten Schlüssel sind optional, sind aber für bestimmte Funktionalitäten Voraussetzung und werden mit
|
||||
default-Werten besetzt. <br>
|
||||
Ist der Schüssel "auto" definiert, kann der Automatikmodus in der integrierten Verbrauchergrafik mit den
|
||||
@ -25148,6 +25396,11 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
|
||||
<ul>
|
||||
<table>
|
||||
<colgroup> <col width="12%"> <col width="88%"> </colgroup>
|
||||
<tr><td> <b>Device</b> </td><td>Verbraucher-Gerät. Im einfachen Fall arbeitet das Gerät sowohl als Energiemesser als auch als Schalter. </td></tr>
|
||||
<tr><td> </td><td>Im optionalen Alias sind Leerzeichen durch '+' zu ersetzen (z.B. 'Ein+toller+Alias'). </td></tr>
|
||||
<tr><td> </td><td>Besteht der Verbraucher aus verschiedenen Geräten/Kanäalen (z.B. Homematic), wird der Energiemesser als <Device> definiert. </td></tr>
|
||||
<tr><td> </td><td>Das dazugehörige Schalt-Gerät wird mit dem Schlüssel 'switchdev' spezifiziert. </td></tr>
|
||||
<tr><td> </td><td> </td></tr>
|
||||
<tr><td> <b>type</b> </td><td>Typ des Verbrauchers. Folgende Typen sind erlaubt: </td></tr>
|
||||
<tr><td> </td><td><b>dishwasher</b> - Verbraucher ist eine Spülmaschine </td></tr>
|
||||
<tr><td> </td><td><b>dryer</b> - Verbraucher ist ein Wäschetrockner </td></tr>
|
||||
|
Loading…
Reference in New Issue
Block a user