2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-19 18:56:03 +00:00

AES enhanvement HMLAN, preparation for condBurst r-wakeup

git-svn-id: https://svn.fhem.de/fhem/trunk@3968 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
martinp876 2013-09-28 14:49:43 +00:00
parent 5fb3e461bd
commit 09ec5be2a6
4 changed files with 333 additions and 275 deletions

View File

@ -148,21 +148,34 @@ sub HMLAN_Attr(@) {#################################
elsif($attrName =~ m /^hmKey/){
my $retVal= "";
if ($cmd eq "set"){
$attr{$name}{$attrName} = ($aVal =~ m /^[0-9A-Fa-f]{32}$/ )?
$aVal:
unpack('H*', md5($aVal));
my $kno = ($attrName eq "hmKey")?1:substr($attrName,5,1);
my ($no,$val) = (sprintf("%02X",$kno),$aVal);
if ($aVal =~ m/:/){#number given
($no,$val) = split ":",$aVal;
return "illegal number:$no" if (hex($no) < 1 || hex($no) > 255 || length($no) != 2);
}
$attr{$name}{$attrName} = "$no:".
(($val =~ m /^[0-9A-Fa-f]{32}$/ )?
$val:
unpack('H*', md5($val)));
$retVal = "$attrName set to $attr{$name}{$attrName}";
}
else{
delete $attr{$name}{$attrName};
}
my ($k1,$k2,$k3) =( AttrVal($name,"hmKey","")
,AttrVal($name,"hmKey2","")
,AttrVal($name,"hmKey3","")
my ($k1no,$k1,$k2no,$k2,$k3no,$k3)
=( "01",AttrVal($name,"hmKey","")
,"02",AttrVal($name,"hmKey2","")
,"03",AttrVal($name,"hmKey3","")
);
HMLAN_SimpleWrite($defs{$name}, "Y01,".($k1?"01,$k1":"00,"));
HMLAN_SimpleWrite($defs{$name}, "Y02,".($k2?"02,$k2":"00,"));
HMLAN_SimpleWrite($defs{$name}, "Y03,".($k3?"03,$k3":"00,"));
if ($k1 =~ m/:/){($k1no,$k1) = split(":",$k1);}
if ($k2 =~ m/:/){($k2no,$k2) = split(":",$k2);}
if ($k3 =~ m/:/){($k3no,$k3) = split(":",$k3);}
HMLAN_SimpleWrite($defs{$name}, "Y01,".($k1?"$k1no,$k1":"00,"));
HMLAN_SimpleWrite($defs{$name}, "Y02,".($k2?"$k2no,$k2":"00,"));
HMLAN_SimpleWrite($defs{$name}, "Y03,".($k3?"$k3no,$k3":"00,"));
return $retVal;
}
return;
@ -567,17 +580,24 @@ sub HMLAN_DoInit($) {##########################################################
my $name = $hash->{NAME};
my $id = AttrVal($name, "hmId", undef);
my $key = AttrVal($name, "hmKey", ""); # 36(!) hex digits
my ($k1no,$k1,$k2no,$k2,$k3no,$k3)
=( "01",AttrVal($name,"hmKey","")
,"02",AttrVal($name,"hmKey2","")
,"03",AttrVal($name,"hmKey3","")
);
if ($k1 =~ m/:/){($k1no,$k1) = split(":",$k1);}
if ($k2 =~ m/:/){($k2no,$k2) = split(":",$k2);}
if ($k3 =~ m/:/){($k3no,$k3) = split(":",$k3);}
my $s2000 = sprintf("%02X", HMLAN_secSince2000());
delete $hash->{READINGS}{state};
HMLAN_SimpleWrite($hash, "A$id") if($id);
HMLAN_SimpleWrite($hash, "C");
HMLAN_SimpleWrite($hash, "Y01,01,$key");
HMLAN_SimpleWrite($hash, "Y02,00,");
HMLAN_SimpleWrite($hash, "Y03,00,");
HMLAN_SimpleWrite($hash, "Y03,00,");
HMLAN_SimpleWrite($defs{$name}, "Y01,".($k1?"$k1no,$k1":"00,"));
HMLAN_SimpleWrite($defs{$name}, "Y02,".($k2?"$k2no,$k2":"00,"));
HMLAN_SimpleWrite($defs{$name}, "Y03,".($k3?"$k3no,$k3":"00,"));
HMLAN_SimpleWrite($hash, "T$s2000,04,00,00000000");
delete $hash->{helper}{ref};

View File

@ -64,7 +64,6 @@ sub CUL_HM_respPendToutProlong($);
sub CUL_HM_PushCmdStack($$);
sub CUL_HM_ProcessCmdStack($);
sub CUL_HM_pushConfig($$$$$$$$@);
sub CUL_HM_Resend($);
sub CUL_HM_ID2PeerList ($$$);
sub CUL_HM_peerChId($$$);
sub CUL_HM_peerChName($$$);
@ -328,6 +327,7 @@ sub CUL_HM_Define($$) {##############################
else{# define a device
$hash->{helper}{role}{dev}=1;
$hash->{helper}{role}{chn}=1;# take role of chn 01 until it is defined
CUL_HM_prtInit ($hash);
AssignIoPort($hash);
}
$modules{CUL_HM}{defptr}{$HMid} = $hash;
@ -831,7 +831,7 @@ sub CUL_HM_Parse($$) {##############################
}
elsif($md eq "HM-CC-RT-DN") { ###############################################
my %ctlTbl=( 0=>"auto", 1=>"manu", 2=>"party",3=>"boost");
if($mTp eq "10" && $p =~ m/^0A(....)(..)(..)(..)/) {#info-level
if ($mTp eq "10" && $p =~ m/^0A(....)(..)(..)(..)/) {#info-level
my ($chn,$setTemp,$actTemp,$err,$bat,$vp,$ctrlMode) =
("04",hex($1),hex($1),hex($2),hex($2),hex($3), hex($4));
$setTemp =(($setTemp >>10) & 0x3f )/2;
@ -851,6 +851,10 @@ sub CUL_HM_Parse($$) {##############################
,3=>"adjustRangeTooSmall" , 4=>"communicationERR"
,5=>"unknown" , 6=>"lowBat" , 7=>"ValveErrorPosition" );
"measured-temp:$actTemp";
"desired-temp:$setTemp";
"ValvePosition:$vp %";
push @event, "motorErr:$errTbl{$err}";
push @event, "measured-temp:$actTemp";
push @event, "desired-temp:$setTemp";
@ -862,6 +866,9 @@ sub CUL_HM_Parse($$) {##############################
push @entities,CUL_HM_UpdtReadBulk($dHash,1
,"battery:".($err&0x80?"low":"ok")
,"batteryLevel:$bat V"
,"measured-temp:$actTemp" # values to please HCS
,"desired-temp:$setTemp"
,"actuator:$vp %"
);
}
elsif($mTp eq "59" && $p =~ m/^(..)/) {#inform team about new value
@ -1319,7 +1326,7 @@ sub CUL_HM_Parse($$) {##############################
#C7: tone off
#01: no alarm
my ($No,$state) = (substr($p,2,2),substr($p,4,2));
if(($dhash && $dname ne $name) && # update source(ID is reported in $dst...)
if(($dhash && $dname ne $name) && # update source(ID reported in $dst)
(!$dhash->{helper}{alarmNo} || $dhash->{helper}{alarmNo} ne $No)){
$dhash->{helper}{alarmNo} = $No;
push @entities,
@ -1518,8 +1525,8 @@ sub CUL_HM_Parse($$) {##############################
sprintf("%02X",$vp*2)."0000";
}
elsif($mTp eq "02"){
if ($dhash->{helper}{respWait}{mNo} &&
$dhash->{helper}{respWait}{mNo} eq $mNo ){
if ($dhash->{helper}{prt}{rspWait}{mNo} &&
$dhash->{helper}{prt}{rspWait}{mNo} eq $mNo ){
#ack we waited for - stop Waiting
CUL_HM_respPendRm($dhash);
}
@ -1575,8 +1582,8 @@ sub CUL_HM_parseCommon(@){#####################################################
my $dhash = $modules{CUL_HM}{defptr}{$dst};
return "" if(!$shash->{DEF});# this should be from ourself
my $ret = "";
my $pendType = $shash->{helper}{respWait}{Pending}?
$shash->{helper}{respWait}{Pending}:"";
my $pendType = $shash->{helper}{prt}{rspWait}{Pending}?
$shash->{helper}{prt}{rspWait}{Pending}:"";
#------------ parse message flag for start processing command Stack
# TC wakes up with 8270, not with A258
# VD wakes up with 8202
@ -1596,13 +1603,16 @@ sub CUL_HM_parseCommon(@){#####################################################
my $reply;
my $success;
if ($shash->{helper}{respWait}{wakeup}){
if ($shash->{helper}{respWait}{mNo} eq $mNo &&
if ($shash->{helper}{prt}{rspWait}{wakeup}){
if ($shash->{helper}{prt}{rspWait}{mNo} eq $mNo &&
$subType eq "00" ){
$shash->{protCondBurst} = "on";
$shash->{helper}{prt}{awake}=2;#awake
}
else{
$shash->{protCondBurst} = "off";
$shash->{helper}{prt}{awake}=3;#reject
return "done";
}
}
@ -1622,8 +1632,8 @@ sub CUL_HM_parseCommon(@){#####################################################
$reply = "ACKStatus";
if ($shash->{helper}{tmdOn}){
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",
my ($pre,$nbr,$msg) = unpack 'A4A2A*',$shash->{helper}{prt}{rspWait}{cmd};
$shash->{helper}{prt}{rspWait}{cmd} = sprintf("%s%02X%s",
$pre,hex($nbr)+1,$msg);
CUL_HM_eventP($shash,"TimedOn");
$success = "no";
@ -1653,7 +1663,7 @@ sub CUL_HM_parseCommon(@){#####################################################
}
elsif($mTp eq "00"){######################################
if ($pendType eq "PairSerial"){
if($shash->{helper}{respWait}{forChn} = substr($p,6,20)){
if($shash->{helper}{prt}{rspWait}{forChn} = substr($p,6,20)){
CUL_HM_respPendRm($shash);
}
}
@ -1673,7 +1683,7 @@ sub CUL_HM_parseCommon(@){#####################################################
}
elsif($subType eq "01"){ #storePeerList#################
if ($pendType eq "PeerList"){
my $chn = $shash->{helper}{respWait}{forChn};
my $chn = $shash->{helper}{prt}{rspWait}{forChn};
my $chnhash = $modules{CUL_HM}{defptr}{$src.$chn};
$chnhash = $shash if (!$chnhash);
my $chnNname = $chnhash->{NAME};
@ -1711,12 +1721,12 @@ sub CUL_HM_parseCommon(@){#####################################################
}
elsif($subType eq "02" ||$subType eq "03"){ #ParamResp==================
if ($pendType eq "RegisterRead"){
my $chnSrc = $src.$shash->{helper}{respWait}{forChn};
my $chnSrc = $src.$shash->{helper}{prt}{rspWait}{forChn};
my $chnHash = $modules{CUL_HM}{defptr}{$chnSrc};
$chnHash = $shash if (!$chnHash);
my $chnName = $chnHash->{NAME};
my ($format,$data) = ($1,$2) if ($p =~ m/^(..)(.*)/);
my $list = $shash->{helper}{respWait}{forList};
my $list = $shash->{helper}{prt}{rspWait}{forList};
$list = "00" if (!$list); #use the default
if ($format eq "02"){ # list 2: format aa:dd aa:dd ...
$data =~ s/(..)(..)/ $1:$2/g;
@ -1737,7 +1747,7 @@ sub CUL_HM_parseCommon(@){#####################################################
}
}
my $peer = $shash->{helper}{respWait}{forPeer};
my $peer = $shash->{helper}{prt}{rspWait}{forPeer};
my $regLNp = "RegL_$list:$peer";# pure, no expert
my $regLN = ((CUL_HM_getAttrInt($chnName,"expert") == 2)?"":".").$regLNp;
readingsSingleUpdate($chnHash,$regLN,
@ -1801,7 +1811,7 @@ sub CUL_HM_parseCommon(@){#####################################################
@{$modules{CUL_HM}{helper}{reqStatus}} = grep { $_ ne $shash->{NAME} }
@{$modules{CUL_HM}{helper}{reqStatus}};
if ($pendType eq "StatusReq"){#it is the answer to our request
my $chnSrc = $src.$shash->{helper}{respWait}{forChn};
my $chnSrc = $src.$shash->{helper}{prt}{rspWait}{forChn};
my $chnhash = $modules{CUL_HM}{defptr}{$chnSrc};
$chnhash = $shash if (!$chnhash);
CUL_HM_respPendRm($shash);
@ -1848,8 +1858,8 @@ sub CUL_HM_parseCommon(@){#####################################################
# CUL_HM_ProcessCmdStack($shash);
}
if ($shash->{helper}{respWait}{mNo} &&
$shash->{helper}{respWait}{mNo} eq $mNo &&
if ($shash->{helper}{prt}{rspWait}{mNo} &&
$shash->{helper}{prt}{rspWait}{mNo} eq $mNo &&
!$repeat){
#response we waited for - stop Waiting
CUL_HM_respPendRm($shash);
@ -3122,9 +3132,10 @@ sub CUL_HM_Set($@) {
}
elsif(($rxType & 0x80) && #burstConditional - have a try
$devHash->{cmdStack} &&
!$devHash->{helper}{respWait}{cmd} &&
!$devHash->{helper}{respWait}{Pending}
!$devHash->{helper}{prt}{rspWait}{cmd}
){
# Log 1,"General !!!!!! wakeup but stack processing $name" if($devHash->{helper}{prt}{sProc});
$hash->{helper}{prt}{awake}=1;# start wakeup
CUL_HM_SndCmd($devHash,"++B112$id$dst");
}
return ("",1);# no not generate trigger outof command
@ -3288,6 +3299,208 @@ sub CUL_HM_getConfig($$$$$){
}
#+++++++++++++++++ Protocol stack, sending, repeat+++++++++++++++++++++++++++++
sub CUL_HM_pushConfig($$$$$$$$@) {#generate messages to config data to register
my ($hash,$src,$dst,$chn,$peerAddr,$peerChn,$list,$content,$prep) = @_;
my $flag = CUL_HM_getFlag($hash);
my $tl = length($content);
$chn = sprintf("%02X",$chn);
$peerChn = sprintf("%02X",$peerChn);
$list = sprintf("%02X",$list);
# --store pending changes in shadow to handle bit manipulations cululativ--
$peerAddr = "000000" if(!$peerAddr);
my $peerN = ($peerAddr ne "000000")?CUL_HM_peerChName($peerAddr.$peerChn,$dst,""):"";
$peerN =~ s/broadcast//;
$peerN =~ s/ /_/g;#remote blanks
my $regLN = ((CUL_HM_getAttrInt($hash->{NAME},"expert") == 2)?"":".").
"RegL_".$list.":".$peerN;
#--- copy data from readings to shadow
my $chnhash = $modules{CUL_HM}{defptr}{$dst.$chn};
$chnhash = $hash if (!$chnhash);
if (!$chnhash->{helper}{shadowReg} ||
!$chnhash->{helper}{shadowReg}{$regLN}){
$chnhash->{helper}{shadowReg}{$regLN} =
ReadingsVal($chnhash->{NAME},$regLN,"");
}
#--- update with ne value
my $regs = $chnhash->{helper}{shadowReg}{$regLN};
for(my $l = 0; $l < $tl; $l+=4) { #substitute changed bytes in shadow
my $addr = substr($content,$l,2);
my $data = substr($content,$l+2,2);
if(!$regs || !($regs =~ s/$addr:../$addr:$data/)){
$regs .= " ".$addr.":".$data;
}
}
$chnhash->{helper}{shadowReg}{$regLN} = $regs;
return if ($prep);#prepare shadowReg only. More data to come.
#Application takes care about execution
CUL_HM_updtRegDisp($hash,$list,$peerAddr.$peerChn);
CUL_HM_PushCmdStack($hash, "++".$flag.'01'.$src.$dst.$chn.'05'.
$peerAddr.$peerChn.$list);
for(my $l = 0; $l < $tl; $l+=28) {
my $ml = $tl-$l < 28 ? $tl-$l : 28;
CUL_HM_PushCmdStack($hash, "++A001".$src.$dst.$chn."08".
substr($content,$l,$ml));
}
CUL_HM_PushCmdStack($hash,"++A001".$src.$dst.$chn."06");
CUL_HM_queueAutoRead($hash->{NAME})
if (2 < CUL_HM_getAttrInt($hash->{NAME},"autoReadReg"));
}
sub CUL_HM_PushCmdStack($$) {
my ($chnhash, $cmd) = @_;
my @arr = ();
my $hash = CUL_HM_getDeviceHash($chnhash);
my $name = $hash->{NAME};
if(!$hash->{cmdStack}){
$hash->{cmdStack} = \@arr;
delete ($hash->{helper}{burstEvtCnt}) if (!$hash->{helper}{prt}{rspWait});
}
push(@{$hash->{cmdStack}}, $cmd);
my $entries = scalar @{$hash->{cmdStack}};
$hash->{protCmdPend} = $entries." CMDs_pending";
CUL_HM_protState($hash,"CMDs_pending") if(!$hash->{helper}{prt}{rspWait}{cmd});
}
sub CUL_HM_ProcessCmdStack($) {
my ($chnhash) = @_;
my $hash = CUL_HM_getDeviceHash($chnhash);
# Log 1,"General proc starting $hash->{NAME}" if($hash->{cmdStack} && !$hash->{helper}{prt}{sProc});
# Log 1,"General proc ERROR $hash->{NAME}" if($hash->{helper}{prt}{rspWait}{cmd} && !$hash->{helper}{prt}{sProc});
# General need to add wakeup here. Only one wakeup per stack processing!
if($hash->{cmdStack} && !$hash->{helper}{prt}{rspWait}{cmd}){
if(@{$hash->{cmdStack}}) {
# Log 1,"General proc send $hash->{NAME}";
CUL_HM_SndCmd($hash, shift @{$hash->{cmdStack}});
}
elsif(!@{$hash->{cmdStack}}) {
delete($hash->{cmdStack});
delete($hash->{protCmdPend});
#-- update info ---
CUL_HM_protState($hash,"CMDs_done".($hash->{helper}{burstEvtCnt}?
("_events:".$hash->{helper}{burstEvtCnt}):""));
}
}
return;
}
sub CUL_HM_prtInit ($){ #setup protocol variables after define
my ($hash)=@_;
$hash->{helper}{prt}{sProc} = 0; # stack not being processed by now
}
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)
# mNoWu: number of message if wakeup
# reSent: number of resends already done - usually init with 1
# wakeup: was wakeup message (burst devices)
#
# commands with multi-message answer
# PendCmd: command message
# Pending: type of answer we are awaiting
# forChn: which channel are we working on?
# forList: which list are we waiting for? (optional)
# forPeer: which peer are we waiting for? (optional)
my ($hash,@a)=@_;
my $mHsh = $hash->{helper}{prt};
$modules{CUL_HM}{prot}{rspPend}++ if(!$mHsh->{rspWait}{cmd});
foreach (@a){
my ($f,$d)=split ":",$_;
$mHsh->{rspWait}{$f}=$d;
}
my $to = gettimeofday() + (($mHsh->{rspWait}{Pending})?rand(20)/10+4:
rand(40)/10+1);
InternalTimer($to,"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
if (($mFlg & 0x20) && ($dst ne '000000')){
if ($mTp eq "01" && $subType){
if ($subType eq "03"){ #PeerList-----------
#--- remember request params in device level
CUL_HM_respWaitSu ($hash,"Pending:PeerList"
,"cmd:$cmd" ,"forChn:".substr($p,0,2)
,"reSent:1");
#--- remove readings in channel
my $chnhash = $modules{CUL_HM}{defptr}{"$dst$chn"};
$chnhash = $hash if (!$chnhash);
delete $chnhash->{READINGS}{peerList};#empty old list
delete $chnhash->{peerList};#empty old list
delete $chnhash->{helper}{peerIDsRaw};
$attr{$chnhash->{NAME}}{peerIDs} = '';
return;
}
elsif($subType eq "04"){ #RegisterRead-------
my ($peer, $list) = ($1,$2) if ($p =~ m/..04(........)(..)/);
$peer = ($peer ne "00000000")?CUL_HM_peerChName($peer,$dst,""):"";
#--- set messaging items
CUL_HM_respWaitSu ($hash,"Pending:RegisterRead"
,"cmd:$cmd" ,"forChn:$chn"
,"forList:$list","forPeer:$peer"
,"reSent:1");
#--- remove channel entries that will be replaced
my $chnhash = $modules{CUL_HM}{defptr}{"$dst$chn"};
$chnhash = $hash if(!$chnhash);
$peer ="" if($list !~ m/^0[34]$/);
#empty val since reading will be cumulative
my $rlName = ((CUL_HM_getAttrInt($chnhash->{NAME},"expert") == 2)?"":".")."RegL_".$list.":".$peer;
$chnhash->{READINGS}{$rlName}{VAL}="";
delete ($chnhash->{READINGS}{$rlName}{TIME});
return;
}
# elsif($subType eq "0A"){ #Pair Serial----------
# #--- set messaging items
# $hash->{helper}{prt}{rspWait}{Pending} = "PairSerial";
# $hash->{helper}{prt}{rspWait}{cmd} = $cmd;
# $hash->{helper}{prt}{rspWait}{forChn} = substr($p,4,20);
#
# # define timeout - holdup cmdStack until response complete or timeout
# InternalTimer(gettimeofday()+$rTo, "CUL_HM_respPendTout", "respPend:$dst", 0);
# return;
# }
}
elsif($mTp eq '11' && $chn =~ m/^(02|81)$/){#!!! chn is subtype!!!
CUL_HM_qStateUpdatIfEnab($dst);
}
elsif($mTp eq '12' && $mFlg & 0x10){#wakeup with burst
# response setup - do not repeat, set counter to 250
CUL_HM_respWaitSu ($hash,"cmd:$cmd","mNo:$mNo","reSent:250","wakeup:1");
return;
}
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)/);
}
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}}){
CUL_HM_protState($hash,"CMDs_processing...");
InternalTimer(gettimeofday()+.5, "CUL_HM_ProcessCmdStack", $hash, 0);
}
else{
CUL_HM_protState($hash,"CMDs_done".($hash->{helper}{burstEvtCnt}?
("_events:".$hash->{helper}{burstEvtCnt}):""));
}
}
if($hash->{cmdStack} && scalar @{$hash->{cmdStack}}){
$hash->{protCmdPend} = scalar @{$hash->{cmdStack}}." CMDs pending";
}
else{
delete($hash->{protCmdPend});
}
}
sub CUL_HM_sndIfOpen($) {
my(undef,$io) = split(':',$_[0]);
RemoveInternalTimer("sndIfOpen:$io");# should not be necessary, but
@ -3383,103 +3596,58 @@ sub CUL_HM_SndCmd($$) {
$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(!$hash->{helper}{respWait}{PendCmd} &&
!$hash->{helper}{respWait}{cmd});
foreach (@a){
my ($f,$d)=split ":",$_;
$hash->{helper}{respWait}{$f}=$d;
}
if ($hash->{helper}{respWait}{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_respPendRm($) {#del response related entries in messageing entity
my ($hash) = @_;
$modules{CUL_HM}{prot}{rspPend}-- if($hash->{helper}{prt}{rspWait}{cmd});
delete ($hash->{helper}{prt}{rspWait});
delete $hash->{helper}{tmdOn};
RemoveInternalTimer($hash); # remove resend-timer
RemoveInternalTimer("respPend:$hash->{DEF}");# remove responsePending timer
$respRemoved = 1;
}
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
if (($mFlg & 0x20) && ($dst ne '000000')){
if ($mTp eq "01" && $subType){
if ($subType eq "03"){ #PeerList-----------
#--- remember request params in device level
CUL_HM_respWaitSu ($hash,"Pending:PeerList"
,"PendCmd:$cmd" ,"forChn:".substr($p,0,2));
sub CUL_HM_respPendTout($) {
my ($HMid) = @_;
(undef,$HMid) = split(":",$HMid,2);
my $hash = $modules{CUL_HM}{defptr}{$HMid};
my $pHash = $hash->{helper}{prt};#shortcut
#--- remove readings in channel
my $chnhash = $modules{CUL_HM}{defptr}{"$dst$chn"};
$chnhash = $hash if (!$chnhash);
delete $chnhash->{READINGS}{peerList};#empty old list
delete $chnhash->{peerList};#empty old list
delete $chnhash->{helper}{peerIDsRaw};
$attr{$chnhash->{NAME}}{peerIDs} = '';
return;
}
elsif($subType eq "04"){ #RegisterRead-------
my ($peer, $list) = ($1,$2) if ($p =~ m/..04(........)(..)/);
$peer = ($peer ne "00000000")?CUL_HM_peerChName($peer,$dst,""):"";
#--- set messaging items
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);
if ($hash && $hash->{DEF} ne '000000'){
my $name = $hash->{NAME};
$pHash->{awake} = 0 if (defined $pHash->{awake});# set to asleep
return if(!$pHash->{rspWait}{reSent}); # Double timer?
$peer ="" if($list !~ m/^0[34]$/);
#empty val since reading will be cumulative
my $rlName = ((CUL_HM_getAttrInt($chnhash->{NAME},"expert") == 2)?"":".")."RegL_".$list.":".$peer;
$chnhash->{READINGS}{$rlName}{VAL}="";
delete ($chnhash->{READINGS}{$rlName}{TIME});
return;
}
# elsif($subType eq "0A"){ #Pair Serial----------
# #--- set messaging items
# $hash->{helper}{respWait}{Pending} = "PairSerial";
# $hash->{helper}{respWait}{PendCmd} = $cmd;
# $hash->{helper}{respWait}{forChn} = substr($p,4,20);
#
# # define timeout - holdup cmdStack until response complete or timeout
# InternalTimer(gettimeofday()+$rTo, "CUL_HM_respPendTout", "respPend:$dst", 0);
# return;
# }
}
elsif($mTp eq '11' && $chn =~ m/^(02|81)$/){#!!! chn is subtype!!!
CUL_HM_qStateUpdatIfEnab($dst);
}
elsif($mTp eq '12' && $mFlg & 0x10){#wakeup with burst
# response setup - do not repeat, set counter to 250
CUL_HM_respWaitSu ($hash,"cmd:$cmd","mNo:$mNo","reSent:250","wakeup:1");
return;
}
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)/);
}
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}}){
CUL_HM_protState($hash,"CMDs_processing...");
InternalTimer(gettimeofday()+.5, "CUL_HM_ProcessCmdStack", $hash, 0);
if ($pHash->{rspWait}{reSent} > AttrVal($hash->{NAME},"msgRepeat",3)
&&( ((CUL_HM_getRxType($hash) & 0x03) != 0)#to slow for wakeup/config
||($hash->{protCondBurst}&&$hash->{protCondBurst} eq "on" ))){
if ($pHash->{rspWait}{wakeup}){
CUL_HM_respPendRm($hash);# do not count problems with wakeup try, just wait
$hash->{protCondBurst} = "off";
}
else{
CUL_HM_protState($hash,"CMDs_done".($hash->{helper}{burstEvtCnt}?
("_events:".$hash->{helper}{burstEvtCnt}):""));
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_ProcessCmdStack($hash); # continue processing commands if any
}
}
if($hash->{cmdStack} && scalar @{$hash->{cmdStack}}){
$hash->{protCmdPend} = scalar @{$hash->{cmdStack}}." CMDs pending";
}
else{
delete($hash->{protCmdPend});
CUL_HM_eventP($hash,"Resnd");
IOWrite($hash, "", $pHash->{rspWait}{cmd});
$pHash->{rspWait}{reSent}++;
Log GetLogLevel($name,4),"CUL_HM_Resend: ".$name. " nr ".$pHash->{rspWait}{reSent};
InternalTimer(gettimeofday()+rand(20)/10+4,"CUL_HM_respPendTout","respPend:$hash->{DEF}", 0);
}
}
}
sub CUL_HM_respPendToutProlong($) {#used when device sends part responses
my ($hash) = @_;
RemoveInternalTimer("respPend:$hash->{DEF}");
InternalTimer(gettimeofday()+1, "CUL_HM_respPendTout", "respPend:$hash->{DEF}", 0);
}
sub CUL_HM_eventP($$) {#handle protocol events
# Current Events are Rcv,NACK,IOerr,Resend,ResendFail,Snd
# additional variables are protCmdDel,protCmdPend,protState,protLastRcv
@ -3519,152 +3687,16 @@ sub CUL_HM_protState($$){
Log GetLogLevel($name,6),"CUL_HM $name protEvent:$state".
($hash->{cmdStack}?" pending:".scalar @{$hash->{cmdStack}}:"");
DoTrigger($name, undef) if ($state =~ m/^CMDs_done/);
}
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
RemoveInternalTimer("respPend:$hash->{DEF}");# remove responsePending timer
$respRemoved = 1;
}
sub CUL_HM_respPendTout($) {
my ($HMid) = @_;
$HMid =~ s/.*://; #remove timer identifier
my $hash = $modules{CUL_HM}{defptr}{$HMid};
if ($hash && $hash->{DEF} ne '000000'){
my $pendCmd = $hash->{helper}{respWait}{Pending};# secure before remove
my $pendRsndCnt = $hash->{helper}{respWait}{PendingRsend};
$pendRsndCnt = 1 if (!$pendRsndCnt); #already one send done
if ($pendRsndCnt < 5 && # some retries
((CUL_HM_getRxType($hash) & 0x03) != 0 || # to slow for wakeup/config
($hash->{protCondBurst}&&$hash->{protCondBurst} eq "on" ))){
my $name = $hash->{NAME};
Log GetLogLevel($name,4),"CUL_HM_Resend: ".$name. " nr ".$pendRsndCnt;
$hash->{helper}{respWait}{PendingRsend} = $pendRsndCnt + 1;
CUL_HM_SndCmd($hash,substr($hash->{helper}{respWait}{PendCmd},4));
CUL_HM_eventP($hash,"Resnd");
if ($state =~ m/^CMDs_done/){ DoTrigger($name, undef);
$hash->{helper}{prt}{sProc} = 0;
$hash->{helper}{prt}{awake} = 0 if (defined$hash->{helper}{prt}{awake}); # asleep
# Log 1,"General StackFinished $hash->{NAME}";
}
else{
CUL_HM_eventP($hash,"ResndFail");
CUL_HM_ProcessCmdStack($hash); # continue processing commands
readingsSingleUpdate($hash,"state","RESPONSE TIMEOUT:".$pendCmd,1);
elsif($state =~ m/processing/){ $hash->{helper}{prt}{sProc} = 1;
# Log 1,"General StackProces $hash->{NAME}";
}
}
}
sub CUL_HM_respPendToutProlong($) {#used when device sends part responses
my ($hash) = @_;
RemoveInternalTimer("respPend:$hash->{DEF}");
InternalTimer(gettimeofday()+1, "CUL_HM_respPendTout", "respPend:$hash->{DEF}", 0);
}
sub CUL_HM_PushCmdStack($$) {
my ($chnhash, $cmd) = @_;
my @arr = ();
my $hash = CUL_HM_getDeviceHash($chnhash);
my $name = $hash->{NAME};
if(!$hash->{cmdStack}){
$hash->{cmdStack} = \@arr;
delete ($hash->{helper}{burstEvtCnt}) if (!$hash->{helper}{respWait});
}
push(@{$hash->{cmdStack}}, $cmd);
my $entries = scalar @{$hash->{cmdStack}};
$hash->{protCmdPend} = $entries." CMDs_pending";
CUL_HM_protState($hash,"CMDs_pending")
if (!$hash->{helper}{respWait}{cmd} &&
!$hash->{helper}{respWait}{Pending});
}
sub CUL_HM_ProcessCmdStack($) {
my ($chnhash) = @_;
my $hash = CUL_HM_getDeviceHash($chnhash);
if($hash->{cmdStack} && !$hash->{helper}{respWait}{cmd} &&
!$hash->{helper}{respWait}{Pending}){
if(@{$hash->{cmdStack}}) {
CUL_HM_SndCmd($hash, shift @{$hash->{cmdStack}});
}
elsif(!@{$hash->{cmdStack}}) {
delete($hash->{cmdStack});
delete($hash->{protCmdPend});
#-- update info ---
CUL_HM_protState($hash,"CMDs_done".($hash->{helper}{burstEvtCnt}?
("_events:".$hash->{helper}{burstEvtCnt}):""));
}
}
return;
}
sub CUL_HM_pushConfig($$$$$$$$@) {#generate messages to config data to register
my ($hash,$src,$dst,$chn,$peerAddr,$peerChn,$list,$content,$prep) = @_;
my $flag = CUL_HM_getFlag($hash);
my $tl = length($content);
$chn = sprintf("%02X",$chn);
$peerChn = sprintf("%02X",$peerChn);
$list = sprintf("%02X",$list);
# --store pending changes in shadow to handle bit manipulations cululativ--
$peerAddr = "000000" if(!$peerAddr);
my $peerN = ($peerAddr ne "000000")?CUL_HM_peerChName($peerAddr.$peerChn,$dst,""):"";
$peerN =~ s/broadcast//;
$peerN =~ s/ /_/g;#remote blanks
my $regLN = ((CUL_HM_getAttrInt($hash->{NAME},"expert") == 2)?"":".").
"RegL_".$list.":".$peerN;
#--- copy data from readings to shadow
my $chnhash = $modules{CUL_HM}{defptr}{$dst.$chn};
$chnhash = $hash if (!$chnhash);
if (!$chnhash->{helper}{shadowReg} ||
!$chnhash->{helper}{shadowReg}{$regLN}){
$chnhash->{helper}{shadowReg}{$regLN} =
ReadingsVal($chnhash->{NAME},$regLN,"");
}
#--- update with ne value
my $regs = $chnhash->{helper}{shadowReg}{$regLN};
for(my $l = 0; $l < $tl; $l+=4) { #substitute changed bytes in shadow
my $addr = substr($content,$l,2);
my $data = substr($content,$l+2,2);
if(!$regs || !($regs =~ s/$addr:../$addr:$data/)){
$regs .= " ".$addr.":".$data;
}
}
$chnhash->{helper}{shadowReg}{$regLN} = $regs;
return if ($prep);#prepare shadowReg only. More data to come.
#Application takes care about execution
CUL_HM_updtRegDisp($hash,$list,$peerAddr.$peerChn);
CUL_HM_PushCmdStack($hash, "++".$flag.'01'.$src.$dst.$chn.'05'.
$peerAddr.$peerChn.$list);
for(my $l = 0; $l < $tl; $l+=28) {
my $ml = $tl-$l < 28 ? $tl-$l : 28;
CUL_HM_PushCmdStack($hash, "++A001".$src.$dst.$chn."08".
substr($content,$l,$ml));
}
CUL_HM_PushCmdStack($hash,"++A001".$src.$dst.$chn."06");
CUL_HM_queueAutoRead($hash->{NAME})
if (2 < CUL_HM_getAttrInt($hash->{NAME},"autoReadReg"));
}
sub CUL_HM_Resend($) {#resend a message if there is no answer
my $hash = shift;
my $name = $hash->{NAME};
return if(!$hash->{helper}{respWait}{reSent}); # Double timer?
my $rep = AttrVal($name,"msgRepeat",3);
if($hash->{helper}{respWait}{reSent} > $rep) {
if (!$hash->{helper}{respWait}{wakeup}){
CUL_HM_eventP($hash,"ResndFail");
readingsSingleUpdate($hash,"state","MISSING ACK",1);
CUL_HM_ProcessCmdStack($hash); # continue processing commands if any
}
else{# do not count problems with wakeup try, just wait
CUL_HM_respPendRm($hash);
$hash->{protCondBurst} = "off";
}
}
else {
CUL_HM_eventP($hash,"Resnd");
IOWrite($hash, "", $hash->{helper}{respWait}{cmd});
$hash->{helper}{respWait}{reSent}++;
Log GetLogLevel($name,4),"CUL_HM_Resend: ".$name. " nr ".$hash->{helper}{respWait}{reSent};
InternalTimer(gettimeofday()+rand(40)/10+1, "CUL_HM_Resend", $hash, 0);#2fast?HMLAN wants 2 sec
elsif($state eq "Info_Cleared"){$hash->{helper}{prt}{sProc} = 0;
# Log 1,"General StackCleared $hash->{NAME}";
}
}
@ -3693,6 +3725,7 @@ sub CUL_HM_ID2PeerList ($$$) {
}
$attr{$name}{peerIDs} = $peerIDs; # make it public
if ($peerNames){
$peerNames =~ s/_chn:01//g; # channel 01 is part of device
readingsSingleUpdate($hash,"peerList",$peerNames,0) ;
$hash->{peerList} = $peerNames;
}

View File

@ -158,10 +158,15 @@ sub HMinfo_peerCheck(@) { #####################################################
else{# work on a valid list:
foreach (split",",$peerIDs){
next if ($_ eq "00000000" ||$_ =~m /$devId/);
my $cId = $id;
if ($md eq "HM-CC-RT-DN" && $id =~ m/05$/){ # special RT climate
$_ =~ s/04$/05/; # have to compare with clima_team, not clima
$cId =~ s/05$/04/;# will find 04 in peerlist, not 05
}
my $pName = CUL_HM_id2Name($_);
$pName =~s/_chn:01//; #channel 01 could be covered by device
my $pPlist = AttrVal($pName,"peerIDs","");
push @peerIDsNoPeer,$eName." p:".$pName if ($pPlist !~ m/$id/);
push @peerIDsNoPeer,$eName." p:".$pName if ($pPlist !~ m/$cId/);
}
}
}

View File

@ -203,7 +203,7 @@ my %culHmModel=(
"00A5" => {name=>"HM-RC-Sec4-2" ,st=>'remote' ,cyc=>'' ,rxt=>'c:l' ,lst=>'1,4' ,chn=>"Btn:1:2,BTN_T:3:1,BTN_A:4:1",},#only 1 and 2 canbe peered???
"00A6" => {name=>"HM-RC-Key4-2" ,st=>'remote' ,cyc=>'' ,rxt=>'c:l' ,lst=>'1,4' ,chn=>"Btn:1:2,BTN_T:3:1,BTN_A:4:1",},#only 1 and 2 canbe peered???
"00A7" => {name=>"HM-Sen-RD-O" ,st=>'sensRain' ,cyc=>'' ,rxt=>'' ,lst=>'1:1,4:1p' ,chn=>"Rain:1:1,Heating:2:2",},#stc:70 THSensor
"00A8" => {name=>"HM-WDS30-OT2-SM" ,st=>'THSensor' ,cyc=>'00:10' ,rxt=>'c:w:f' ,lst=>'p' ,chn=>"T1:1:1,T2:2:2,T1-T2:3:3,T2-T1:4:4,Event:5:5",},
"00A8" => {name=>"HM-WDS30-OT2-SM" ,st=>'THSensor' ,cyc=>'00:10' ,rxt=>'c:w:f' ,lst=>'p' ,chn=>"T1:1:1,T2:2:2,T1_T2:3:3,T2_T1:4:4,Event:5:5",},
"00A9" => {name=>"HM-PB-6-WM55" ,st=>'remote' ,cyc=>'' ,rxt=>'c' ,lst=>'1,4' ,chn=>"Btn:1:6",},
"00AB" => {name=>"HM-LC-SW4-BA-PCB" ,st=>'switch' ,cyc=>'' ,rxt=>'b' ,lst=>'1,3' ,chn=>"Sw:1:4",},
"00AF" => {name=>"HM-OU-CM-PCB" ,st=>'outputUnit' ,cyc=>'' ,rxt=>'' ,lst=>'3' ,chn=>"",},