From a1defcef2ad40316f5f5221b7d260233d19bb054 Mon Sep 17 00:00:00 2001 From: martinp876 <> Date: Wed, 30 Oct 2013 10:07:00 +0000 Subject: [PATCH] repeater bugfix, HM manual mode, protocol cleanup git-svn-id: https://svn.fhem.de/fhem/trunk@4135 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/10_CUL_HM.pm | 89 +++++++++++++++++++++++------------------- fhem/FHEM/98_HMinfo.pm | 48 ++++++++++++++++++++--- fhem/FHEM/HMConfig.pm | 4 +- 3 files changed, 92 insertions(+), 49 deletions(-) diff --git a/fhem/FHEM/10_CUL_HM.pm b/fhem/FHEM/10_CUL_HM.pm index 6ce75c4bf..5cafe0cde 100755 --- a/fhem/FHEM/10_CUL_HM.pm +++ b/fhem/FHEM/10_CUL_HM.pm @@ -115,7 +115,6 @@ 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 @@ -144,8 +143,6 @@ sub CUL_HM_Initialize($) { "param msgRepeat ". ".stc .devInfo ". $readingFnAttributes; - $hash->{hmAutoReadScan} = 4; # delay autoConf readings - #autoReadReg: # ,6_allForce # ,4_backUpdt @@ -166,6 +163,9 @@ sub CUL_HM_Initialize($) { $hash->{helper}{qReqConf} = \@confQArr; $hash->{helper}{qReqConfWu} = \@confQWuArr; CUL_HM_initRegHash(); + $hash->{hmIoMaxDly} = 60;# poll timeout - stop poll and discard + $hash->{hmAutoReadScan} = 4; # delay autoConf readings + $hash->{helper}{hmManualOper} = 0;# default automode } sub CUL_HM_updateConfig($){ @@ -1615,10 +1615,12 @@ sub CUL_HM_parseCommon(@){##################################################### $ret = $reply; } elsif($mTp eq "00"){###################################### - CUL_HM_infoUpdtDevData($shash->{NAME}, $shash,$p);#update data - my $iohash = $shash->{IODev}; my $id = CUL_HM_Id($iohash); + CUL_HM_infoUpdtDevData($shash->{NAME}, $shash,$p) + if (!$modules{CUL_HM}{helper}{hmManualOper}#no autoaction + ||$iohash->{hmPair} + ||$iohash->{hmPairSerial} ); if( $dst =~ m /(000000|$id)/ #--- see if we need to pair &&($iohash->{hmPair} @@ -1848,6 +1850,10 @@ sub CUL_HM_parseCommon(@){##################################################### } sub CUL_HM_queueUpdtCfg($){ my $name = shift; + if ($modules{CUL_HM}{helper}{hmManualOper}){ # no update when manual operation + delete $modules{CUL_HM}{helper}{updtCfgLst}; + return; + } my @arr; if ($modules{CUL_HM}{helper}{updtCfgLst}){ @arr = CUL_HM_noDup((@{$modules{CUL_HM}{helper}{updtCfgLst}}, $name)); @@ -2596,7 +2602,6 @@ sub CUL_HM_Set($@) { return "entry must be between 1 and 36" if ($eNo < 1 || $eNo > 36); my $sndID = CUL_HM_name2Id($sId); my $recID = CUL_HM_name2Id($rId); - $sndID = AttrVal($sId,"hmId",""); if ($sndID !~ m/(^[0-9A-F]{6})$/){$sndID = AttrVal($sId,"hmId","");}; if ($recID !~ m/(^[0-9A-F]{6})$/){$recID = AttrVal($rId,"hmId","");}; return "sender ID $sId unknown:".$sndID if ($sndID !~ m/(^[0-9A-F]{6})$/); @@ -3385,12 +3390,12 @@ sub CUL_HM_ProcessCmdStack($) { return; } -sub CUL_HM_prtInit ($){ #setup protocol variables after define +sub CUL_HM_prtInit($){ #setup protocol variables after define my ($hash)=@_; $hash->{helper}{prt}{sProc} = 0; # stack not being processed by now $hash->{helper}{prt}{bErr}=0; } -sub CUL_HM_respWaitSu ($@){ #setup response for multi-message response +sub CUL_HM_respWaitSu($@){ #setup response for multi-message response # single commands # cmd: single msg that needs to be ACKed # mNo: number of message (needs to be in ACK) @@ -3533,11 +3538,11 @@ 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" + if ( $ioHash->{STATE} !~ m/^(opened|Initialized)$/ ||(defined $ioHash->{XmitOpen} && $ioHash->{XmitOpen} == 0) # ||$modules{CUL_HM}{prot}{rspPend}>=$maxPendCmds ){#still no send allowed - if ($modules{CUL_HM}{$io}{tmrStart} < gettimeofday() - $IOpolltout){ + if ($modules{CUL_HM}{$io}{tmrStart} < gettimeofday() - $modules{CUL_HM}{hmIoMaxDly}){ # we need to clean up - this is way to long Stop delay if ($modules{CUL_HM}{$io}{pendDev}) { while(@{$modules{CUL_HM}{$io}{pendDev}}){ @@ -3570,10 +3575,10 @@ sub CUL_HM_SndCmd($$) { || AttrVal($hash->{NAME},"ignore","") || AttrVal($hash->{NAME},"dummy","")); my $ioName = $io->{NAME}; - if ((hex substr($cmd,2,2) & 0x20) && ( # check for commands with resp-req - $io->{STATE} !~ m/^(opened|Initialized)$/ # we need to queue - || $modules{CUL_HM}{$ioName}{tmr} # queue already running - ||(defined $io->{XmitOpen} && $io->{XmitOpen} == 0)#overload, dont send + if ( $io->{STATE} !~ m/^(opened|Initialized)$/ # we need to queue + ||(hex substr($cmd,2,2) & 0x20) && ( # check for commands with resp-req + $modules{CUL_HM}{$ioName}{tmr} # queue already running + ||(defined $io->{XmitOpen} && $io->{XmitOpen} == 0)#overload, dont send ) ){ @@ -3582,7 +3587,7 @@ sub CUL_HM_SndCmd($$) { # 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 + unshift (@{$hash->{cmdStack}}, $cmd);#pushback cmd, wait for opportunity # push device to list if (!defined $modules{CUL_HM}{$ioName}{tmr}){ @@ -3596,7 +3601,6 @@ sub CUL_HM_SndCmd($$) { @{$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 start timer my $tn = gettimeofday(); InternalTimer($tn+$IOpoll, "CUL_HM_sndIfOpen", "sndIfOpen:$ioName", 0); @@ -3633,6 +3637,8 @@ sub CUL_HM_respPendRm($) {#del response related entries in messageing entity $modules{CUL_HM}{prot}{rspPend}-- if($hash->{helper}{prt}{rspWait}{cmd}); delete ($hash->{helper}{prt}{rspWait}); delete $hash->{helper}{tmdOn}; + delete $hash->{helper}{prt}{mmcA}; + delete $hash->{helper}{prt}{mmcS}; RemoveInternalTimer($hash); # remove resend-timer RemoveInternalTimer("respPend:$hash->{DEF}");# remove responsePending timer $respRemoved = 1; @@ -3654,26 +3660,17 @@ sub CUL_HM_respPendTout($) { $pHash->{awake} = 0;# set to asleep CUL_HM_protState($hash,"CMDs_pending"); } + elsif ($hash->{IODev}->{STATE} !~ m/^(opened|Initialized)$/){#IO errors + CUL_HM_eventP($hash,"IOdly"); + CUL_HM_ProcessCmdStack($hash) if(CUL_HM_getRxType($hash) & 0x03); + } elsif ($pHash->{rspWait}{reSent} > AttrVal($hash->{NAME},"msgRepeat",3) # too much ||((CUL_HM_getRxType($hash) & 0x83) == 0)){ #to slow - if ($pHash->{mmcA}){ - #shall we re-insert commands? - #unshift @{$hash->{cmdStack}},@{$pHash->{mmcA}}; - delete $pHash->{mmcA}; - delete $pHash->{mmcS}; - } - - if ($hash->{IODev}->{STATE} !~ m/^(opened|Initialized)$/){#IO errors - CUL_HM_eventP($hash,"IOerr"); - readingsSingleUpdate($hash,"state","IOerr",1); - } - else{ - my $pendCmd = ($pHash->{rspWait}{Pending} + my $pendCmd = ($pHash->{rspWait}{Pending} ?"RESPONSE TIMEOUT:".$pHash->{rspWait}{Pending} :"MISSING ACK");# save before remove - CUL_HM_eventP($hash,"ResndFail"); - readingsSingleUpdate($hash,"state",$pendCmd,1); - } + CUL_HM_eventP($hash,"ResndFail"); + readingsSingleUpdate($hash,"state",$pendCmd,1); CUL_HM_ProcessCmdStack($hash); # continue processing commands if any } else{# manage retries @@ -3682,7 +3679,8 @@ sub CUL_HM_respPendTout($) { $pHash->{rspWait}{reSent}++; my (undef,$addr,$msg) = unpack 'A10A12A*',$hash->{helper}{prt}{rspWait}{cmd}; - $pHash->{rspWaitSec}{$_} = $pHash->{rspWait}{$_} foreach (keys%{$pHash->{rspWait}}); ; + $pHash->{rspWaitSec}{$_} = $pHash->{rspWait}{$_} + foreach (keys%{$pHash->{rspWait}}); CUL_HM_SndCmd($hash,"++B112$addr"); $hash->{helper}{prt}{awake}=4;# start re-wakeup } @@ -3717,16 +3715,24 @@ sub CUL_HM_eventP($$) {#handle protocol events $nAttr->{"prot".$evntType} = ++$evntCnt." last_at:".TimeNow(); if ($evntType =~ m/(Nack|ResndFail|IOerr)/){# unrecoverable Error + readingsSingleUpdate($hash,"state",$evntType,1); $hash->{helper}{prt}{bErr}++; - $nAttr->{protCmdDel}++; - if ( (CUL_HM_getRxType($hash) & 0x01) == 0 #to slow for wakeup and config - #no retry for burst either - || $evntType eq "IOerr"){ #IO problem - $nAttr->{protCmdDel} = 0 if(!$nAttr->{protCmdDel}); - $nAttr->{protCmdDel} += scalar @{$hash->{cmdStack}} + $nAttr->{protCmdDel} = 0 if(!$nAttr->{protCmdDel}); + $nAttr->{protCmdDel} += scalar @{$hash->{cmdStack}} + 1 if ($hash->{cmdStack}); - CUL_HM_protState($hash,"CMDs_done".($hash->{helper}{prt}{bErr}? - ("_Errors:".$hash->{helper}{prt}{bErr}):"")); + CUL_HM_protState($hash,"CMDs_done".($hash->{helper}{prt}{bErr}? + ("_Errors:".$hash->{helper}{prt}{bErr}):"")); + CUL_HM_respPendRm($hash); + } + elsif($evntType eq "IOdly"){ # IO problem - will see whether it recovers + my $pHash = $hash->{helper}{prt}; + if ($pHash->{mmcA}){ + unshift @{$hash->{cmdStack}},$_ foreach (reverse@{$pHash->{mmcA}}); + delete $pHash->{mmcA}; + delete $pHash->{mmcS}; + } + else{ + unshift @{$hash->{cmdStack}}, $pHash->{rspWait}{cmd};#pushback } CUL_HM_respPendRm($hash); } @@ -4804,6 +4810,7 @@ sub CUL_HM_unQEntity($$){# remove entity from q - task no longer necesary } sub CUL_HM_qEntity($$){ my ($name,$q) = @_; + return if ($modules{CUL_HM}{helper}{hmManualOper});#no autoaction when manual $q = $modules{CUL_HM}{helper}{$q}; return if (AttrVal($name,"subType","") eq "virtual"); if ($defs{$name}{helper}{role}{dev}){ diff --git a/fhem/FHEM/98_HMinfo.pm b/fhem/FHEM/98_HMinfo.pm index 2046df7de..d3bed9c57 100644 --- a/fhem/FHEM/98_HMinfo.pm +++ b/fhem/FHEM/98_HMinfo.pm @@ -23,11 +23,12 @@ sub HMinfo_Initialize($$) {#################################################### $hash->{DefFn} = "HMinfo_Define"; $hash->{SetFn} = "HMinfo_SetFn"; $hash->{AttrFn} = "HMinfo_Attr"; - $hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 ". - "sumStatus sumERROR ". - "autoUpdate ". - "hmAutoReadScan ". - $readingFnAttributes; + $hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 " + ."sumStatus sumERROR " + ."autoUpdate " + ."hmAutoReadScan hmIoMaxDly " + ."hmManualOper:0_auto,1_manual " + .$readingFnAttributes; } sub HMinfo_Define($$){######################################################### @@ -69,7 +70,7 @@ sub HMinfo_Attr(@) {################################# $hash->{helper}{autoUpdate} = $sec; InternalTimer(gettimeofday()+$sec,"HMinfo_autoUpdate","sUpdt:".$name,0); } - elsif ($attrName eq "hmAutoReadScan"){# 00:00 hh:mm + elsif($attrName eq "hmAutoReadScan"){# 00:00 hh:mm if ($cmd eq "del"){ $modules{CUL_HM}{hmAutoReadScan} = 4;# return to default } @@ -83,6 +84,29 @@ sub HMinfo_Attr(@) {################################# CUL_HM_queueAutoRead(""); #will restart timer } } + elsif($attrName eq "hmIoMaxDly"){# + if ($cmd eq "del"){ + $modules{CUL_HM}{hmIoMaxDly} = 60;# return to default + } + else{ + return "please add plain integer between 0 and 3600" + if ( $attrVal !~ m/^(\d+)$/ + ||$attrVal<0 + ||$attrVal >3600 ); + ## implement new timer to CUL_HM + $modules{CUL_HM}{hmIoMaxDly}=$attrVal; + } + } + elsif($attrName eq "hmManualOper"){# 00:00 hh:mm + if ($cmd eq "del"){ + $modules{CUL_HM}{helper}{hmManualOper} = 0;# default automode + } + else{ + return "please set 0 or 1" if ($attrVal !~ m/^(0|1)/); + ## implement new timer to CUL_HM + $modules{CUL_HM}{helper}{hmManualOper} = substr($attrVal,0,1); + } + } return; } sub HMinfo_autoUpdate($){#in:name, send status-request @@ -1359,6 +1383,18 @@ sub HMinfo_noDup(@) {#return list with no duplicates Note that compressing will increase message load while stretch will extent waiting time. data.
+
  • hmIoMaxDly + max time in seconds CUL_HM stacks messages if the IO device is not ready to send. + If the IO device will not reappear in time all command will be deleted and IOErr will be reported.
    + Note: commands will be executed after the IO device reappears - which could lead to unexpected + activity long after command issue.
    + default is 60sec. max value is 3600sec
    +
  • +
  • hmManualOper + set to 1 will prevent any automatic operation, update or default settings + in CUL_HM.
    +
  • +
    Variables diff --git a/fhem/FHEM/HMConfig.pm b/fhem/FHEM/HMConfig.pm index 93cc2fcd5..ea576684f 100644 --- a/fhem/FHEM/HMConfig.pm +++ b/fhem/FHEM/HMConfig.pm @@ -1342,8 +1342,8 @@ my %culHmBits = ( BUTTON => '00,2,$val=(hex($val)&0x3F)', LONG => '00,2,$val=(hex($val)&0x40)?1:0', LOWBAT => '00,2,$val=(hex($val)&0x80)?1:0', - VALUE => '02,2,$val=(hex($val))', - NEXT => '04,2,$val=(hex($val))',} }, + NBR => '02,2,$val=(hex($val))', + VALUE => '04,2,$val=(hex($val))',} }, "53" => { txt => "SensorData" , params => { CMD => "00,2", Fld1=> "02,2",