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:
rudolfkoenig
2013-03-01 11:09:18 +00:00
parent e0fd2d9f73
commit 624385760a
7 changed files with 868 additions and 24 deletions

View File

@@ -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
View 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 &lt;name&gt; FBAHA &lt;host&gt;:&lt;port&gt;</code>
<br>
<br>
&lt;host&gt; is normally the address of the FRITZ!Box running the AHA server
(fritz.box or localhost), and :&lt;port&gt; 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&szlig; 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&uuml;ck zum <a
href="#FBDECT">FBDECT</a> Modul.
<br><br>
<a name="FBAHAdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; FBAHA &lt;host&gt;:&lt;port&gt;</code>
<br>
<br>
&lt;host&gt; ist normalerweise die Adresse der FRITZ!Box, wo das AHA Server
l&auml;uft (fritz.box oder localhost), &lt;port&gt; 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&auml;te an f&uuml;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&auml;ge der AHA Server zur&uuml;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
View 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 &lt;name&gt; FBDECT &lt;homeId&gt; &lt;id&gt; [classes]</code>
<br>
<br>
&lt;id&gt; 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&auml;te via FHEM zu
steuern, siehe auch das <a href="#FBAHA">FBAHA</a> Modul f&uumlr die
Anbindung an das FRITZ!Box.
<br><br>
<a name="FBDECTdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; FBDECT &lt;homeId&gt; &lt;id&gt; [classes]</code>
<br>
<br>
&lt;id&gt; ist das Ger&auml;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&auml;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&auml;t einschalten bzw. ausschalten.</li>
<li>
Die <a href="#setExtensions">set extensions</a> werden unterst&uuml;tzt.</li>
</ul>
<br>
<a name="FBDECTget"></a>
<b>Get</b>
<ul>
<li>devInfo<br>
meldet Ger&auml;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

View File

@@ -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);

View File

@@ -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>

View File

@@ -355,15 +355,6 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.</p>
Auswertung passiert bei jeder &Auml;nderung eines Readings. Auswertung passiert bei jeder &Auml;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&auml;nderung eines "readings" ein Wenn nicht gesetzt, erzeugt jede Ver&auml;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&auml;lt eine durch Kommata getrennte Liste von Dieses Attribut enth&auml;lt eine durch Kommata getrennte Liste von
"readings". Wenn gesetzt, erzeugen nur Ver&auml;nderungen der gelisteten "readings". Wenn gesetzt, erzeugen nur Ver&auml;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&uuml;hrt ist, <li>Wenn ein "reading" in event-on-update-reading aufgef&uuml;hrt ist,
erzeugt eine Aktualisierung ein Ereignis unabh&auml;ngig ob das erzeugt eine Aktualisierung ein Ereignis unabh&auml;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&auml;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>

42
fhem.pl
View File

@@ -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,6 +3139,8 @@ 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)) {
@@ -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"});