event-min-interval
FBAHA/FBDECT git-svn-id: https://fhem.svn.sourceforge.net/svnroot/fhem/trunk/fhem@2835 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
2
CHANGED
2
CHANGED
@@ -92,6 +92,8 @@
|
|||||||
added, Extend devStateIcon, js setting of attr values in detail
|
added, Extend devStateIcon, js setting of attr values in detail
|
||||||
screen, live slider update in detail and room view
|
screen, live slider update in detail and room view
|
||||||
- feature: added support for third-party packages to 98_update.pm (M. Fischer)
|
- feature: added support for third-party packages to 98_update.pm (M. Fischer)
|
||||||
|
- feature: FBAHA/FBDECT for FRITZ!DECT devices
|
||||||
|
- feature: event-min-interval Attribute
|
||||||
|
|
||||||
- 2012-10-28 (5.3)
|
- 2012-10-28 (5.3)
|
||||||
- feature: added functions trim, ltrim, rtrim, UntoggleDirect,
|
- feature: added functions trim, ltrim, rtrim, UntoggleDirect,
|
||||||
|
|||||||
446
FHEM/00_FBAHA.pm
Executable file
446
FHEM/00_FBAHA.pm
Executable file
@@ -0,0 +1,446 @@
|
|||||||
|
##############################################
|
||||||
|
# $Id: 00_FBAHA.pm 2777 2013-02-20 08:02:01Z rudolfkoenig $
|
||||||
|
package main;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Time::HiRes qw(gettimeofday);
|
||||||
|
|
||||||
|
sub FBAHA_Read($@);
|
||||||
|
sub FBAHA_Write($$$);
|
||||||
|
sub FBAHA_ReadAnswer($$$);
|
||||||
|
sub FBAHA_Ready($);
|
||||||
|
|
||||||
|
sub FBAHA_getDevList($$);
|
||||||
|
|
||||||
|
|
||||||
|
sub
|
||||||
|
FBAHA_Initialize($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
require "$attr{global}{modpath}/FHEM/DevIo.pm";
|
||||||
|
|
||||||
|
# Provider
|
||||||
|
$hash->{ReadFn} = "FBAHA_Read";
|
||||||
|
$hash->{WriteFn} = "FBAHA_Write";
|
||||||
|
$hash->{ReadyFn} = "FBAHA_Ready";
|
||||||
|
$hash->{UndefFn} = "FBAHA_Undef";
|
||||||
|
$hash->{ShutdownFn} = "FBAHA_Undef";
|
||||||
|
$hash->{ReadAnswerFn} = "FBAHA_ReadAnswer";
|
||||||
|
|
||||||
|
# Normal devices
|
||||||
|
$hash->{DefFn} = "FBAHA_Define";
|
||||||
|
$hash->{GetFn} = "FBAHA_Get";
|
||||||
|
$hash->{SetFn} = "FBAHA_Set";
|
||||||
|
$hash->{AttrList}= "dummy:1,0 loglevel:0,1,2,3,4,5,6 ";
|
||||||
|
}
|
||||||
|
|
||||||
|
my %gets = ("devList"=>1);
|
||||||
|
my %sets = ("createDevs"=>1);
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
FBAHA_Define($$)
|
||||||
|
{
|
||||||
|
my ($hash, $def) = @_;
|
||||||
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
|
|
||||||
|
if(@a != 3) {
|
||||||
|
return "wrong syntax: define <name> FBAHA hostname:2002";
|
||||||
|
}
|
||||||
|
|
||||||
|
DevIo_CloseDev($hash);
|
||||||
|
|
||||||
|
my $name = $a[0];
|
||||||
|
my $dev = $a[2];
|
||||||
|
|
||||||
|
$hash->{Clients} = ":FBDECT:";
|
||||||
|
my %matchList = ( "1:FBDECT" => ".*" );
|
||||||
|
$hash->{MatchList} = \%matchList;
|
||||||
|
|
||||||
|
$hash->{DeviceName} = $dev;
|
||||||
|
my $ret = DevIo_OpenDev($hash, 0, "FBAHA_DoInit");
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
FBAHA_Set($@)
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
my $name = shift @a;
|
||||||
|
|
||||||
|
return "set $name needs at least one parameter" if(@a < 1);
|
||||||
|
my $type = shift @a;
|
||||||
|
|
||||||
|
return "Unknown argument $type, choose one of " . join(" ", sort keys %sets)
|
||||||
|
if(!defined($sets{$type}));
|
||||||
|
|
||||||
|
if($type eq "createDevs") {
|
||||||
|
my @arg = FBAHA_getDevList($hash,0);
|
||||||
|
foreach my $arg (@arg) {
|
||||||
|
if($arg =~ m/ID:(\d+).*PROP:(.*)/) {
|
||||||
|
my ($i,$p) = ($1,$2,$3);
|
||||||
|
Log 1, "UNDEFINED FBDECT_$i FBDECT $i $p";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
FBAHA_Get($@)
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
my $name = shift @a;
|
||||||
|
|
||||||
|
return "get $name needs at least one parameter" if(@a < 1);
|
||||||
|
my $type = shift @a;
|
||||||
|
|
||||||
|
return "Unknown argument $type, choose one of ". join(" ", sort keys %gets)
|
||||||
|
if(!defined($gets{$type}));
|
||||||
|
|
||||||
|
if($type eq "devList") {
|
||||||
|
return join("\n", FBAHA_getDevList($hash,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FBAHA_getDevList($$)
|
||||||
|
{
|
||||||
|
my ($hash, $onlyId) = @_;
|
||||||
|
|
||||||
|
FBAHA_Write($hash, "05", "00000000"); # CONFIG_REQ
|
||||||
|
my ($err, $data) = FBAHA_ReadAnswer($hash, "CONFIG_RSP", "^06");
|
||||||
|
return ($err) if($err);
|
||||||
|
|
||||||
|
$data = substr($data, 32); # Header
|
||||||
|
return FBAHA_configInd($data, $onlyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FBAHA_configInd($$)
|
||||||
|
{
|
||||||
|
my ($data, $onlyId) = @_;
|
||||||
|
|
||||||
|
|
||||||
|
my @answer;
|
||||||
|
while(length($data) >= 288) {
|
||||||
|
my $id = hex(substr($data, 0, 4));
|
||||||
|
my $act = hex(substr($data, 4, 2));
|
||||||
|
my $typ = hex(substr($data, 8, 4));
|
||||||
|
my $lsn = hex(substr($data, 16, 8));
|
||||||
|
my $nam = pack("H*",substr($data,24,160)); $nam =~ s/\x0//g;
|
||||||
|
|
||||||
|
$act = ($act == 2 ? "active" : ($act == 1 ? "inactive" : "removed"));
|
||||||
|
|
||||||
|
my %tl = ( 2=>"AVM FRITZ!Dect Powerline 546E", 9=>"AVM FRITZ!Dect 200");
|
||||||
|
$typ = $tl{$typ} ? $tl{$typ} : "unknown($typ)";
|
||||||
|
|
||||||
|
my %ll = (7=>"powerMeter",9=>"switch");
|
||||||
|
$lsn = join ",", map { $ll{$_} if((1 << $_) & $lsn) } sort keys %ll;
|
||||||
|
|
||||||
|
my $dlen = hex(substr($data, 280, 8))*2; # DATA MSG
|
||||||
|
|
||||||
|
push @answer, "NAME:$nam, ID:$id, $act, TYPE:$typ PROP:$lsn"
|
||||||
|
if(!$onlyId || $onlyId == $id);
|
||||||
|
|
||||||
|
if($onlyId && $onlyId == $id) {
|
||||||
|
my $mnf = hex(substr($data,184, 4)); # empty/0
|
||||||
|
my $idf = substr($data,192,40); # empty/0
|
||||||
|
my $frm = substr($data,232,40); # empty/0
|
||||||
|
push @answer, " MANUF:$mnf";
|
||||||
|
push @answer, " UniqueID:$idf";
|
||||||
|
push @answer, " Firmware:$frm";
|
||||||
|
push @answer, substr($data, 288, $dlen);
|
||||||
|
return @answer;
|
||||||
|
}
|
||||||
|
$data = substr($data, 288+$dlen); # rest
|
||||||
|
}
|
||||||
|
return @answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
FBAHA_DoInit($)
|
||||||
|
{
|
||||||
|
my $hash = shift;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
Log 1, "FBAHA_DoInit called";
|
||||||
|
|
||||||
|
FBAHA_Write($hash, "00", "00010001");
|
||||||
|
my ($err, $data) = FBAHA_ReadAnswer($hash, "REGISTER", "^01");
|
||||||
|
if($err) {
|
||||||
|
Log 1, $err;
|
||||||
|
$hash->{STATE} = "???";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($data =~ m/^01030010(........)/) {
|
||||||
|
$hash->{STATE} = "Initialized";
|
||||||
|
$hash->{HANDLE} = $1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log 1, "Got bogus answer for REGISTER request: $data";
|
||||||
|
$hash->{STATE} = "???";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FBAHA_Write($hash, "03", "0000028200000000"); # LISTEN
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
FBAHA_Undef($@)
|
||||||
|
{
|
||||||
|
my ($hash, $arg) = @_;
|
||||||
|
FBAHA_Write($hash, "02", ""); # RELEASE
|
||||||
|
DevIo_CloseDev($hash);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
FBAHA_Write($$$)
|
||||||
|
{
|
||||||
|
my ($hash,$fn,$msg) = @_;
|
||||||
|
|
||||||
|
$msg = sprintf("%s03%04x%s%s", $fn, length($msg)/2+8,
|
||||||
|
$hash->{HANDLE} ? $hash->{HANDLE} : "00000000", $msg);
|
||||||
|
DevIo_SimpleWrite($hash, $msg, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# called from the global loop, when the select for hash->{FD} reports data
|
||||||
|
sub
|
||||||
|
FBAHA_Read($@)
|
||||||
|
{
|
||||||
|
my ($hash, $local, $regexp) = @_;
|
||||||
|
|
||||||
|
my $buf = ($local ? $local : DevIo_SimpleRead($hash));
|
||||||
|
return "" if(!defined($buf));
|
||||||
|
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my $ll5 = GetLogLevel($name,5);
|
||||||
|
|
||||||
|
$buf = unpack('H*', $buf);
|
||||||
|
my $data = ($hash->{PARTIAL} ? $hash->{PARTIAL} : "");
|
||||||
|
|
||||||
|
# drop old data
|
||||||
|
if($data) {
|
||||||
|
$data = "" if(gettimeofday() - $hash->{READ_TS} > 1);
|
||||||
|
delete($hash->{READ_TS});
|
||||||
|
}
|
||||||
|
|
||||||
|
Log $ll5, "FBAHA/RAW: $data/$buf";
|
||||||
|
$data .= $buf;
|
||||||
|
|
||||||
|
my $msg;
|
||||||
|
while(length($data) >= 16) {
|
||||||
|
my $len = hex(substr($data, 4,4))*2;
|
||||||
|
last if($len > length($data));
|
||||||
|
$msg = substr($data, 0, $len);
|
||||||
|
$data = substr($data, $len);
|
||||||
|
last if(defined($local) && (!defined($regexp) || ($msg =~ m/$regexp/)));
|
||||||
|
|
||||||
|
$hash->{"${name}_MSGCNT"}++;
|
||||||
|
$hash->{"${name}_TIME"} = TimeNow();
|
||||||
|
$hash->{RAWMSG} = $msg;
|
||||||
|
my %addvals = (RAWMSG => $msg);
|
||||||
|
Dispatch($hash, $msg, \%addvals) if($init_done);
|
||||||
|
$msg = undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash->{PARTIAL} = $data;
|
||||||
|
$hash->{READ_TS} = gettimeofday() if($data);
|
||||||
|
return $msg if(defined($local));
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# This is a direct read for commands like get
|
||||||
|
sub
|
||||||
|
FBAHA_ReadAnswer($$$)
|
||||||
|
{
|
||||||
|
my ($hash, $arg, $regexp) = @_;
|
||||||
|
return ("No FD (dummy device?)", undef)
|
||||||
|
if(!$hash || ($^O !~ /Win/ && !defined($hash->{FD})));
|
||||||
|
my $to = ($hash->{RA_Timeout} ? $hash->{RA_Timeout} : 3);
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
return ("Device lost when reading answer for get $arg", undef)
|
||||||
|
if(!$hash->{FD});
|
||||||
|
my $rin = '';
|
||||||
|
vec($rin, $hash->{FD}, 1) = 1;
|
||||||
|
my $nfound = select($rin, undef, undef, $to);
|
||||||
|
if($nfound < 0) {
|
||||||
|
next if ($! == EAGAIN() || $! == EINTR() || $! == 0);
|
||||||
|
my $err = $!;
|
||||||
|
DevIo_Disconnected($hash);
|
||||||
|
return("FBAHA_ReadAnswer $arg: $err", undef);
|
||||||
|
}
|
||||||
|
return ("Timeout reading answer for get $arg", undef)
|
||||||
|
if($nfound == 0);
|
||||||
|
my $buf = DevIo_SimpleRead($hash);
|
||||||
|
return ("No data", undef) if(!defined($buf));
|
||||||
|
|
||||||
|
my $ret = FBAHA_Read($hash, $buf, $regexp);
|
||||||
|
return (undef, $ret) if(defined($ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
FBAHA_Ready($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
return DevIo_OpenDev($hash, 1, "FBAHA_DoInit")
|
||||||
|
if($hash->{STATE} eq "disconnected");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
=begin html
|
||||||
|
|
||||||
|
<a name="FBAHA"></a>
|
||||||
|
<h3>FBAHA</h3>
|
||||||
|
<ul>
|
||||||
|
<b>NOTE:</b> As of FRITZ!OS 5.50 this module is known to work on the FB7390,
|
||||||
|
and is known to <b>crash the FB7270</b>.<br><br>
|
||||||
|
|
||||||
|
This module connects to the AHA server (AVM Home Automation) on a FRITZ!Box.
|
||||||
|
It serves as the "physical" counterpart to the <a href="#FBDECT">FBDECT</a>
|
||||||
|
devices.
|
||||||
|
<br><br>
|
||||||
|
<a name="FBAHAdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> FBAHA <host>:<port></code>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<host> is normally the address of the FRITZ!Box running the AHA server
|
||||||
|
(fritz.box or localhost), and :<port> is 2002.
|
||||||
|
<br>
|
||||||
|
Example:
|
||||||
|
<ul>
|
||||||
|
<code>define fb1 FBAHA fritz.box:2002</code><br>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBAHAset"></a>
|
||||||
|
<b>Set</b>
|
||||||
|
<ul>
|
||||||
|
<li>createDevs<br>
|
||||||
|
create a FHEM device for each DECT device found on the AHA-Host, see also
|
||||||
|
get devList.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBAHAget"></a>
|
||||||
|
<b>Get</b>
|
||||||
|
<ul>
|
||||||
|
<li>devList<br>
|
||||||
|
return a list of devices with short info.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBAHAattr"></a>
|
||||||
|
<b>Attributes</b>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#dummy">dummy</a></li>
|
||||||
|
<li><a href="#loglevel">loglevel</a></li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBAHAevents"></a>
|
||||||
|
<b>Generated events:</b>
|
||||||
|
<ul>
|
||||||
|
<li>UNDEFINED FBDECT_$ahaName_${NR} FBDECT $id"
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
=end html
|
||||||
|
|
||||||
|
=begin html_DE
|
||||||
|
|
||||||
|
<a name="FBAHA"></a>
|
||||||
|
<h3>FBAHA</h3>
|
||||||
|
<ul>
|
||||||
|
<b>Achtung:</b> Es ist bekannt, daß dieses Modul mit FRITZ!OS 5.50 auf
|
||||||
|
einem FB7390 funktioniert, aber <b>den FB7270 zum Absurz bringt</b>.<br><br>
|
||||||
|
|
||||||
|
Dieses Modul verbindet sich mit dem AHA (AVM Home Automation) Server auf
|
||||||
|
einem FRITZ!Box. Es dient als "physikalisches" Gegenstück zum <a
|
||||||
|
href="#FBDECT">FBDECT</a> Modul.
|
||||||
|
<br><br>
|
||||||
|
<a name="FBAHAdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> FBAHA <host>:<port></code>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<host> ist normalerweise die Adresse der FRITZ!Box, wo das AHA Server
|
||||||
|
läuft (fritz.box oder localhost), <port> ist 2002.
|
||||||
|
<br>
|
||||||
|
Beispiel:
|
||||||
|
<ul>
|
||||||
|
<code>define fb1 FBAHA fritz.box:2002</code><br>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBAHAset"></a>
|
||||||
|
<b>Set</b>
|
||||||
|
<ul>
|
||||||
|
<li>createDevs<br>
|
||||||
|
legt FHEM Geräte an für jedes auf dem AHA-Server gefundenen DECT
|
||||||
|
Eintrag, siehe auch "get devList".
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBAHAget"></a>
|
||||||
|
<b>Get</b>
|
||||||
|
<ul>
|
||||||
|
<li>devList<br>
|
||||||
|
liefert die Liste aller DECT-Einträge der AHA Server zurück, mit
|
||||||
|
einem kurzen Info.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBAHAattr"></a>
|
||||||
|
<b>Attributes</b>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#dummy">dummy</a></li>
|
||||||
|
<li><a href="#loglevel">loglevel</a></li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBAHAevents"></a>
|
||||||
|
<b>Generierte Events:</b>
|
||||||
|
<ul>
|
||||||
|
<li>UNDEFINED FBDECT_$ahaName_${NR} FBDECT $id"
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
=end html_DE
|
||||||
|
|
||||||
|
=cut
|
||||||
354
FHEM/10_FBDECT.pm
Executable file
354
FHEM/10_FBDECT.pm
Executable file
@@ -0,0 +1,354 @@
|
|||||||
|
##############################################
|
||||||
|
# $Id: 10_FBDECT.pm 2779 2013-02-21 08:52:27Z rudolfkoenig $
|
||||||
|
package main;
|
||||||
|
|
||||||
|
# TODO: test multi-dev, test on the FB
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use SetExtensions;
|
||||||
|
|
||||||
|
sub FBDECT_Parse($$@);
|
||||||
|
sub FBDECT_Set($@);
|
||||||
|
sub FBDECT_Get($@);
|
||||||
|
sub FBDECT_Cmd($$@);
|
||||||
|
|
||||||
|
my @fbdect_models = qw(
|
||||||
|
"AVM FRITZ!Dect Powerline 546E"
|
||||||
|
"AVM FRITZ!Dect 200"
|
||||||
|
);
|
||||||
|
|
||||||
|
my %fbdect_payload = (
|
||||||
|
7 => { n=>"connected" },
|
||||||
|
8 => { n=>"disconnected" },
|
||||||
|
10 => { n=>"configChanged" },
|
||||||
|
15 => { n=>"state", fmt=>'hex($pyld)?"on":"off"' },
|
||||||
|
18 => { n=>"current", fmt=>'sprintf("%0.4f A", hex($pyld)/10000)' },
|
||||||
|
19 => { n=>"voltage", fmt=>'sprintf("%0.3f V", hex($pyld)/1000)' },
|
||||||
|
20 => { n=>"power", fmt=>'sprintf("%0.2f W", hex($pyld)/100)' },
|
||||||
|
21 => { n=>"energy", fmt=>'sprintf("%0.0f Wh",hex($pyld))' },
|
||||||
|
22 => { n=>"powerFactor", fmt=>'sprintf("%0.3f", hex($pyld))' },
|
||||||
|
23 => { n=>"temperature", fmt=>'sprintf("%0.1f C", hex($pyld)/10)' },
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
sub
|
||||||
|
FBDECT_Initialize($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
$hash->{Match} = ".*";
|
||||||
|
$hash->{SetFn} = "FBDECT_Set";
|
||||||
|
$hash->{GetFn} = "FBDECT_Get";
|
||||||
|
$hash->{DefFn} = "FBDECT_Define";
|
||||||
|
$hash->{UndefFn} = "FBDECT_Undef";
|
||||||
|
$hash->{ParseFn} = "FBDECT_Parse";
|
||||||
|
$hash->{AttrList} =
|
||||||
|
"IODev do_not_notify:1,0 ignore:1,0 dummy:1,0 showtime:1,0 ".
|
||||||
|
"loglevel:0,1,2,3,4,5,6 $readingFnAttributes " .
|
||||||
|
"model:".join(",", sort @fbdect_models);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#############################
|
||||||
|
sub
|
||||||
|
FBDECT_Define($$)
|
||||||
|
{
|
||||||
|
my ($hash, $def) = @_;
|
||||||
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
|
my $name = shift @a;
|
||||||
|
my $type = shift(@a); # always FBDECT
|
||||||
|
|
||||||
|
my $u = "wrong syntax for $name: define <name> FBDECT id props";
|
||||||
|
return $u if(int(@a) != 2);
|
||||||
|
|
||||||
|
my $id = shift @a;
|
||||||
|
return "define $name: wrong id ($id): need a number"
|
||||||
|
if( $id !~ m/^\d+$/i );
|
||||||
|
$hash->{id} = $id;
|
||||||
|
$hash->{props} = shift @a;
|
||||||
|
|
||||||
|
$modules{FBDECT}{defptr}{$id} = $hash;
|
||||||
|
AssignIoPort($hash);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
###################################
|
||||||
|
my %sets = ("on"=>1, "off"=>1);
|
||||||
|
sub
|
||||||
|
FBDECT_Set($@)
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
my $ret = undef;
|
||||||
|
my $cmd = $a[1];
|
||||||
|
|
||||||
|
if(!$sets{$cmd}) {
|
||||||
|
return SetExtensions($hash, join(" ", sort keys %sets), @a);
|
||||||
|
}
|
||||||
|
my $relay = sprintf("%08x%04x0000%08x", 15, 4, $cmd eq "on" ? 1 : 0);
|
||||||
|
my $msg = sprintf("%04x0000%08x$relay", $hash->{id}, length($relay)/2);
|
||||||
|
IOWrite($hash, "07", $msg);
|
||||||
|
readingsSingleUpdate($hash, "state", "set_$cmd", 1);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
my %gets = ("devInfo"=>1);
|
||||||
|
sub
|
||||||
|
FBDECT_Get($@)
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
my $ret = undef;
|
||||||
|
my $cmd = ($a[1] ? $a[1] : "");
|
||||||
|
|
||||||
|
if(!$gets{$cmd}) {
|
||||||
|
return "Unknown argument $cmd, choose one of ".join(" ", sort keys %gets);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($cmd eq "devInfo") {
|
||||||
|
my @answ = FBAHA_getDevList($hash->{IODev}, $hash->{id});
|
||||||
|
return $answ[0] if(@answ == 1);
|
||||||
|
my $d = pop @answ;
|
||||||
|
while($d) {
|
||||||
|
my ($ptyp, $plen, $pyld) = FBDECT_decodePayload($d);
|
||||||
|
push @answ, " $ptyp: $pyld";
|
||||||
|
$d = substr($d, 16+$plen*2);
|
||||||
|
}
|
||||||
|
return join("\n", @answ);
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
###################################
|
||||||
|
sub
|
||||||
|
FBDECT_Parse($$@)
|
||||||
|
{
|
||||||
|
my ($iodev, $msg, $local) = @_;
|
||||||
|
my $ioName = $iodev->{NAME};
|
||||||
|
my $ll4 = AttrVal($ioName, "loglevel", 4);
|
||||||
|
|
||||||
|
my $mt = substr($msg, 0, 2);
|
||||||
|
if($mt ne "07" && $mt ne "04") {
|
||||||
|
Log 1, "FBDECT: unknown message type $mt";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $id = hex(substr($msg, 16, 4));
|
||||||
|
my $hash = $modules{FBDECT}{defptr}{$id};
|
||||||
|
if(!$hash) {
|
||||||
|
my $ret = "UNDEFINED FBDECT_$id FBDECT $id switch";
|
||||||
|
Log 1, $ret;
|
||||||
|
DoTrigger("global", $ret);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
readingsBeginUpdate($hash);
|
||||||
|
|
||||||
|
if($mt eq "07") {
|
||||||
|
my $d = substr($msg, 32);
|
||||||
|
while($d) {
|
||||||
|
my ($ptyp, $plen, $pyld) = FBDECT_decodePayload($d);
|
||||||
|
readingsBulkUpdate($hash, $ptyp, $pyld);
|
||||||
|
$d = substr($d, 16+$plen*2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($mt eq "04") {
|
||||||
|
my @answ = FBAHA_configInd(substr($msg,16), $id);
|
||||||
|
my $d = pop @answ;
|
||||||
|
while($d) {
|
||||||
|
my ($ptyp, $plen, $pyld) = FBDECT_decodePayload($d);
|
||||||
|
last if(!$plen);
|
||||||
|
push @answ, " $ptyp: $pyld";
|
||||||
|
$d = substr($d, 16+$plen*2);
|
||||||
|
}
|
||||||
|
# Ignore the rest, is too confusing.
|
||||||
|
@answ = grep /state:/, @answ;
|
||||||
|
my ($undef, $state) = split(": ", $answ[0], 2);
|
||||||
|
readingsBulkUpdate($hash, "state", $state) if($state);
|
||||||
|
Log 1, join("\n", @answ);
|
||||||
|
}
|
||||||
|
|
||||||
|
readingsEndUpdate($hash, 1);
|
||||||
|
|
||||||
|
return $hash->{NAME};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FBDECT_decodePayload($)
|
||||||
|
{
|
||||||
|
my ($d) = @_;
|
||||||
|
my $ptyp = hex(substr($d, 0, 8));
|
||||||
|
my $plen = hex(substr($d, 8, 4));
|
||||||
|
my $pyld = substr($d, 16, $plen*2);
|
||||||
|
if($fbdect_payload{$ptyp}) {
|
||||||
|
$pyld = eval $fbdect_payload{$ptyp}{fmt} if($fbdect_payload{$ptyp}{fmt});
|
||||||
|
$ptyp = $fbdect_payload{$ptyp}{n};
|
||||||
|
}
|
||||||
|
return ($ptyp, $plen, $pyld);
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
FBDECT_Undef($$)
|
||||||
|
{
|
||||||
|
my ($hash, $arg) = @_;
|
||||||
|
my $homeId = $hash->{homeId};
|
||||||
|
my $id = $hash->{id};
|
||||||
|
delete $modules{FBDECT}{defptr}{$id};
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
=begin html
|
||||||
|
|
||||||
|
<a name="FBDECT"></a>
|
||||||
|
<h3>FBDECT</h3>
|
||||||
|
<ul>
|
||||||
|
This module is used to control AVM FRITZ!DECT devices via FHEM, see also the
|
||||||
|
<a href="#FBAHA">FBAHA</a> module for the base.
|
||||||
|
<br><br>
|
||||||
|
<a name="FBDECTdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> FBDECT <homeId> <id> [classes]</code>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<id> is the id of the device, the classes argument ist ignored for now.
|
||||||
|
<br>
|
||||||
|
Example:
|
||||||
|
<ul>
|
||||||
|
<code>define lamp FBDECT 16 switch,powerMeter</code><br>
|
||||||
|
</ul>
|
||||||
|
<b>Note:</b>Usually the device is created via
|
||||||
|
<a href="#autocreate">autocreate</a>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<br
|
||||||
|
|
||||||
|
<a name="FBDECTset"></a>
|
||||||
|
<b>Set</b>
|
||||||
|
<ul>
|
||||||
|
<li>on/off<br>
|
||||||
|
set the device on or off.</li>
|
||||||
|
<li>
|
||||||
|
<a href="#setExtensions">set extensions</a> are supported.</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBDECTget"></a>
|
||||||
|
<b>Get</b>
|
||||||
|
<ul>
|
||||||
|
<li>devInfo<br>
|
||||||
|
report device information</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBDECTattr"></a>
|
||||||
|
<b>Attributes</b>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#IODev">IODev</a></li>
|
||||||
|
<li><a href="#do_not_notify">do_not_notify</a></li>
|
||||||
|
<li><a href="#ignore">ignore</a></li>
|
||||||
|
<li><a href="#dummy">dummy</a></li>
|
||||||
|
<li><a href="#showtime">showtime</a></li>
|
||||||
|
<li><a href="#loglevel">loglevel</a></li>
|
||||||
|
<li><a href="#model">model</a></li>
|
||||||
|
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBDECTevents"></a>
|
||||||
|
<b>Generated events:</b>
|
||||||
|
<ul>
|
||||||
|
<li>on</li>
|
||||||
|
<li>off</li>
|
||||||
|
<li>set_on</li>
|
||||||
|
<li>set_off</li>
|
||||||
|
<li>current: $v A</li>
|
||||||
|
<li>voltage: $v V</li>
|
||||||
|
<li>power: $v W</li>
|
||||||
|
<li>energy: $v Wh</li>
|
||||||
|
<li>powerFactor: $v"</li>
|
||||||
|
<li>temperature: $v C</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
=end html
|
||||||
|
|
||||||
|
=begin html_DE
|
||||||
|
|
||||||
|
<a name="FBDECT"></a>
|
||||||
|
<h3>FBDECT</h3>
|
||||||
|
<ul>
|
||||||
|
Dieses Modul wird verwendet, um AVM FRITZ!DECT Geräte via FHEM zu
|
||||||
|
steuern, siehe auch das <a href="#FBAHA">FBAHA</a> Modul für die
|
||||||
|
Anbindung an das FRITZ!Box.
|
||||||
|
<br><br>
|
||||||
|
<a name="FBDECTdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> FBDECT <homeId> <id> [classes]</code>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<id> ist das Geräte-ID, das Argument wird z.Zt ignoriert.
|
||||||
|
<br>
|
||||||
|
Beispiel:
|
||||||
|
<ul>
|
||||||
|
<code>define lampe FBDECT 16 switch,powerMeter</code><br>
|
||||||
|
</ul>
|
||||||
|
<b>Achtung:</b>FBDECT Einträge werden noralerweise per
|
||||||
|
<a href="#autocreate">autocreate</a> angelegt.
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<br
|
||||||
|
|
||||||
|
<a name="FBDECTset"></a>
|
||||||
|
<b>Set</b>
|
||||||
|
<ul>
|
||||||
|
<li>on/off<br>
|
||||||
|
Gerät einschalten bzw. ausschalten.</li>
|
||||||
|
<li>
|
||||||
|
Die <a href="#setExtensions">set extensions</a> werden unterstützt.</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBDECTget"></a>
|
||||||
|
<b>Get</b>
|
||||||
|
<ul>
|
||||||
|
<li>devInfo<br>
|
||||||
|
meldet Geräte-Informationen.</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBDECTattr"></a>
|
||||||
|
<b>Attribute</b>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#IODev">IODev</a></li>
|
||||||
|
<li><a href="#do_not_notify">do_not_notify</a></li>
|
||||||
|
<li><a href="#ignore">ignore</a></li>
|
||||||
|
<li><a href="#dummy">dummy</a></li>
|
||||||
|
<li><a href="#showtime">showtime</a></li>
|
||||||
|
<li><a href="#loglevel">loglevel</a></li>
|
||||||
|
<li><a href="#model">model</a></li>
|
||||||
|
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="FBDECTevents"></a>
|
||||||
|
<b>Generierte events:</b>
|
||||||
|
<ul>
|
||||||
|
<li>on</li>
|
||||||
|
<li>off</li>
|
||||||
|
<li>set_on</li>
|
||||||
|
<li>set_off</li>
|
||||||
|
<li>current: $v A</li>
|
||||||
|
<li>voltage: $v V</li>
|
||||||
|
<li>power: $v W</li>
|
||||||
|
<li>energy: $v Wh</li>
|
||||||
|
<li>powerFactor: $v"</li>
|
||||||
|
<li>temperature: $v C</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
=end html_DE
|
||||||
|
|
||||||
|
=cut
|
||||||
@@ -76,6 +76,10 @@ my %flogpar = (
|
|||||||
# Lacrosse TX
|
# Lacrosse TX
|
||||||
"CUL_TX.*"
|
"CUL_TX.*"
|
||||||
=> { GPLOT => "temp4hum4:Temp/Hum,", FILTER => "%NAME" },
|
=> { GPLOT => "temp4hum4:Temp/Hum,", FILTER => "%NAME" },
|
||||||
|
|
||||||
|
"FBDECT.*"
|
||||||
|
=> { GPLOT => "power4:Power,", FILTER => "%NAME:power.*",
|
||||||
|
ATTR => "event-min-interval:power:120" },
|
||||||
);
|
);
|
||||||
|
|
||||||
# Do not create FileLog for the following devices.
|
# Do not create FileLog for the following devices.
|
||||||
@@ -180,11 +184,13 @@ autocreate_Notify($$)
|
|||||||
next if(!$fl);
|
next if(!$fl);
|
||||||
my $flname = "FileLog_$name";
|
my $flname = "FileLog_$name";
|
||||||
delete($defs{$flname}); # If we are re-creating it with createlog.
|
delete($defs{$flname}); # If we are re-creating it with createlog.
|
||||||
my ($gplot, $filter) = ("", $name);
|
my ($gplot, $filter, $devattr) = ("", $name, "");
|
||||||
foreach my $k (keys %flogpar) {
|
foreach my $k (keys %flogpar) {
|
||||||
next if($name !~ m/^$k$/);
|
next if($name !~ m/^$k$/);
|
||||||
$gplot = $flogpar{$k}{GPLOT};
|
$gplot = $flogpar{$k}{GPLOT};
|
||||||
$filter = replace_wildcards($hash, $flogpar{$k}{FILTER});
|
$filter = replace_wildcards($hash, $flogpar{$k}{FILTER});
|
||||||
|
$devattr = $flogpar{$k}{ATTR};
|
||||||
|
last;
|
||||||
}
|
}
|
||||||
$cmd = "$flname FileLog $fl $filter";
|
$cmd = "$flname FileLog $fl $filter";
|
||||||
Log $ll2, "autocreate: define $cmd";
|
Log $ll2, "autocreate: define $cmd";
|
||||||
@@ -195,7 +201,12 @@ autocreate_Notify($$)
|
|||||||
}
|
}
|
||||||
$attr{$flname}{room} = $room if($room);
|
$attr{$flname}{room} = $room if($room);
|
||||||
$attr{$flname}{logtype} = "${gplot}text";
|
$attr{$flname}{logtype} = "${gplot}text";
|
||||||
|
if($devattr) {
|
||||||
|
foreach my $attrNV (split(" ", $devattr)) {
|
||||||
|
my ($an, $av) = split(":", $attrNV, 2);
|
||||||
|
$attr{$name}{$an} = $av;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
####################
|
####################
|
||||||
next if(!AttrVal($me, "weblink", 1) || !$gplot);
|
next if(!AttrVal($me, "weblink", 1) || !$gplot);
|
||||||
|
|||||||
@@ -370,6 +370,15 @@ A line ending with \ will be concatenated with the next one, so long lines
|
|||||||
new value identical to the old value, no event is created.
|
new value identical to the old value, no event is created.
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
|
<a name="event-min-interval"></a>
|
||||||
|
<li>event-min-interval<br>
|
||||||
|
This attribute takes a comma-separated list of reading:minInterval pairs.
|
||||||
|
You may use regular expressions for reading. Events will only be
|
||||||
|
generated, if at least minInterval seconds elapsed since the last reading
|
||||||
|
of the matched type.
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
|
||||||
The precedence of event-on-update-reading and event-on-change-reading is as
|
The precedence of event-on-update-reading and event-on-change-reading is as
|
||||||
follows:
|
follows:
|
||||||
<ol>
|
<ol>
|
||||||
|
|||||||
@@ -355,15 +355,6 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.</p>
|
|||||||
Auswertung passiert bei jeder Änderung eines Readings.
|
Auswertung passiert bei jeder Änderung eines Readings.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<a name="event-on-update-reading"></a>
|
|
||||||
<li>event-on-update-reading<br>
|
|
||||||
If not set, every update of any reading creates an event, which e.g. is
|
|
||||||
handled by <a href="#notify">notify</a> or <a href="#FileLog">FileLog</a>.
|
|
||||||
The attribute takes a comma-separated list of readings. You may use regular
|
|
||||||
expressions in that list. If set, only updates of the listed readings
|
|
||||||
create events.
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<a name="event-on-update-reading"></a>
|
<a name="event-on-update-reading"></a>
|
||||||
<li>event-on-update-reading<br>
|
<li>event-on-update-reading<br>
|
||||||
Wenn nicht gesetzt, erzeugt jede Veränderung eines "readings" ein
|
Wenn nicht gesetzt, erzeugt jede Veränderung eines "readings" ein
|
||||||
@@ -374,7 +365,6 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.</p>
|
|||||||
|
|
||||||
<a name="event-on-change-reading"></a>
|
<a name="event-on-change-reading"></a>
|
||||||
<li>event-on-change-reading<br>
|
<li>event-on-change-reading<br>
|
||||||
|
|
||||||
Dieses Attribut enthält eine durch Kommata getrennte Liste von
|
Dieses Attribut enthält eine durch Kommata getrennte Liste von
|
||||||
"readings". Wenn gesetzt, erzeugen nur Veränderungen der gelisteten
|
"readings". Wenn gesetzt, erzeugen nur Veränderungen der gelisteten
|
||||||
"readings" ein Ereignis. Wenn die aktualiserten Werte der gelisteten
|
"readings" ein Ereignis. Wenn die aktualiserten Werte der gelisteten
|
||||||
@@ -390,7 +380,15 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.</p>
|
|||||||
<li>Wenn ein "reading" in event-on-update-reading aufgeführt ist,
|
<li>Wenn ein "reading" in event-on-update-reading aufgeführt ist,
|
||||||
erzeugt eine Aktualisierung ein Ereignis unabhängig ob das
|
erzeugt eine Aktualisierung ein Ereignis unabhängig ob das
|
||||||
"reading" auch in event-on-change-reading aufgelistet ist.</li>
|
"reading" auch in event-on-change-reading aufgelistet ist.</li>
|
||||||
</ul><br>
|
</ul><br></li>
|
||||||
|
|
||||||
|
<a name="event-min-interval"></a>
|
||||||
|
<li>event-min-interval<br>
|
||||||
|
Dieses Attribut enthält eine durch Kommata getrennte Liste von
|
||||||
|
"readings:minInterval" Paare. readings kann ein regexp sein. Ein Event wird
|
||||||
|
nur dann generiert, falls seit dem letzten Auftreten des gleichen Events
|
||||||
|
mindestens minInterval Sekunden vergangen sind.
|
||||||
|
</li><br>
|
||||||
|
|
||||||
<a name="userReadings"></a>
|
<a name="userReadings"></a>
|
||||||
<li>userReadings<br>
|
<li>userReadings<br>
|
||||||
|
|||||||
46
fhem.pl
46
fhem.pl
@@ -205,12 +205,14 @@ $modules{Global}{AttrList} =
|
|||||||
"verbose:1,2,3,4,5 mseclog:1,0 version nofork:1,0 logdir holiday2we " .
|
"verbose:1,2,3,4,5 mseclog:1,0 version nofork:1,0 logdir holiday2we " .
|
||||||
"autoload_undefined_devices:1,0 dupTimeout latitude longitude " .
|
"autoload_undefined_devices:1,0 dupTimeout latitude longitude " .
|
||||||
"backupcmd backupdir backupsymlink backup_before_update " .
|
"backupcmd backupdir backupsymlink backup_before_update " .
|
||||||
"exclude_from_update motd updatebranch uniqueID sendStatistics:onUpdate,manually,never ".
|
"exclude_from_update motd updatebranch uniqueID ".
|
||||||
|
"sendStatistics:onUpdate,manually,never ".
|
||||||
"showInternalValues:1,0 ";
|
"showInternalValues:1,0 ";
|
||||||
$modules{Global}{AttrFn} = "GlobalAttr";
|
$modules{Global}{AttrFn} = "GlobalAttr";
|
||||||
|
|
||||||
use vars qw($readingFnAttributes);
|
use vars qw($readingFnAttributes);
|
||||||
$readingFnAttributes = "event-on-change-reading event-on-update-reading stateFormat";
|
$readingFnAttributes = "event-on-change-reading event-on-update-reading ".
|
||||||
|
"event-min-interval stateFormat";
|
||||||
|
|
||||||
|
|
||||||
%cmds = (
|
%cmds = (
|
||||||
@@ -2109,9 +2111,7 @@ SignalHandling()
|
|||||||
sub
|
sub
|
||||||
TimeNow()
|
TimeNow()
|
||||||
{
|
{
|
||||||
my @t = localtime;
|
return FmtDateTime(time());
|
||||||
return sprintf("%04d-%02d-%02d %02d:%02d:%02d",
|
|
||||||
$t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
@@ -2992,9 +2992,16 @@ readingsBeginUpdate($)
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
# get timestamp
|
# get timestamp
|
||||||
my $now = TimeNow();
|
my $now = gettimeofday();
|
||||||
$hash->{".updateTime"} = time(); # in seconds since the epoch
|
my $fmtDateTime = FmtDateTime($now);
|
||||||
$hash->{".updateTimestamp"} = $now;
|
$hash->{".updateTime"} = $now; # in seconds since the epoch
|
||||||
|
$hash->{".updateTimestamp"} = $fmtDateTime;
|
||||||
|
|
||||||
|
my $attrminint = AttrVal($name, "event-min-interval", undef);
|
||||||
|
if($attrminint) {
|
||||||
|
my @a = split(/,/,$attrminint);
|
||||||
|
$hash->{".attrminint"} = \@a;
|
||||||
|
}
|
||||||
|
|
||||||
my $attreocr= AttrVal($name, "event-on-change-reading", undef);
|
my $attreocr= AttrVal($name, "event-on-change-reading", undef);
|
||||||
if($attreocr) {
|
if($attreocr) {
|
||||||
@@ -3009,7 +3016,7 @@ readingsBeginUpdate($)
|
|||||||
}
|
}
|
||||||
|
|
||||||
$hash->{CHANGED}= ();
|
$hash->{CHANGED}= ();
|
||||||
return $now;
|
return $fmtDateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
@@ -3095,6 +3102,7 @@ readingsEndUpdate($$)
|
|||||||
delete $hash->{".updateTime"};
|
delete $hash->{".updateTime"};
|
||||||
delete $hash->{".attreour"};
|
delete $hash->{".attreour"};
|
||||||
delete $hash->{".attreocr"};
|
delete $hash->{".attreocr"};
|
||||||
|
delete $hash->{".attrminint"};
|
||||||
|
|
||||||
|
|
||||||
# propagate changes
|
# propagate changes
|
||||||
@@ -3131,12 +3139,14 @@ readingsBulkUpdate($$$@)
|
|||||||
if(!defined($changed)) {
|
if(!defined($changed)) {
|
||||||
$changed = (substr($reading,0,1) ne "."); # Dont trigger dot-readings
|
$changed = (substr($reading,0,1) ne "."); # Dont trigger dot-readings
|
||||||
}
|
}
|
||||||
|
$changed = 0 if($hash->{".ignoreEvent"});
|
||||||
|
|
||||||
# check for changes only if reading already exists
|
# check for changes only if reading already exists
|
||||||
if($changed && defined($readings)) {
|
if($changed && defined($readings)) {
|
||||||
|
|
||||||
# these flags determine if any of the "event-on" attributes are set
|
# these flags determine if any of the "event-on" attributes are set
|
||||||
my $attreocr= $hash->{".attreocr"};
|
my $attreocr = $hash->{".attreocr"};
|
||||||
my $attreour= $hash->{".attreour"};
|
my $attreour = $hash->{".attreour"};
|
||||||
|
|
||||||
# these flags determine whether the reading is listed in any of
|
# these flags determine whether the reading is listed in any of
|
||||||
# the attributes
|
# the attributes
|
||||||
@@ -3151,6 +3161,20 @@ readingsBulkUpdate($$$@)
|
|||||||
|| $eour
|
|| $eour
|
||||||
|| ($eocr && ($value ne $readings->{VAL}));
|
|| ($eocr && ($value ne $readings->{VAL}));
|
||||||
#Log 1, "EOCR:$eocr EOUR:$eour CHANGED:$changed";
|
#Log 1, "EOCR:$eocr EOUR:$eour CHANGED:$changed";
|
||||||
|
|
||||||
|
my @v = grep { my $l = $_;
|
||||||
|
$l =~ s/:.*//;
|
||||||
|
($reading=~ m/^$l$/) ? $_ : undef} @{$hash->{".attrminint"}};
|
||||||
|
if($changed && @v) {
|
||||||
|
my (undef, $minInt) = split(":", $v[0]);
|
||||||
|
my $now = $hash->{".updateTime"};
|
||||||
|
my $le = $hash->{".lastTime$reading"};
|
||||||
|
if($le && $now-$le < $minInt) {
|
||||||
|
$changed = 0;
|
||||||
|
} else {
|
||||||
|
$hash->{".lastTime$reading"} = $now;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setReadingsVal($hash, $reading, $value, $hash->{".updateTimestamp"});
|
setReadingsVal($hash, $reading, $value, $hash->{".updateTimestamp"});
|
||||||
|
|||||||
Reference in New Issue
Block a user