From ae8482245a67cd38c0695d01386f071961fea2b0 Mon Sep 17 00:00:00 2001
From: martinp876 <>
Date: Sun, 8 Sep 2013 14:57:34 +0000
Subject: [PATCH] introduce flow contorl for HMLAN
git-svn-id: https://svn.fhem.de/fhem/trunk@3879 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/FHEM/00_HMLAN.pm | 172 ++++++++++++++++++++++++--------
fhem/FHEM/10_CUL_HM.pm | 216 ++++++++++++++++++++++++++++-------------
fhem/FHEM/98_HMinfo.pm | 58 ++++++-----
fhem/FHEM/HMConfig.pm | 2 +-
4 files changed, 319 insertions(+), 129 deletions(-)
diff --git a/fhem/FHEM/00_HMLAN.pm b/fhem/FHEM/00_HMLAN.pm
index 8d0d9eefe..d7e9d67c5 100755
--- a/fhem/FHEM/00_HMLAN.pm
+++ b/fhem/FHEM/00_HMLAN.pm
@@ -24,7 +24,6 @@ sub HMLAN_DoInit($);
sub HMLAN_KeepAlive($);
sub HMLAN_secSince2000();
sub HMLAN_relOvrLd($);
-sub HMLAN_relOvrLd($);
sub HMLAN_condUpdate($$);
my $debug = 1; # set 1 for better log readability
@@ -34,8 +33,10 @@ my %sets = ( "hmPairForSec" => "HomeMatic"
my %HMcond = ( 0 =>'ok'
,2 =>'Warning-HighLoad'
,4 =>'ERROR-Overload'
+ ,253=>'disconnected'
,254=>'Overload-released'
,255=>'init');
+
my $HMOvLdRcvr = 6*60;# time HMLAN needs to recover from overload
sub HMLAN_Initialize($) {
@@ -63,6 +64,7 @@ sub HMLAN_Initialize($) {
"hmId hmKey " .
"respTime wdStrokeTime:5,10,15,20,25 " .
"hmProtocolEvents:0_off,1_dump,2_dumpFull,3_dumpTrigger ".
+ "hmLanQlen:1_min,2_low,3_normal,4_high,5_critical ".
"wdTimer ".
$readingFnAttributes;
}
@@ -87,7 +89,17 @@ sub HMLAN_Define($$) {#########################################################
return undef;
}
$attr{$name}{wdTimer} = 25;
+ $attr{$name}{hmLanQlen} = "1_min"; #max message queue length in HMLan
+ no warnings 'numeric';
+ $hash->{helper}{q}{hmLanQlen} = int($attr{$name}{hmLanQlen})+0;
+ use warnings 'numeric';
$hash->{DeviceName} = $dev;
+
+ $hash->{helper}{q}{answerPend} = 0;#pending answers from LANIf
+ my @arr = ();
+ @{$hash->{helper}{q}{apIDs}} = \@arr;
+
+ HMLAN_condUpdate($hash,253);#set disconnected
my $ret = DevIo_OpenDev($hash, 0, "HMLAN_DoInit");
return $ret;
}
@@ -120,6 +132,16 @@ sub HMLAN_Attr(@) {#################################
return "select wdTimer between 5 and 25 seconds" if ($aVal>25 || $aVal<5);
$attr{$name}{wdTimer} = $aVal;
}
+ elsif($attrName eq "hmLanQlen"){
+ if ($cmd eq "set"){
+ no warnings 'numeric';
+ $defs{$name}{helper}{q}{hmLanQlen} = int($aVal)+0;
+ use warnings 'numeric';
+ }
+ else{
+ $defs{$name}{helper}{q}{hmLanQlen} = 1;
+ }
+ }
return;
}
@@ -176,6 +198,7 @@ sub HMLAN_ReadAnswer($$$) {# This is a direct read for commands like get
next if ($! == EAGAIN() || $! == EINTR() || $! == 0);
my $err = $!;
DevIo_Disconnected($hash);
+ HMLAN_condUpdate($hash,253);
return("HMLAN_ReadAnswer $arg: $err", undef);
}
return ("Timeout reading answer for get $arg", undef) if($nfound == 0);
@@ -346,8 +369,11 @@ sub HMLAN_Parse($$) {##########################################################
# $CULinfo = "AESresp";# General needs approval
}
if ($stat){# message with status information
- HMLAN_condUpdate($hash,$HMcnd)if ($hash->{helper}{HMcnd} != $HMcnd);
+ HMLAN_condUpdate($hash,$HMcnd)if ($hash->{helper}{q}{HMcndN} != $HMcnd);
+ if ($stat & 0x03 && $dst eq $attr{$name}{hmId}){HMLAN_qResp($hash,$src,0);}
+ elsif ($stat & 0x08 && $src eq $attr{$name}{hmId}){HMLAN_qResp($hash,$dst,0);}
+
$hash->{helper}{$dst}{flg} = 0;#got response => unblock sending
if ($stat & 0x0A){#08 and 02 dont need to go to CUL, internal ack only
Log $ll5, "HMLAN_Parse: $name no ACK from $dst" if($stat & 0x08);
@@ -356,7 +382,7 @@ sub HMLAN_Parse($$) {##########################################################
$CULinfo = "AESerrReject";
}elsif (($stat & 0x70) == 0x20){$CULinfo = "AESok";
}elsif (($stat & 0x70) == 0x40){;#$CULinfo = "???";
- }
+ }
}
my $rssi = hex($mFld[4])-65536;
@@ -390,7 +416,7 @@ sub HMLAN_Parse($$) {##########################################################
# we ack ourself an long as logic is uncertain - also possible is 'A6' for RHS
if (hex($flg)&0x4){#not sure: 4 oder 2 ?
my $wait = 0.100 - $dly/1000;
- $hash->{helper}{nextSend}{$src} = gettimeofday() + $wait if ($wait > 0);
+ $hash->{helper}{$src}{nextSend} = gettimeofday() + $wait if ($wait > 0);
}
if (hex($flg)&0xA4 == 0xA4 && $hash->{owner} eq $dst){
Log $ll5, "HMLAN_Parse: $name ACK config";
@@ -418,8 +444,8 @@ sub HMLAN_Parse($$) {##########################################################
$hash->{owner} = $mFld[4];
$hash->{uptime} = HMLAN_uptime($mFld[5],$hash);
$hash->{assignIDsReport}=hex($mFld[6]);
- $hash->{helper}{keepAliveRec} = 1;
- $hash->{helper}{keepAliveRpt} = 0;
+ $hash->{helper}{q}{keepAliveRec} = 1;
+ $hash->{helper}{q}{keepAliveRpt} = 0;
Log $ll5, 'HMLAN_Parse: '.$name. ' V:'.$mFld[1]
.' sNo:'.$mFld[2].' d:'.$mFld[3]
.' O:' .$mFld[4].' t:'.$mFld[5].' IDcnt:'.$mFld[6];
@@ -446,6 +472,8 @@ sub HMLAN_SimpleWrite(@) {#####################################################
my ($hash, $msg, $nonl) = @_;
return if(!$hash || AttrVal($hash->{NAME}, "dummy", undef));
+ HMLAN_condUpdate($hash,253) if ($hash->{STATE} eq "disconnected");#closed?
+
my $name = $hash->{NAME};
my $ll5 = GetLogLevel($name,5);
my $len = length($msg);
@@ -453,34 +481,44 @@ sub HMLAN_SimpleWrite(@) {#####################################################
# It is not possible to answer befor 100ms
if ($len>51){
- return if($hash->{helper}{HMcnd} && $hash->{helper}{HMcnd} == 4);#overload
+ if($hash->{helper}{q}{HMcndN}){
+ my $HMcnd = $hash->{helper}{q}{HMcndN};
+ return if ($HMcnd == 4 || $HMcnd == 253);# no send if overload or disconnect
+ }
+
my $dst = substr($msg,46,6);
- if ($hash->{helper}{nextSend}{$dst}){
- my $DevDelay = $hash->{helper}{nextSend}{$dst} - gettimeofday();
+ my $hDst = $hash->{helper}{$dst};# shortcut
+ if ($hDst->{nextSend}){
+ my $DevDelay = $hDst->{nextSend} - gettimeofday();
select(undef, undef, undef, (($DevDelay > 0.1)?0.1:$DevDelay))
if ($DevDelay > 0.01);
- delete $hash->{helper}{nextSend}{$dst};
+ delete $hDst->{nextSend};
}
if ($dst ne $attr{$name}{hmId}){ #delay send if answer is pending
- if ( $hash->{helper}{$dst}{flg} && #HMLAN's ack pending
- ($hash->{helper}{$dst}{to} > gettimeofday())){#won't wait forever!
- $hash->{helper}{$dst}{msg} = $msg; #postpone message
+ if ( $hDst->{flg} && #HMLAN's ack pending
+ ($hDst->{to} > gettimeofday())){#won't wait forever!
+ $hDst->{msg} = $msg; #postpone message
Log $ll5,"HMLAN_Delay: $name $dst";
return;
}
my $flg = substr($msg,36,2);
- $hash->{helper}{$dst}{flg} = (hex($flg)&0x20)?1:0;
- $hash->{helper}{$dst}{to} = gettimeofday() + 2;# flag timeout after 2 sec
- $hash->{helper}{$dst}{msg} = "";
+ $hDst->{flg} = (hex($flg)&0x20)?1:0;# answer expected?
+ $hDst->{to} = gettimeofday() + 2;# flag timeout after 2 sec
+ $hDst->{msg} = "";
+
+ if ($hDst->{flg} == 1 &&
+ substr($msg,40,6) eq $attr{$name}{hmId}){
+ HMLAN_qResp($hash,$dst,1);
+ }
}
if ($len > 52){#channel information included, send sone kind of clearance
my $chn = substr($msg,52,2);
- if ($hash->{helper}{$dst}{chn} && $hash->{helper}{$dst}{chn} ne $chn){
- my $updt = $hash->{helper}{$dst}{newChn};
+ if ($hDst->{chn} && $hDst->{chn} ne $chn){
+ my $updt = $hDst->{newChn};
Log $ll5, 'HMLAN_Send: '.$name.' S:'.$updt;
syswrite($hash->{TCPDev}, $updt."\r\n") if($hash->{TCPDev});
}
- $hash->{helper}{$dst}{chn} = $chn;
+ $hDst->{chn} = $chn;
}
$msg =~ m/(.{9}).(..).(.{8}).(..).(.{8}).(..)(....)(.{6})(.{6})(.*)/;
Log $ll5, 'HMLAN_Send: '.$name.' S:'.$1
@@ -519,12 +557,12 @@ sub HMLAN_DoInit($) {##########################################################
HMLAN_SimpleWrite($hash, "T$s2000,04,00,00000000");
delete $hash->{helper}{ref};
- $hash->{helper}{HMcnd} = 0xff; # init HMLAN xmit cond, will force reading
+ HMLAN_condUpdate($hash,0xff);
RemoveInternalTimer( "Overload:".$name);
foreach (keys %lhash){delete ($lhash{$_})};# clear IDs - HMLAN might have a reset
- $hash->{helper}{keepAliveRec} = 1; # ok for first time
- $hash->{helper}{keepAliveRpt} = 0; # ok for first time
+ $hash->{helper}{q}{keepAliveRec} = 1; # ok for first time
+ $hash->{helper}{q}{keepAliveRpt} = 0; # ok for first time
RemoveInternalTimer( "keepAliveCk:".$name);# avoid duplicate timer
RemoveInternalTimer( "keepAlive:".$name);# avoid duplicate timer
@@ -535,7 +573,7 @@ sub HMLAN_KeepAlive($) {#######################################################
my($in ) = shift;
my(undef,$name) = split(':',$in);
my $hash = $defs{$name};
- $hash->{helper}{keepAliveRec} = 0; # reset indicator
+ $hash->{helper}{q}{keepAliveRec} = 0; # reset indicator
return if(!$hash->{FD});
HMLAN_SimpleWrite($hash, "K");
@@ -550,17 +588,18 @@ sub HMLAN_KeepAliveCheck($) {##################################################
my($in ) = shift;
my(undef,$name) = split(':',$in);
my $hash = $defs{$name};
- if ($hash->{helper}{keepAliveRec} != 1){# no answer
- if ($hash->{helper}{keepAliveRpt} >2){# give up here
+ if ($hash->{helper}{q}{keepAliveRec} != 1){# no answer
+ if ($hash->{helper}{q}{keepAliveRpt} >2){# give up here
DevIo_Disconnected($hash);
+ HMLAN_condUpdate($hash,253);
}
else{
- $hash->{helper}{keepAliveRpt}++;
+ $hash->{helper}{q}{keepAliveRpt}++;
HMLAN_KeepAlive("keepAlive:".$name);#repeat
}
}
else{
- $hash->{helper}{keepAliveRpt}=0;
+ $hash->{helper}{q}{keepAliveRpt}=0;
}
}
@@ -575,26 +614,76 @@ sub HMLAN_secSince2000() {#####################################################
- 7200; # HM Special
return $t;
}
+sub HMLAN_qResp($$$) {#response-waiting queue##################################
+ my($hash,$id,$cmd) = @_;
+ my $hashQ = $hash->{helper}{q};
+ if ($cmd){
+ $hashQ->{answerPend} ++;
+ push @{$hashQ->{apIDs}},$id;
+ $hash->{XmitOpen} = 0 if ($hashQ->{answerPend} >= $hashQ->{hmLanQlen});
+ }
+ else{
+ $hashQ->{answerPend}-- if ($hashQ->{answerPend}>0);
+ @{$hashQ->{apIDs}}=grep !/$id/,@{$hashQ->{apIDs}};
+ $hash->{XmitOpen} = 1
+ if (($hashQ->{answerPend} < $hashQ->{hmLanQlen}) &&
+ !($hashQ->{HMcndN} == 4 ||
+ $hashQ->{HMcndN} == 253)
+ );
+ }
+
+# Log 1,"General max:$hashQ->{hmLanQlen} cmd:$cmd"
+# ."/".$hash->{XmitOpen}
+# ." :".$hashQ->{answerPend}
+# ."/".@{$hashQ->{apIDs}}
+# .":".join("-",@{$hashQ->{apIDs}})
+# .":$debug" ;
+}
sub HMLAN_relOvrLd($) {########################################################
my(undef,$name) = split(':',$_[0]);
HMLAN_condUpdate($defs{$name},0xFE);
+ $defs{$name}{STATE} = "opened";
}
sub HMLAN_condUpdate($$) {#####################################################
my($hash,$HMcnd) = @_;
my $name = $hash->{NAME};
- $hash->{helper}{cnd}{$HMcnd} = 0 if (!$hash->{helper}{cnd}{$HMcnd});
- $hash->{helper}{cnd}{$HMcnd}++;
- InternalTimer(gettimeofday()+$HMOvLdRcvr,"HMLAN_relOvrLd","Overload:".$name,1)
- if ($HMcnd == 4);
+ my $hashCnd = $hash->{helper}{cnd};#short to helper
+ my $hashQ = $hash->{helper}{q};#short to helper
+ $hashCnd->{$HMcnd} = 0 if (!$hashCnd->{$HMcnd});
+ $hashCnd->{$HMcnd}++;
+ if ($HMcnd == 4){#HMLAN needs a rest. Supress all sends exept keep alive
+ InternalTimer(gettimeofday()+$HMOvLdRcvr,"HMLAN_relOvrLd","Overload:".$name,1);
+ $hash->{STATE} = "overload";
+ }
my $HMcndTxt = $HMcond{$HMcnd}?$HMcond{$HMcnd}:"Unknown:$HMcnd";
Log GetLogLevel($name,2), "HMLAN_Parse: $name new condition $HMcndTxt";
- readingsSingleUpdate($hash,"cond",$HMcndTxt,1);
my $txt;
- $txt .= $HMcond{$_}.":".$hash->{helper}{cnd}{$_}." "
- foreach (keys%{$hash->{helper}{cnd}});
- readingsSingleUpdate($hash,"Xmit-Events",$txt,1);
- $hash->{helper}{HMcnd} = $HMcnd;
+ $txt .= $HMcond{$_}.":".$hashCnd->{$_}." "
+ foreach (keys%{$hashCnd});
+
+ readingsBeginUpdate($hash);
+ readingsBulkUpdate($hash,"cond",$HMcndTxt);
+ readingsBulkUpdate($hash,"Xmit-Events",$txt);
+ readingsBulkUpdate($hash,"prot_".$HMcndTxt,"last");
+ readingsEndUpdate($hash,1);
+
+ $hashQ->{HMcndN} = $HMcnd;
+
+ if ($HMcnd == 4 || $HMcnd == 253) {#transmission down
+ $hashQ->{answerPend} = 0;
+ @{$hashQ->{apIDs}} = (); #clear Q-status
+ $hash->{XmitOpen} = 0; #deny transmit
+ }
+ elsif ($HMcnd == 255) {#reset counter after init
+ $hashQ->{answerPend} = 0;
+ @{$hashQ->{apIDs}} = (); #clear Q-status
+ $hash->{XmitOpen} = 1; #deny transmit
+ }
+ else{
+ $hash->{XmitOpen} = 1
+ if($hashQ->{answerPend} < $hashQ->{hmLanQlen});#allow transmit
+ }
}
1;
@@ -660,9 +749,16 @@ sub HMLAN_condUpdate($$) {#####################################################
Define max response time of the HMLAN adapter in seconds. Default is 1 sec.
Longer times may be used as workaround in slow/instable systems or LAN configurations.
wdTimer
- Time in sec to trigger HMLAN. Values between 5 and 25 are allowed, 25 is default.
- It is not recommended to change this timer. If problems are detected with
+ Time in sec to trigger HMLAN. Values between 5 and 25 are allowed, 25 is default.
+ It is not recommended to change this timer. If problems are detected with
HLMLAN disconnection it is advisable to resolve the root-cause of the problem and not symptoms.
+ hmLanQlen
+ defines queuelength of HMLAN interface. This is therefore the number of
+ simultanously send messages. increasing values may cause higher transmission speed.
+ It may also cause retransmissions up to data loss.
+ Effects can be observed by watching protocol events
+ 1 - is a conservatibe value, and is default
+ 5 - is critical length, likely cause message loss
diff --git a/fhem/FHEM/10_CUL_HM.pm b/fhem/FHEM/10_CUL_HM.pm
index e1a04e987..68870cf67 100755
--- a/fhem/FHEM/10_CUL_HM.pm
+++ b/fhem/FHEM/10_CUL_HM.pm
@@ -117,6 +117,12 @@ sub CUL_HM_putHash($);
# ----------------modul globals-----------------------
my $respRemoved; # used to control trigger of stack processing
+my $IOpoll = 0.2;# poll speed to scan IO device out of order
+my $IOpolltout = 60; # poll timeout - stop poll and discard if to late
+
+my $maxPendCmds = 10; #number of parallel requests
+my $autoConfDly = 5; # delay autoConf readings
+
# need to take care that ACK is first
#+++++++++++++++++ startup, init, definition+++++++++++++++++++++++++++++++++++
sub CUL_HM_Initialize($) {
@@ -148,10 +154,14 @@ sub CUL_HM_Initialize($) {
$hash->{AttrList} .= " model:" .join(",", sort @modellist);
$hash->{AttrList} .= " subType:".join(",",
CUL_HM_noDup(map { $culHmModel{$_}{st} } keys %culHmModel));
+
+ $hash->{prot}{rspPend} = 0;#count Pending responses
+
CUL_HM_initRegHash();
}
sub CUL_HM_reqStatus($){
+ return if(!defined$modules{CUL_HM}{helper}{reqStatus});
while(@{$modules{CUL_HM}{helper}{reqStatus}}){
my $name = shift(@{$modules{CUL_HM}{helper}{reqStatus}});
CUL_HM_Set($defs{$name},$name,"statusRequest");
@@ -171,7 +181,9 @@ sub CUL_HM_autoReadConfig($){
CUL_HM_Set($hash,$name,"getSerial");
CUL_HM_Set($hash,$name,"getConfig");
CUL_HM_Set($hash,$name,"statusRequest");
- InternalTimer(gettimeofday()+15,"CUL_HM_autoReadConfig","autoRdCfg",0);
+ InternalTimer(gettimeofday()+$autoConfDly
+ ,"CUL_HM_autoReadConfig"
+ ,"autoRdCfg",0);
last;
}
}
@@ -542,7 +554,6 @@ sub CUL_HM_Parse($$) {##############################
return $name; #return something to please dispatcher
}
$shash->{lastMsg} = $msgX;
-# $iohash->{HM_CMDNR} = hex($mNo) if($dst eq $id);# updt message cnt to rec
delete $shash->{helper}{rpt};# new message, rm recent ack
my @ack; # ack and responses, might be repeated
@@ -553,10 +564,15 @@ sub CUL_HM_Parse($$) {##############################
push @event, "powerOn" if($parse eq "powerOn");
push @event, "" if($parse eq "parsed"); # msg is parsed but may
# be processed further
- if ($parse =~ s/entities://){#common generated trigger for some entities
- push @entities,split(",",$parse);
+ foreach my $r (split";",$parse){
+ if ($r =~ s/entities://){#common generated trigger for some entities
+ push @entities,split(",",$r);
+ }
+ else{
+ $parse = $r;
+ }
}
-
+
if ($parse eq "ACK"){# remember - ACKinfo will be passed on
push @event, "";
}
@@ -904,12 +920,8 @@ sub CUL_HM_Parse($$) {##############################
my $chId = $src.$chn;
$shash = $modules{CUL_HM}{defptr}{$chId}
if($modules{CUL_HM}{defptr}{$chId});
- if ($err&0x40 && $chn eq "02"){
- push @event, "timedOn:running";
- }
- else{
- push @event, "timedOn:off";
- }
+
+ push @event, "timedOn:".(($err&0x40 && $chn eq "02")?"running":"off");
my $mdCh = $md.$chn;
if($lvlStr{mdCh}{$mdCh} && $lvlStr{mdCh}{$mdCh}{$val}){
@@ -1016,12 +1028,8 @@ sub CUL_HM_Parse($$) {##############################
$eventName = "motor" if($st eq "blindActuator");
$eventName = "dim" if($st eq "dimmer");
my $action; #determine action
- if ($err&0x40){
- push @event, "timedOn:running";
- }
- else{
- push @event, "timedOn:off" if ($shash->{READINGS}{timedOn});
- }
+ push @event, "timedOn:".($err&0x40)?"running":"off";
+
if ($st ne "switch"){
push @event, "$eventName:up:$vs" if(($err&0x30) == 0x10);
push @event, "$eventName:down:$vs" if(($err&0x30) == 0x20);
@@ -1537,19 +1545,16 @@ sub CUL_HM_parseCommon(@){#####################################################
if ($rssi && $rssi ne '00' && $rssi ne'80');
$reply = "ACKStatus";
if ($shash->{helper}{tmdOn}){
- my $timedOn = hex(substr($p,6,2))&0x40?1:0;
- if (not hex(substr($p,6,2))&0x40){# not timed on, we have to repeat
+ if (not hex(substr($p,6,2))&0x40){# not timedOn, we have to repeat
my ($pre,$nbr,$msg) = unpack 'A4A2A*',$shash->{helper}{respWait}{cmd};
- $shash->{helper}{respWait}{cmd} = sprintf("%s%02X%s",$pre,hex($nbr)+1,$msg);
- # General changes pending aproval
-# CUL_HM_eventP($shash,"TimedOn");
-# $success = "no";
-# $repeat = 1;
-# $reply = "NACK";
- Log 1,"General missed timedOn for ".$chnhash->{NAME};
+ $shash->{helper}{respWait}{cmd} = sprintf("%s%02X%s",
+ $pre,hex($nbr)+1,$msg);
+ CUL_HM_eventP($shash,"TimedOn");
+ $success = "no";
+ $repeat = 1;
+ $reply = "NACK";
}
}
-
}
else{ #ACK
$success = "yes";
@@ -1592,7 +1597,7 @@ sub CUL_HM_parseCommon(@){#####################################################
CUL_HM_ID2PeerList ($chnNname,$_,1) foreach (@peers);
if (grep /00000000/,@peers) {# last entry, peerList is complete
- CUL_HM_respPendRm($shash);
+ CUL_HM_respPendRm($shash);
# check for request to get List3 data
my $reqPeer = $chnhash->{helper}{getCfgList};
if ($reqPeer){
@@ -1664,10 +1669,14 @@ sub CUL_HM_parseCommon(@){#####################################################
CUL_HM_updtRegDisp($chnHash,$list,
CUL_HM_peerChId($peer,
substr($chnHash->{DEF},0,6),"00000000"));
+ $ret = "done;entities:$chnName";
}
else{
CUL_HM_respPendToutProlong($shash);#wasn't last - reschedule timer
+ $ret = "done";
}
+ }
+ else{#response without request - discard
$ret = "done";
}
}
@@ -1868,13 +1877,11 @@ sub CUL_HM_Get($@) {
my @regValList; #storage of results
my $regHeader = "list:peer\tregister :value\n";
foreach my $regName (@regArr){
- Log 1,"Gegeral process $regName";
my $regL = $culHmRegDefine{$regName}->{l};
my @peerExe = (grep (/$regL/,@listWp))?@peers:("00000000");
foreach my $peer(@peerExe){
next if($peer eq "");
my $regVal= CUL_HM_getRegFromStore($name,$regName,0,$peer);#determine
- Log 1,"Gegeral get $regName p:$peer v:$regVal";
my $peerN = CUL_HM_id2Name($peer);
$peerN = " " if ($peer eq "00000000");
push @regValList,sprintf(" %d:%s\t%-16s :%s\n",
@@ -2013,6 +2020,7 @@ sub CUL_HM_Set($@) {
my @h;
@h = split(" ", $h) if($h);
+ my @postCmds=(); #Commands to be appended after regSet (ugly...)
if(!defined($h) && defined($culHmSubTypeSets{$st}{pct}) && $cmd =~ m/^\d+/) {
splice @a, 1, 0,"pct";#insert the actual command
@@ -2091,13 +2099,14 @@ sub CUL_HM_Set($@) {
}
elsif($cmd =~ m /(displayMode|displayTemp|displayTempUnit|controlMode|decalcDay)/) {
splice @a,1,3, ("regSet",$a[1],$a[2]);
+ push @postCmds,"++803F$id${dst}0204".sprintf("%02X",CUL_HM_secSince2000());
}
elsif($cmd eq "partyMode") { ################################################
my $days = $a[3];
my ($eH,$eM) = split(':',$a[2]);
return "use 00 or 30 minutes only" if ($eM !~ m/^(00|30)$/);
return "hour must be between 0 and 23" if ($eH lt 0 || $eH gt 23);
- return "days must be between 0 and 200" if ($days lt 0 || $days gt 200);
+ return "days must be between 0 and 200" if ($days < 0 || $days > 200);
$eH += 128 if ($eM eq "30");
my $cHash = CUL_HM_id2Hash($dst."02");
$cHash->{helper}{partyReg} = sprintf("61%02X62%02X0000",$eH,$days);
@@ -2113,6 +2122,7 @@ sub CUL_HM_Set($@) {
CUL_HM_pushConfig($hash,$id,$dst,2,"000000","00",6,
sprintf("61%02X62%02X",$eH,$days));
splice @a,1,3, ("regSet","controlMode","party");
+ push @postCmds,"++803F$id${dst}0204".sprintf("%02X",CUL_HM_secSince2000());
}
$cmd = $a[1];# get converted command
@@ -2136,7 +2146,8 @@ sub CUL_HM_Set($@) {
delete $hash->{READINGS};
}
elsif($sect eq "msgEvents"){
- CUL_HM_respPendRm($hash);
+ CUL_HM_respPendRm($hash);
+
delete ($hash->{helper}{burstEvtCnt});
delete ($hash->{cmdStack});
delete ($hash->{EVENTS});
@@ -2144,6 +2155,11 @@ sub CUL_HM_Set($@) {
my $protLastRcv = $hash->{protLastRcv} if ($hash->{protLastRcv});
delete ($hash->{$_}) foreach (grep(/^prot/,keys %{$hash}));
$hash->{protLastRcv} = $protLastRcv if ($protLastRcv);
+ if ($modules{CUL_HM}{$hash->{IODev}{NAME}} &&
+ $modules{CUL_HM}{$hash->{IODev}{NAME}}{pendDev}){
+ @{$modules{CUL_HM}{$hash->{IODev}{NAME}}{pendDev}} =
+ grep !/$name/,@{$modules{CUL_HM}{$hash->{IODev}{NAME}}{pendDev}};
+ }
CUL_HM_protState($hash,"Info_Cleared");
}
elsif($sect eq "rssi"){
@@ -2352,6 +2368,8 @@ sub CUL_HM_Set($@) {
$cHash = $hash if (!$cHash);
CUL_HM_pushConfig($cHash,$id,$dst,$lChn,$peerId,hex($peerChn),$list
,$addrData,$prep);
+
+ CUL_HM_PushCmdStack($hash,$_) foreach(@postCmds);#ugly commands after regSet
}
elsif($cmd eq "level") { ####################################################
#level =>" ..."
@@ -2371,9 +2389,6 @@ sub CUL_HM_Set($@) {
elsif($cmd =~ m/^(on|off|toggle)$/) { #######################################
my $lvl = ($cmd eq 'on') ? 'C8':
(($cmd eq 'off') ? '00':(CUL_HM_getChnLvl($name) != 0 ?"00":"C8"));
- if($st eq "blindActuator") { # need to stop blind to protect relais
- CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'03'.$chn)
- }
CUL_HM_PushCmdStack($hash,"++$flag"."11$id$dst"."02$chn$lvl".'0000');
$hash = $chnHash; # report to channel if defined
}
@@ -2425,9 +2440,6 @@ sub CUL_HM_Set($@) {
$tval = $a[3]?CUL_HM_encodeTime16($a[3]):"FFFF";# onTime 0.05..85825945.6, 0=forever
$rval = CUL_HM_encodeTime16((@a > 4)?$a[4]:2.5);# rampTime 0.0..85825945.6, 0=immediate
}
- elsif($st eq "blindActuator") { # need to stop blind to protect relais
- CUL_HM_PushCmdStack($hash,'++'.$flag.'11'.$id.$dst.'03'.$chn)
- }
CUL_HM_PushCmdStack($hash,sprintf("++%s11%s%s02%s%02X%s%s",
$flag,$id,$dst,$chn,$lvl*2,$rval,$tval));
readingsSingleUpdate($hash,"level","set_".$lvl,1);
@@ -2797,7 +2809,8 @@ sub CUL_HM_Set($@) {
}
else{#serve internal channels for actor
my $pChn = $chn; # simple device, only one button per channel
- $pChn = (($vChn && $vChn eq "off")?-1:0) + $chn*2 if($st eq 'blindActuator'||$st eq 'dimmer');
+ $pChn = (($vChn && $vChn eq "off")?-1:0) + $chn*2
+ if($st eq 'blindActuator'||$st eq 'dimmer');
CUL_HM_PushCmdStack($hash, sprintf("++%s3E%s%s%s40%02X%02X",$flag,
$id,$dst,$dst,
$pChn+(($mode && $mode eq "long")?64:0),
@@ -3053,16 +3066,81 @@ sub CUL_HM_getConfig($$$$$){
}
#+++++++++++++++++ Protocol stack, sending, repeat+++++++++++++++++++++++++++++
+sub CUL_HM_sndIfOpen($) {
+ my(undef,$io) = split(':',$_[0]);
+ RemoveInternalTimer("sndIfOpen:$io");# should not be necessary, but
+ my $ioHash = $defs{$io};
+ if ( $ioHash->{STATE} ne "opened"
+ ||(defined $ioHash->{XmitOpen} && $ioHash->{XmitOpen} == 0)
+# ||$modules{CUL_HM}{prot}{rspPend}>=$maxPendCmds
+ ){#still no send allowed
+ if ($modules{CUL_HM}{$io}{tmrStart} < gettimeofday() - $IOpolltout){
+ # we need to clean up - this is way to long Stop delay
+ if ($modules{CUL_HM}{$io}{pendDev}) {
+ while(@{$modules{CUL_HM}{$io}{pendDev}}){
+ my $name = shift(@{$modules{CUL_HM}{$io}{pendDev}});
+ CUL_HM_eventP($defs{$name},"IOerr");
+ }
+ }
+ $modules{CUL_HM}{$io}{tmr} = 0;
+ }
+ else{
+ InternalTimer(gettimeofday()+$IOpoll,"CUL_HM_sndIfOpen",
+ "sndIfOpen:$io", 0);
+ }
+ }
+ else{
+ $modules{CUL_HM}{$io}{tmr} = 0;
+ my $name = shift(@{$modules{CUL_HM}{$io}{pendDev}});
+ CUL_HM_ProcessCmdStack($defs{$name});
+ if (@{$modules{CUL_HM}{$io}{pendDev}}){#tmr = 0, clearing queue slowly
+ InternalTimer(gettimeofday()+$IOpoll,"CUL_HM_sndIfOpen",
+ "sndIfOpen:$io", 0);
+ }
+ }
+}
sub CUL_HM_SndCmd($$) {
my ($hash, $cmd) = @_;
$hash = CUL_HM_getDeviceHash($hash);
my $io = $hash->{IODev};
return if(!$io);
- if ($io->{helper}{HMcnd} && $io->{helper}{HMcnd} == 4){#io in overload, dont send
- CUL_HM_eventP($hash,"IOerr");
+ my $ioName = $io->{NAME};
+ if ((hex substr($cmd,2,2) & 0x20) && ( # check for commands with resp-req
+ $io->{STATE} ne "opened" # we need to queue
+ || $modules{CUL_HM}{$ioName}{tmr} # queue already running
+ ||(defined $io->{XmitOpen} && $io->{XmitOpen} == 0)#overload, dont send
+# ||$modules{CUL_HM}{prot}{rspPend}>=$maxPendCmds
+ )
+ ){
+
+ # shall we delay commands if IO device is not present?
+ # it could cause trouble if light switches on after a long period
+ # repetition will be stopped after 1min forsecurity reason.
+ my @arr = ();
+ $hash->{cmdStack} = \@arr if(!$hash->{cmdStack});
+ unshift (@{$hash->{cmdStack}}, $cmd);#pushback cmd, wait for opportunitiy
+
+ # push device to list
+ if (!defined $modules{CUL_HM}{$ioName}{tmr}){
+ # some setup work for this timer
+ $modules{CUL_HM}{$ioName}{tmr} = 0;
+ my @arr2 = ();
+ $modules{CUL_HM}{$ioName}{pendDev} = \@arr2
+ if (!$modules{CUL_HM}{$ioName}{pendDev});
+ }
+ @{$modules{CUL_HM}{$ioName}{pendDev}} =
+ CUL_HM_noDup(@{$modules{CUL_HM}{$ioName}{pendDev}},$hash->{NAME});
+ CUL_HM_respPendRm($hash);#rm timer - we are out
+
+ if ($modules{CUL_HM}{$ioName}{tmr} != 1){# need to stat timer
+ my $tn = gettimeofday();
+ InternalTimer($tn+$IOpoll, "CUL_HM_sndIfOpen", "sndIfOpen:$ioName", 0);
+ $modules{CUL_HM}{$ioName}{tmr} = 1;
+ $modules{CUL_HM}{$ioName}{tmrStart} = $tn; # abort if to long
+ }
return;
}
-
+
$cmd =~ m/^(..)(.*)$/;
my ($mn, $cmd2) = ($1, $2);
@@ -3079,28 +3157,37 @@ sub CUL_HM_SndCmd($$) {
}
$cmd = sprintf("As%02X%02X%s", length($cmd2)/2+1, $mn, $cmd2);
IOWrite($hash, "", $cmd);
+ CUL_HM_eventP($hash,"Snd");
CUL_HM_responseSetup($hash,$cmd);
$cmd =~ m/As(..)(..)(..)(..)(......)(......)(.*)/;
CUL_HM_DumpProtocol("SND", $io, ($1,$2,$3,$4,$5,$6,$7));
}
+sub CUL_HM_respWaitSu ($@){ #setup response for multi-message response
+ my ($hash,@a)=@_;
+ my $hashW = $hash->{helper}{respWait};
+ $modules{CUL_HM}{prot}{rspPend}++ if(!$hashW->{PendCmd} &&
+ !$hashW->{cmd});
+ foreach (@a){
+ my ($f,$d)=split ":",$_;
+ $hashW->{$f}=$d;
+ }
+ if ($hashW->{cmd}){InternalTimer(gettimeofday()+rand(40)/10+1,"CUL_HM_Resend" , $hash, 0);}
+ else{ InternalTimer(gettimeofday()+rand(20)/10+4,"CUL_HM_respPendTout","respPend:$hash->{DEF}", 0);}
+}
sub CUL_HM_responseSetup($$) {#store all we need to handle the response
#setup repeatTimer and cmdStackControll
my ($hash,$cmd) = @_;
my ($mNo,$mFlg,$mTp,$dst,$p) = ($2,hex($3),$4,$6,$7)
if ($cmd =~ m/As(..)(..)(..)(..)(......)(......)(.*)/);
my ($chn,$subType) = ($1,$2) if($p =~ m/^(..)(..)/);
- my $rTo = rand(20)/10+4; #default response timeout
+# my $rTo = rand(20)/10+4; #default response timeout
if (($mFlg & 0x20) && ($dst ne '000000')){
if ($mTp eq "01" && $subType){
if ($subType eq "03"){ #PeerList-------------
#--- remember request params in device level
- $hash->{helper}{respWait}{Pending} = "PeerList";
- $hash->{helper}{respWait}{PendCmd} = $cmd;
- $hash->{helper}{respWait}{forChn} = substr($p,0,2);#channel info we await
-
- # define timeout - holdup cmdStack until response complete or timeout
- InternalTimer(gettimeofday()+$rTo, "CUL_HM_respPendTout", "respPend:$dst", 0);
-
+ CUL_HM_respWaitSu ($hash,"Pending:PeerList"
+ ,"PendCmd:$cmd" ,"forChn:".substr($p,0,2));
+
#--- remove readings in channel
my $chnhash = $modules{CUL_HM}{defptr}{"$dst$chn"};
$chnhash = $hash if (!$chnhash);
@@ -3114,14 +3201,9 @@ sub CUL_HM_responseSetup($$) {#store all we need to handle the response
my ($peer, $list) = ($1,$2) if ($p =~ m/..04(........)(..)/);
$peer = ($peer ne "00000000")?CUL_HM_peerChName($peer,$dst,""):"";
#--- set messaging items
- $hash->{helper}{respWait}{Pending}= "RegisterRead";
- $hash->{helper}{respWait}{PendCmd}= $cmd;
- $hash->{helper}{respWait}{forChn} = $chn;
- $hash->{helper}{respWait}{forList}= $list;
- $hash->{helper}{respWait}{forPeer}= $peer;
-
- # define timeout - holdup cmdStack until response complete or timeout
- InternalTimer(gettimeofday()+$rTo,"CUL_HM_respPendTout","respPend:$dst", 0);
+ CUL_HM_respWaitSu ($hash,"Pending:RegisterRead"
+ ,"PendCmd:$cmd" ,"forChn:$chn"
+ ,"forList:$list","forPeer:$peer");
#--- remove channel entries that will be replaced
my $chnhash = $modules{CUL_HM}{defptr}{"$dst$chn"};
$chnhash = $hash if(!$chnhash);
@@ -3147,16 +3229,13 @@ sub CUL_HM_responseSetup($$) {#store all we need to handle the response
elsif($mTp eq '11' && $chn =~ m/^(02|81)$/){#!!! chn is subtype!!!
CUL_HM_qStateUpdatIfEnab($dst);
}
- if ($mTp eq "11" && $p =~ m/02........(....)/){
- $hash->{helper}{tmdOn} = $1 if ($1 ne "0000");
+ if ($mTp eq "11" && $p =~ m/02..(..)....(....)/){#lvl ne 0 and timer on
+ $hash->{helper}{tmdOn} = $2 if ($1 ne "00" && $2 != m/(0000|FFFF)/);
}
- $hash->{helper}{respWait}{cmd} = $cmd;
- $hash->{helper}{respWait}{mNo} = $mNo; #mNo we wait to ack
- $hash->{helper}{respWait}{reSent} = 1;
-
- InternalTimer(gettimeofday()+rand(40)/10+1, "CUL_HM_Resend", $hash, 0);
- CUL_HM_protState($hash,"CMDs_processing...");
+ CUL_HM_respWaitSu ($hash,"cmd:$cmd","mNo:$mNo","reSent:1");
+
+ CUL_HM_protState($hash,"CMDs_processing...");
}
else{# no answer expected
if($hash->{cmdStack} && scalar @{$hash->{cmdStack}}){
@@ -3218,6 +3297,8 @@ sub CUL_HM_protState($$){
}
sub CUL_HM_respPendRm($) {#del response related entries in messageing entity
my ($hash) = @_;
+ $modules{CUL_HM}{prot}{rspPend}-- if( $hash->{helper}{respWait}{cmd}
+ ||$hash->{helper}{respWait}{PendCmd});
delete ($hash->{helper}{respWait});
delete $hash->{helper}{tmdOn};
RemoveInternalTimer($hash); # remove resend-timer
@@ -3232,7 +3313,7 @@ sub CUL_HM_respPendTout($) {
my $pendCmd = $hash->{helper}{respWait}{Pending};# secure before remove
my $pendRsndCnt = $hash->{helper}{respWait}{PendingRsend};
- $pendRsndCnt = 1 if (!$pendRsndCnt);
+ $pendRsndCnt = 1 if (!$pendRsndCnt); #already one send done
if ($pendRsndCnt < 5 && # some retries
(CUL_HM_getRxType($hash) & 0x03) != 0){# to slow for wakeup and config
my $name = $hash->{NAME};
@@ -3276,7 +3357,6 @@ sub CUL_HM_ProcessCmdStack($) {
!$hash->{helper}{respWait}{Pending}){
if(@{$hash->{cmdStack}}) {
CUL_HM_SndCmd($hash, shift @{$hash->{cmdStack}});
- CUL_HM_eventP($hash,"Snd");
}
elsif(!@{$hash->{cmdStack}}) {
delete($hash->{cmdStack});
diff --git a/fhem/FHEM/98_HMinfo.pm b/fhem/FHEM/98_HMinfo.pm
index 0f2d61baa..e59704d13 100644
--- a/fhem/FHEM/98_HMinfo.pm
+++ b/fhem/FHEM/98_HMinfo.pm
@@ -264,22 +264,39 @@ sub HMinfo_SetFn($@) {#########################################################
}
elsif($cmd eq "protoEvents"){##print protocol-events-------------------------
my @paramList;
+ my @IOlist;
foreach my $dName (HMinfo_getEntities($opt."dv",$filter)){
my $id = $defs{$dName}{DEF};
- my ($found,$para) = HMinfo_getParam($id,"protState","protCmdPend","protSnd",
- "protLastRcv","protResndFail","protResnd","protNack");
+ my ($found,$para) = HMinfo_getParam($id
+ ,"protState","protCmdPend"
+ ,"protSnd","protLastRcv","protResnd"
+ ,"protResndFail","protNack","protIOerr");
$para =~ s/( last_at|20..-|\|)//g;
my @pl = split "\t",$para;
$_ =~ s/\s+$|//g foreach (@pl);
- $para = sprintf("%-20s%-22s|%-18s|%-18s|%-14s|%-18s|%-18s|%-18s",
- $pl[0],$pl[1],$pl[2],$pl[3],$pl[4],$pl[5],$pl[6],$pl[7]);
- push @paramList,$para;
+ push @paramList, sprintf("%-20s%-22s|%-18s|%-18s|%-14s|%-18s|%-18s|%-18s|%-18s",
+ $pl[0],$pl[1],$pl[2],$pl[3],$pl[4],$pl[5],$pl[6],$pl[7],$pl[8]);
+ push @IOlist,$defs{$pl[0]}{IODev}->{NAME};
}
- my $hdr = sprintf("%-20s:%-21s|%-18s|%-18s|%-14s|%-18s|%-18s|%-18s",
- "name","protState","protCmdPend","protSnd",
- "protLastRcv","protResndFail","protResnd","protNack");
+ my $hdr = sprintf("%-20s:%-21s|%-18s|%-18s|%-14s|%-18s|%-18s|%-18s|%-18s",
+ ,"name"
+ ,"protState","protCmdPend"
+ ,"protSnd","protLastRcv","protResnd"
+ ,"protResndFail","protNack","protIOerr");
$ret = $cmd." done:" ."\n ".$hdr ."\n ".(join "\n ",sort @paramList)
;
+ $ret .= "\n\n CUL_HM queue:$modules{CUL_HM}{prot}{rspPend}";
+ $ret .= "\n autoRegRead pending:".
+ join(",",@{$modules{CUL_HM}{helper}{autoRdCfgLst}})
+ if ($modules{CUL_HM}{helper}{autoRdCfgLst});
+ @IOlist = HMinfo_noDup(@IOlist);
+ foreach(@IOlist){
+ $_ .= ":".$defs{$_}{STATE}.
+ (defined $defs{$_}{helper}{q}{answerPend}?
+ " pending=".$defs{$_}{helper}{q}{answerPend} :
+ "");
+ }
+ $ret .= "\n IODevs:".(join"\n ",HMinfo_noDup(@IOlist));
}
elsif($cmd eq "rssi") {##print RSSI protocol-events--------------------
my @rssiList;
@@ -642,18 +659,13 @@ sub HMinfo_status($){##########################################################
push @updates,"ERR_$read:".$d;
}
- my %allE; # remove duplicates
- $allE{$_}=0 foreach (grep !//, @errNames);
- @errNames = sort keys %allE;
+ @errNames = grep !/^$/,HMinfo_noDup(@errNames);
$hash->{ERR_names} = join",",@errNames if(@errNames);# and name entities
-# push @updates,":".$hash->{ERR_names} if(@errNames);
push @updates,"C_sumDefined:"."entities:$nbrE device:$nbrD channel:$nbrC virtual:$nbrV";
# ------- display status of action detector ------
push @updates,"I_actTotal:".$modules{CUL_HM}{defptr}{"000000"}{STATE};
-# push @updates,"ERR_actTotal:".$modules{CUL_HM}{defptr}{"000000"}{STATE};
$hash->{ERRactNames} = join",",@Anames if (@Anames);
-# push @updates,":".$hash->{ERRactNames} if(@Anames);
# ------- what about IO devices??? ------
my %tmp; # remove duplicates
@@ -664,7 +676,6 @@ sub HMinfo_status($){##########################################################
$_ .= " :".$defs{$_}{READINGS}{cond}{VAL};
}
$hash->{I_HM_IOdevices}= join",",@IOdev;
-# push @updates,":".$hash->{I_HM_IOdevices};
# ------- what about protocol events ------
# Current Events are Rcv,NACK,IOerr,Resend,ResendFail,Snd
@@ -676,16 +687,11 @@ sub HMinfo_status($){##########################################################
push @tpw,"$_:$protW{$_}" foreach (grep {$protW{$_}} keys(%protW));
push @updates,"W__protocol:".join",",@tpw if(@tpw);
- my %all; # remove duplicates
- $all{$_}=0 foreach (grep !//,@protNamesE);
- @protNamesE = sort keys %all;
+ @protNamesE = grep !/^$/,HMinfo_noDup(@protNamesE);;
$hash->{ERR__protoNames} = join",",@protNamesE if(@protNamesE);
-# push @updates,":".$hash->{ERR__protoNames} if(@protNamesE);
- $all{$_}=0 foreach (grep !//,@protNamesW);
- @protNamesW = sort keys %all;
+ @protNamesW = grep !/^$/,HMinfo_noDup(@protNamesW);
$hash->{W__protoNames} = join",",@protNamesW if(@protNamesW);
-# push @updates,":".$hash->{W__protoNames} if(@protNamesW);
if (defined $modules{CUL_HM}{helper}{autoRdCfgLst} &&
@{$modules{CUL_HM}{helper}{autoRdCfgLst}}>0){
@@ -1054,6 +1060,14 @@ sub HMinfo_cpRegs(@){#########################################################
my ($ret,undef) = CUL_HM_Set($defs{$dstCh},$dstCh,"regBulk",$srcRegLn,split(" ",$srcData));
return $ret;
}
+sub HMinfo_noDup(@) {#return list with no duplicates
+ my %all;
+ return "" if (scalar(@_) == 0);
+ $all{$_}=0 foreach (grep !/^$/,@_);
+ delete $all{""}; #remove empties if present
+ return (sort keys %all);
+}
+
1;
=pod
=begin html
diff --git a/fhem/FHEM/HMConfig.pm b/fhem/FHEM/HMConfig.pm
index e7d7cec11..981b61abd 100644
--- a/fhem/FHEM/HMConfig.pm
+++ b/fhem/FHEM/HMConfig.pm
@@ -458,7 +458,7 @@ my %culHmRegDefine = (
useCustom =>{a=>110.0,s=>1 ,l=>1,min=>110,max=>310 ,c=>'lit' ,f=>'' ,u=>'' ,d=>1,t=>"use custom" ,lit=>{off=>0,on=>1}},
evtFltrPeriod =>{a=> 1.0,s=>0.4,l=>1,min=>0.5,max=>7.5 ,c=>'' ,f=>2 ,u=>'s' ,d=>1,t=>"event filter period"},
- evtFltrNum =>{a=> 1.4,s=>0.4,l=>1,min=>1 ,max=>15 ,c=>'' ,f=>'' ,u=>'' ,d=>1,t=>"sensitivity - read sach n-th puls"},
+ evtFltrNum =>{a=> 1.4,s=>0.4,l=>1,min=>1 ,max=>15 ,c=>'' ,f=>'' ,u=>'' ,d=>1,t=>"sensitivity - read each n-th puls"},
minInterval =>{a=> 2.0,s=>0.3,l=>1,min=>0 ,max=>4 ,c=>'lit' ,f=>'' ,u=>'' ,d=>1,t=>"minimum interval in sec" ,lit=>{15=>0,30=>1,60=>2,120=>3,240=>4}},
captInInterval =>{a=> 2.3,s=>0.1,l=>1,min=>0 ,max=>1 ,c=>'lit' ,f=>'' ,u=>'' ,d=>1,t=>"capture within interval" ,lit=>{off=>0,on=>1}},
brightFilter =>{a=> 2.4,s=>0.4,l=>1,min=>0 ,max=>7 ,c=>'' ,f=>'' ,u=>'' ,d=>1,t=>"brightness filter - ignore light at night"},