diff --git a/CHANGED b/CHANGED
index 03ea28cc4..cbdeac94a 100644
--- a/CHANGED
+++ b/CHANGED
@@ -92,6 +92,8 @@
added, Extend devStateIcon, js setting of attr values in detail
screen, live slider update in detail and room view
- 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)
- feature: added functions trim, ltrim, rtrim, UntoggleDirect,
diff --git a/FHEM/00_FBAHA.pm b/FHEM/00_FBAHA.pm
new file mode 100755
index 000000000..864bcb425
--- /dev/null
+++ b/FHEM/00_FBAHA.pm
@@ -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 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
+
+
+FBAHA
+
+ NOTE: As of FRITZ!OS 5.50 this module is known to work on the FB7390,
+ and is known to crash the FB7270.
+
+ This module connects to the AHA server (AVM Home Automation) on a FRITZ!Box.
+ It serves as the "physical" counterpart to the FBDECT
+ devices.
+
+
+ Define
+
+ define <name> FBAHA <host>:<port>
+
+
+ <host> is normally the address of the FRITZ!Box running the AHA server
+ (fritz.box or localhost), and :<port> is 2002.
+
+ Example:
+
+ define fb1 FBAHA fritz.box:2002
+
+
+
+
+
+ Set
+
+ - createDevs
+ create a FHEM device for each DECT device found on the AHA-Host, see also
+ get devList.
+
+
+
+
+
+ Get
+
+ - devList
+ return a list of devices with short info.
+
+
+
+
+
+ Attributes
+
+
+
+
+ Generated events:
+
+ - UNDEFINED FBDECT_$ahaName_${NR} FBDECT $id"
+
+
+
+
+
+
+=end html
+
+=begin html_DE
+
+
+FBAHA
+
+ Achtung: Es ist bekannt, daß dieses Modul mit FRITZ!OS 5.50 auf
+ einem FB7390 funktioniert, aber den FB7270 zum Absurz bringt.
+
+ Dieses Modul verbindet sich mit dem AHA (AVM Home Automation) Server auf
+ einem FRITZ!Box. Es dient als "physikalisches" Gegenstück zum FBDECT Modul.
+
+
+ Define
+
+ define <name> FBAHA <host>:<port>
+
+
+ <host> ist normalerweise die Adresse der FRITZ!Box, wo das AHA Server
+ läuft (fritz.box oder localhost), <port> ist 2002.
+
+ Beispiel:
+
+ define fb1 FBAHA fritz.box:2002
+
+
+
+
+
+ Set
+
+ - createDevs
+ legt FHEM Geräte an für jedes auf dem AHA-Server gefundenen DECT
+ Eintrag, siehe auch "get devList".
+
+
+
+
+
+ Get
+
+ - devList
+ liefert die Liste aller DECT-Einträge der AHA Server zurück, mit
+ einem kurzen Info.
+
+
+
+
+
+ Attributes
+
+
+
+
+ Generierte Events:
+
+ - UNDEFINED FBDECT_$ahaName_${NR} FBDECT $id"
+
+
+
+
+=end html_DE
+
+=cut
diff --git a/FHEM/10_FBDECT.pm b/FHEM/10_FBDECT.pm
new file mode 100755
index 000000000..4203c03a6
--- /dev/null
+++ b/FHEM/10_FBDECT.pm
@@ -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 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
+
+
+FBDECT
+
+ This module is used to control AVM FRITZ!DECT devices via FHEM, see also the
+ FBAHA module for the base.
+
+
+ Define
+
+ define <name> FBDECT <homeId> <id> [classes]
+
+
+ <id> is the id of the device, the classes argument ist ignored for now.
+
+ Example:
+
+ define lamp FBDECT 16 switch,powerMeter
+
+ Note:Usually the device is created via
+ autocreate
+
+
+
+ Set
+
+ - on/off
+ set the device on or off.
+ -
+ set extensions are supported.
+
+
+
+
+ Get
+
+ - devInfo
+ report device information
+
+
+
+
+ Attributes
+
+
+
+
+ Generated events:
+
+ - on
+ - off
+ - set_on
+ - set_off
+ - current: $v A
+ - voltage: $v V
+ - power: $v W
+ - energy: $v Wh
+ - powerFactor: $v"
+ - temperature: $v C
+
+
+
+=end html
+
+=begin html_DE
+
+
+FBDECT
+
+ Dieses Modul wird verwendet, um AVM FRITZ!DECT Geräte via FHEM zu
+ steuern, siehe auch das FBAHA Modul für die
+ Anbindung an das FRITZ!Box.
+
+
+ Define
+
+ define <name> FBDECT <homeId> <id> [classes]
+
+
+ <id> ist das Geräte-ID, das Argument wird z.Zt ignoriert.
+
+ Beispiel:
+
+ define lampe FBDECT 16 switch,powerMeter
+
+ Achtung:FBDECT Einträge werden noralerweise per
+ autocreate angelegt.
+
+
+
+ Set
+
+ - on/off
+ Gerät einschalten bzw. ausschalten.
+ -
+ Die set extensions werden unterstützt.
+
+
+
+
+ Get
+
+ - devInfo
+ meldet Geräte-Informationen.
+
+
+
+
+ Attribute
+
+
+
+
+ Generierte events:
+
+ - on
+ - off
+ - set_on
+ - set_off
+ - current: $v A
+ - voltage: $v V
+ - power: $v W
+ - energy: $v Wh
+ - powerFactor: $v"
+ - temperature: $v C
+
+
+=end html_DE
+
+=cut
diff --git a/FHEM/98_autocreate.pm b/FHEM/98_autocreate.pm
index aafecd8a3..bf1d6879d 100644
--- a/FHEM/98_autocreate.pm
+++ b/FHEM/98_autocreate.pm
@@ -76,6 +76,10 @@ my %flogpar = (
# Lacrosse TX
"CUL_TX.*"
=> { 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.
@@ -180,11 +184,13 @@ autocreate_Notify($$)
next if(!$fl);
my $flname = "FileLog_$name";
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) {
next if($name !~ m/^$k$/);
$gplot = $flogpar{$k}{GPLOT};
$filter = replace_wildcards($hash, $flogpar{$k}{FILTER});
+ $devattr = $flogpar{$k}{ATTR};
+ last;
}
$cmd = "$flname FileLog $fl $filter";
Log $ll2, "autocreate: define $cmd";
@@ -195,7 +201,12 @@ autocreate_Notify($$)
}
$attr{$flname}{room} = $room if($room);
$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);
diff --git a/docs/commandref_frame.html b/docs/commandref_frame.html
index feb89688f..fbb1999fc 100644
--- a/docs/commandref_frame.html
+++ b/docs/commandref_frame.html
@@ -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.
+
+ event-min-interval
+ 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.
+
+
+
The precedence of event-on-update-reading and event-on-change-reading is as
follows:
diff --git a/docs/commandref_frame_DE.html b/docs/commandref_frame_DE.html
index c5b070058..e52c52a60 100644
--- a/docs/commandref_frame_DE.html
+++ b/docs/commandref_frame_DE.html
@@ -355,15 +355,6 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.
Auswertung passiert bei jeder Änderung eines Readings.
-
- event-on-update-reading
- If not set, every update of any reading creates an event, which e.g. is
- handled by notify or FileLog.
- 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.
-
-
event-on-update-reading
Wenn nicht gesetzt, erzeugt jede Veränderung eines "readings" ein
@@ -374,7 +365,6 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.
event-on-change-reading
-
Dieses Attribut enthält eine durch Kommata getrennte Liste von
"readings". Wenn gesetzt, erzeugen nur Veränderungen 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.
Wenn ein "reading" in event-on-update-reading aufgeführt ist,
erzeugt eine Aktualisierung ein Ereignis unabhängig ob das
"reading" auch in event-on-change-reading aufgelistet ist.
-
+
+
+
+ event-min-interval
+ 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.
+
userReadings
diff --git a/fhem.pl b/fhem.pl
index 54a351610..f39e6ef1b 100755
--- a/fhem.pl
+++ b/fhem.pl
@@ -205,12 +205,14 @@ $modules{Global}{AttrList} =
"verbose:1,2,3,4,5 mseclog:1,0 version nofork:1,0 logdir holiday2we " .
"autoload_undefined_devices:1,0 dupTimeout latitude longitude " .
"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 ";
$modules{Global}{AttrFn} = "GlobalAttr";
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 = (
@@ -2109,9 +2111,7 @@ SignalHandling()
sub
TimeNow()
{
- my @t = localtime;
- return sprintf("%04d-%02d-%02d %02d:%02d:%02d",
- $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);
+ return FmtDateTime(time());
}
#####################################
@@ -2992,9 +2992,16 @@ readingsBeginUpdate($)
my $name = $hash->{NAME};
# get timestamp
- my $now = TimeNow();
- $hash->{".updateTime"} = time(); # in seconds since the epoch
- $hash->{".updateTimestamp"} = $now;
+ my $now = gettimeofday();
+ my $fmtDateTime = FmtDateTime($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);
if($attreocr) {
@@ -3009,7 +3016,7 @@ readingsBeginUpdate($)
}
$hash->{CHANGED}= ();
- return $now;
+ return $fmtDateTime;
}
sub
@@ -3095,6 +3102,7 @@ readingsEndUpdate($$)
delete $hash->{".updateTime"};
delete $hash->{".attreour"};
delete $hash->{".attreocr"};
+ delete $hash->{".attrminint"};
# propagate changes
@@ -3131,12 +3139,14 @@ readingsBulkUpdate($$$@)
if(!defined($changed)) {
$changed = (substr($reading,0,1) ne "."); # Dont trigger dot-readings
}
+ $changed = 0 if($hash->{".ignoreEvent"});
+
# check for changes only if reading already exists
if($changed && defined($readings)) {
# these flags determine if any of the "event-on" attributes are set
- my $attreocr= $hash->{".attreocr"};
- my $attreour= $hash->{".attreour"};
+ my $attreocr = $hash->{".attreocr"};
+ my $attreour = $hash->{".attreour"};
# these flags determine whether the reading is listed in any of
# the attributes
@@ -3151,6 +3161,20 @@ readingsBulkUpdate($$$@)
|| $eour
|| ($eocr && ($value ne $readings->{VAL}));
#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"});