From c467ba303f267838c67447f999d9998c2ed7a05c Mon Sep 17 00:00:00 2001 From: martinp876 <> Date: Sat, 5 Jan 2019 23:21:58 +0000 Subject: [PATCH] 10_CUL_HM:introduce modelForce, correct message repeat for burst devices git-svn-id: https://svn.fhem.de/fhem/trunk@18153 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/10_CUL_HM.pm | 219 ++++++++++++++++++++++++++++++----------- 1 file changed, 160 insertions(+), 59 deletions(-) diff --git a/fhem/FHEM/10_CUL_HM.pm b/fhem/FHEM/10_CUL_HM.pm index 6f8a14e4f..7e6a31686 100755 --- a/fhem/FHEM/10_CUL_HM.pm +++ b/fhem/FHEM/10_CUL_HM.pm @@ -154,6 +154,11 @@ my $evtDly = 0; # ugly switch to delay set readings if in parser - actually n sub CUL_HM_Initialize($) { my ($hash) = @_; + my @modellist; + foreach my $model (keys %{$culHmModel}){ + push @modellist,$culHmModel->{$model}{name}; + } + $hash->{Match} = "^A...................."; $hash->{DefFn} = "CUL_HM_Define"; $hash->{UndefFn} = "CUL_HM_Undef"; @@ -168,7 +173,7 @@ sub CUL_HM_Initialize($) { ."IODev IOList IOgrp " ."rssiLog:1,0 " # enable writing RSSI to Readings (device only) ."actCycle " # also for action detector - ."hmKey hmKey2 hmKey3 " + ."hmKey hmKey2 hmKey3 " ."readingOnDead:multiple,noChange,state,periodValues,periodString,channels " ; $hash->{Attr}{devPhy} = # -- physical device only attributes @@ -176,9 +181,12 @@ sub CUL_HM_Initialize($) { ."actStatus " ."autoReadReg:0_off,1_restart,2_pon-restart,3_onChange,4_reqStatus,5_readMissing,8_stateOnly " ."burstAccess:0_off,1_auto " - ."msgRepeat " + ."msgRepeat " ."hmProtocolEvents:0_off,1_dump,2_dumpFull,3_dumpTrigger " ."aesKey:5,4,3,2,1,0 " + ."modelForce:".join(",", sort @modellist)." " + .".mId " + ."subType:" .join(",",CUL_HM_noDup(map { $culHmModel->{$_}{st} } keys %{$culHmModel}))." " ; $hash->{Attr}{chn} = "repPeers " # -- channel only attributes ."peerIDs " @@ -193,6 +201,7 @@ sub CUL_HM_Initialize($) { ."readOnly:0,1 " ."actAutoTry:0_off,1_on " ."aesCommReq:1,0 " # IO will request AES if + ."model " ; $hash->{AttrList} = $hash->{Attr}{glb} .$hash->{Attr}{dev} @@ -202,13 +211,9 @@ sub CUL_HM_Initialize($) { ; CUL_HM_initRegHash(); - my @modellist; - foreach my $model (keys %{$culHmModel}){ - push @modellist,$culHmModel->{$model}{name}; - } - $hash->{AttrList} .= " model:" .join(",", sort @modellist); - $hash->{AttrList} .= " subType:".join(",", - CUL_HM_noDup(map { $culHmModel->{$_}{st} } keys %{$culHmModel})); +# $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 my @statQArr = (); @@ -236,6 +241,7 @@ sub CUL_HM_Initialize($) { } sub CUL_HM_updateConfig($){ + my $type = shift; # this routine is called 5 sec after the last define of a restart # this gives FHEM sufficient time to fill in attributes # it will also be called after each manual definition @@ -245,7 +251,17 @@ sub CUL_HM_updateConfig($){ InternalTimer(1,"CUL_HM_updateConfig", "updateConfig", 0);#start asap once FHEM is operational return; } - + if ($type eq "startUp"){# only once after startup + foreach(devspec2array("TYPE=CUL_HM:FILTER=DEF=......:FILTER=subType!=virtual")){ + if ($attr{$_}{".mId"} && $culHmModel->{$attr{$_}{".mId"}}){ #if mId is available set model to its original value -at least temporarliy + $attr{$_}{model} = $culHmModel->{$attr{$_}{name}}; + } + else{#if mId is not available use attr model and assign it. + $attr{$_}{".mId"} = CUL_HM_getmIdFromModel($attr{$_}{model}); + } + CUL_HM_updtDeviceModel($_,AttrVal($_,"modelForce",AttrVal($_,"model",""))); + } + } foreach my $name (@{$modules{CUL_HM}{helper}{updtCfgLst}}){ my $hash = $defs{$name}; next if (!$hash->{DEF}); # likely renamed @@ -776,6 +792,7 @@ sub CUL_HM_Attr(@) {################################# return; } elsif($attrName eq "model" && $hash->{helper}{role}{dev}){ + return "$attrName must not be changed by User. \nUse modelForce instead" if ($init_done); delete $hash->{helper}{rxType}; # needs new calculation delete $hash->{helper}{mId}; if ($attrVal eq "CCU-FHEM"){ @@ -788,7 +805,27 @@ sub CUL_HM_Attr(@) {################################# } $attr{$name}{$attrName} = $attrVal if ($cmd eq "set"); } + elsif($attrName eq "modelForce"){ + if ($init_done){# while init allow anything. Correct with CUL_HM_updateConfig after init_done + if ($cmd eq "set"){ + if (!defined $attr{$name}{".mId"} && defined $attr{$name}{model}){ # set .mId in case it is missing + $attr{$name}{".mId"} = CUL_HM_getmIdFromModel($attr{$name}{model}); + } + + return "invalid model name:$attrVal. Please check options" if (!CUL_HM_getmIdFromModel($attrVal)); + CUL_HM_updtDeviceModel($name,$attrVal); + } + else{ + $attr{$name}{model} = $culHmModel->{$attr{$name}{".mId"}}{name};# return to old model name + CUL_HM_updtDeviceModel($name,$attr{$name}{model}); + } + } + } + elsif($attrName eq ".mId"){ + return "$attrName must not be changed by User. \nUse modelForce instead" if ($init_done); + } elsif($attrName eq "subType"){ + return "$attrName must not be changed by User. \nUse modelForce instead" if ($init_done); $updtReq = 1; } elsif($attrName eq "aesCommReq" ){ @@ -1151,7 +1188,7 @@ sub CUL_HM_Parse($$) {######################################################### my $sname = "HM_$mh{src}"; Log3 undef, 2, "CUL_HM Unknown device $sname is now defined"; DoTrigger("global","UNDEFINED $sname CUL_HM $mh{src}"); - $mh{devH} = CUL_HM_id2Hash($mh{src}); #sourcehash - changed to channel entity + $mh{devH} = CUL_HM_id2Hash($mh{src}); #sourcehash - changed to channel entity $mh{devH}->{IODev} = $iohash; $mh{devH}->{helper}{io}{nextSend} = $mh{rectm}+0.09 if(!defined($mh{devH}->{helper}{io}{nextSend}));# io couldn't set } @@ -4076,15 +4113,15 @@ sub CUL_HM_Set($@) {#+++++++++++++++++ set command+++++++++++++++++++++++++++++ if( $culHmFunctSets->{$fkt} && $roleC){foreach(keys %{$culHmFunctSets->{$fkt}} ){push @arr1,"$_:".${$culHmFunctSets->{$fkt}}{$_} }}; @arr1 = CUL_HM_noDup(@arr1); foreach(@arr1){ - my ($cmd,$val) = split(":",$_,2); + my ($cmdS,$val) = split(":",$_,2); if (!$val){ # no agruments possible - $_ = "$cmd:noArg"; + $_ = "$cmdS:noArg"; } elsif($val !~ m/^\[.*\]$/ || $val =~ m/\[.*\[/ || $val =~ m/(\<|\>)]/ ){ - $_ = $cmd; + $_ = $cmdS; } else{ $val =~ s/(\[|\])//g; @@ -4096,7 +4133,7 @@ sub CUL_HM_Set($@) {#+++++++++++++++++ set command+++++++++++++++++++++++++++++ $_ = join(",",@list); } } - $_ = "$cmd:".join(",",@vArr); + $_ = "$cmdS:".join(",",@vArr); } } @arr1 = ("--") if (!scalar @arr1); @@ -4495,7 +4532,7 @@ sub CUL_HM_Set($@) {#+++++++++++++++++ set command+++++++++++++++++++++++++++++ $state = ""; my $sn = ReadingsVal($name,"D-serialNr",""); return "serial number unknown" if (! $sn); - CUL_HM_PushCmdStack($hash,'++8401'.$id.'000000010A'.uc(unpack('H*', $sn))); + CUL_HM_PushCmdStack($hash,'++8401'.$id.$dst.'010A'.uc(unpack('H*', $sn))); } elsif($cmd eq "getConfig") { ################################################ CUL_HM_unQEntity($name,"qReqConf"); @@ -6319,7 +6356,7 @@ sub CUL_HM_Set($@) {#+++++++++++++++++ set command+++++++++++++++++++++++++++++ my $ret = HMinfo_SetFn($defs{hm},$hm,"templateSet",$name,$tpl,"$tPeer$tTyp",@par); return $ret; } - elsif($cmd =~ m/tplPara(..)(.)_.*/) { ##################################### + elsif($cmd =~ m/tplPara(..)(.)_.*/) { ####################################### $state = ""; my ($tNo,$pNo) = ($1,$2); my ($hm) = devspec2array("TYPE=HMinfo"); @@ -6484,21 +6521,24 @@ sub CUL_HM_weather(@) {#periodically send weather data CUL_HM_SndCmd($hash,"++8470".$ioId."00000000".$hash->{helper}{weather}); InternalTimer(gettimeofday()+150,"CUL_HM_weather","weather:$name",0); } + sub CUL_HM_infoUpdtDevData($$$) {#autoread config my($name,$hash,$p) = @_; my($fw1,$fw2,$mId,$serNo,$stc,$devInfo) = unpack('A1A1A4A20A2A*', $p); - my $md = $culHmModel->{$mId}{name} ? $culHmModel->{$mId}{name}:"unknown"; + my $md = $culHmModel->{$mId}{name} ? $culHmModel->{$mId}{name}:"unknown";# original model my $serial = pack('H*',$serNo); my $fw = sprintf("%d.%d", hex($fw1),hex($fw2)); - $attr{$name}{model} = $md; + $attr{$name}{".mId"} = $mId; + $attr{$name}{model} = AttrVal($name,"modelForce",$md); #may be overwritten by modelForce $attr{$name}{subType} = $culHmModel->{$mId}{st}; $attr{$name}{serialNr} = $serial; # to be removed from attributes $attr{$name}{firmware} = $fw; # to be removed from attributes -# $attr{$name}{".devInfo"} = $devInfo; # to be removed from attributes -# $attr{$name}{".stc"} = $stc; # to be removed from attributes - CUL_HM_configUpdate($name) if(ReadingsVal($name,"D-firmware","") ne $fw + + CUL_HM_updtDeviceModel($name,$attr{$name}{model}); + + CUL_HM_configUpdate($name) if(ReadingsVal($name,"D-firmware","") ne $fw # force read register ||ReadingsVal($name,"D-serialNr","") ne $serial ||ReadingsVal($name,".D-devInfo","") ne $devInfo ||ReadingsVal($name,".D-stc" ,"") ne $stc @@ -6507,33 +6547,84 @@ sub CUL_HM_infoUpdtDevData($$$) {#autoread config "D-serialNr:$serial", ".D-devInfo:$devInfo", ".D-stc:$stc"); +# delete $hash->{helper}{rxType}; +# CUL_HM_getRxType($hash); #will update rxType +# $mId = CUL_HM_getMId($hash);# set helper valiable and use result +# +# # autocreate undefined channels +# my @chanTypesList = split(',',$culHmModel->{$mId}{chn}); +# foreach my $chantype (@chanTypesList){ +# my ($chnTpName,$chnStart,$chnEnd) = split(':',$chantype); +# my $chnNoTyp = 1; +# for (my $chnNoAbs = $chnStart; $chnNoAbs <= $chnEnd;$chnNoAbs++){ +# my $chnId = $hash->{DEF}.sprintf("%02X",$chnNoAbs); +# if (!$modules{CUL_HM}{defptr}{$chnId}){ +# my $chnName = $name."_".$chnTpName.(($chnStart == $chnEnd)? +# '':'_'.sprintf("%02d",$chnNoTyp)); +# +# CommandDefine(undef,$chnName.' CUL_HM '.$chnId); +# $attr{CUL_HM_id2Name($chnId)}{model} = $attr{$name}{model}; +# } +# $attr{CUL_HM_id2Name($chnId)}{model} = $attr{$name}{model}; +# $chnNoTyp++; +# } +# } +# if ($culHmModel->{$mId}{cyc}){ +# CUL_HM_ActAdd($hash->{DEF},AttrVal($name,"actCycle", +# $culHmModel->{$mId}{cyc})); +# } +} +sub CUL_HM_updtDeviceModel($$) {#change the model for a device - obey overwrite modelForce + my($name,$model) = @_; + my $hash = $defs{$name}; + $attr{$name}{model} = $model; delete $hash->{helper}{rxType}; + delete $hash->{helper}{mId}; CUL_HM_getRxType($hash); #will update rxType - $mId = CUL_HM_getMId($hash);# set helper valiable and use result + my $mId = CUL_HM_getMId($hash);# set helper valiable and use result + $attr{$name}{subType} = $culHmModel->{$mId}{st}; # autocreate undefined channels - my @chanTypesList = split(',',$culHmModel->{$mId}{chn}); - foreach my $chantype (@chanTypesList){ - my ($chnTpName,$chnStart,$chnEnd) = split(':',$chantype); - my $chnNoTyp = 1; - for (my $chnNoAbs = $chnStart; $chnNoAbs <= $chnEnd;$chnNoAbs++){ - my $chnId = $hash->{DEF}.sprintf("%02X",$chnNoAbs); - if (!$modules{CUL_HM}{defptr}{$chnId}){ - my $chnName = $name."_".$chnTpName.(($chnStart == $chnEnd)? - '':'_'.sprintf("%02d",$chnNoTyp)); - - CommandDefine(undef,$chnName.' CUL_HM '.$chnId); - $attr{CUL_HM_id2Name($chnId)}{model} = $md; - } - $attr{CUL_HM_id2Name($chnId)}{model} = $md; - $chnNoTyp++; - } + my %chanExist; + %chanExist = map { $_ => 0 } CUL_HM_getAssChnIds($name); + + if ($attr{$name}{subType} eq "virtual"){# du not apply all possible channels for virtual + $attr{CUL_HM_id2Name($_)}{model} = $model foreach(keys %chanExist); } - if ($culHmModel->{$mId}{cyc}){ - CUL_HM_ActAdd($hash->{DEF},AttrVal($name,"actCycle", - $culHmModel->{$mId}{cyc})); + else{ + my @chanTypesList = split(',',$culHmModel->{$mId}{chn}); + foreach my $chantype (@chanTypesList){# check all regulat channels + my ($chnTpName,$chnStart,$chnEnd) = split(':',$chantype); + my $chnNoTyp = 1; + for (my $chnNoAbs = $chnStart; $chnNoAbs <= $chnEnd;$chnNoAbs++){ + my $chnId = $hash->{DEF}.sprintf("%02X",$chnNoAbs); + if (!$modules{CUL_HM}{defptr}{$chnId}){# not existing by now - create + my $chnName = $name."_".$chnTpName.(($chnStart == $chnEnd)?'' + :'_'.sprintf("%02d",$chnNoTyp)); + + CommandDefine(undef,$chnName.' CUL_HM '.$chnId); + Log3 $name,3,"CUL_HM_update: $name add channel ID: $chnId name: $chnName"; + } + $attr{CUL_HM_id2Name($chnId)}{model} = $model; + $chanExist{$chnId} = 1; # mark this channel as required + $chnNoTyp++; + } + } + if (scalar @chanTypesList == 0){# we won't delete channel 01. This may be on purpose + $chanExist{$defs{$name}{DEF}."01"} = 1; + my $cn01 = CUL_HM_id2Name($defs{$name}{DEF}."01"); + $attr{$cn01}{model} = $model if (defined $attr{$cn01}); + } + foreach(keys %chanExist){ + next if ($chanExist{$_} == 1); + CommandDelete(undef,CUL_HM_id2Name($_)); + Log3 $name,3,"CUL_HM_update: $name delete channel name: $_"; + } + CUL_HM_ActAdd($hash->{DEF},AttrVal($name,"actCycle", $culHmModel->{$mId}{cyc}))if ($culHmModel->{$mId}{cyc}); + CUL_HM_queueUpdtCfg($name); } } + sub CUL_HM_getConfig($){ my $hash = shift; my $flag = 'A0'; @@ -6829,7 +6920,7 @@ sub CUL_HM_responseSetup($$) {#store all we need to handle the response if (($mFlg & 0x20) && ($dst ne '000000')){#msg wants ack my $rss = $hash->{helper}{prt}{wuReSent} ? $hash->{helper}{prt}{wuReSent} - :1;#resend count - may need preloaded for WU device + :1;#resend counter start value - may need preloaded for WU device if ($mTp eq '01' && $sTp) { if ($sTp eq "03"){ #PeerList----------- @@ -7205,10 +7296,9 @@ sub CUL_HM_respPendTout($) { } else{# manage retries $pHash->{rspWait}{reSent}++; - CUL_HM_eventP($hash,"Resnd"); Log3 $name,4,"CUL_HM_Resend: $name nr ".$pHash->{rspWait}{reSent}; - if ($hash->{protCondBurst}&&$hash->{protCondBurst} eq "on" ){ + if ($hash->{protCondBurst} && $hash->{protCondBurst} eq "on" ){ #timeout while conditional burst was active. try re-wakeup my $addr = CUL_HM_IoId($hash); $pHash->{rspWaitSec}{$_} = $pHash->{rspWait}{$_} @@ -7232,7 +7322,7 @@ sub CUL_HM_respPendTout($) { CUL_HM_protState($hash,"CMDs_pending"); $pHash->{wuReSent} = $wuReSent;# restore'invalid' count after general delete } - else{# normal device resend + else{# normal/burst device resend if ($rxt & 0x02){# type = burst - need to set burst-Bit for retry if ($pHash->{mmcA}){#fillback multi-message command unshift @{$hash->{cmdStack}},$_ foreach (reverse@{$pHash->{mmcA}}); @@ -7242,7 +7332,9 @@ sub CUL_HM_respPendTout($) { my $cmd = shift @{$hash->{cmdStack}}; $cmd = sprintf("As%02X01%s", length($cmd)/2, substr($cmd,2)); $pHash->{rspWait}{cmd} = $cmd; + my $rss = $pHash->{rspWait}{reSent}; # rescue repeat counter (will be overwritten in responseSetup) CUL_HM_responseSetup($hash,$cmd); + $pHash->{rspWait}{reSent} = $rss; # restore repeat counter } my ($pre,$tp,$tail) = unpack 'A6A2A*',$pHash->{rspWait}{cmd}; @@ -7603,22 +7695,20 @@ sub CUL_HM_getMId($) {#in: hash(chn or dev) out:model key (key for %culHmModel) my $hash = shift; $hash = CUL_HM_getDeviceHash($hash); return "" if (!$hash->{NAME}); - if (!defined $hash->{helper}{mId} || !$hash->{helper}{mId}){ - my $model = AttrVal($hash->{NAME}, "model", ""); - $hash->{helper}{mId} = ""; - foreach my $mIdKey(keys%{$culHmModel}){ - next if (!$culHmModel->{$mIdKey}{name} || - $culHmModel->{$mIdKey}{name} ne $model); - $hash->{helper}{mId} = $mIdKey; - #--- mId is updated - now update the reglist - foreach(CUL_HM_getAssChnNames($hash->{NAME})){ - $defs{$_}{helper}{regLst} = CUL_HM_getChnList($defs{$_}); - } - last; - } + if (!defined $hash->{helper}{mId} || !$hash->{helper}{mId}){# need to search + $hash->{helper}{mId} = CUL_HM_getmIdFromModel(AttrVal($hash->{NAME}, "model", "")); + $hash->{helper}{subType} = $hash->{helper}{mId} ? $culHmModel->{$hash->{helper}{mId}}{st}:""; + #--- mId is updated - now update the reglist + $defs{$_}{helper}{regLst} = CUL_HM_getChnList($defs{$_}) foreach(CUL_HM_getAssChnNames($hash->{NAME})); } return $hash->{helper}{mId}; } +sub CUL_HM_getmIdFromModel($){# enter model and receive the corresponding ID + my $model = shift; + foreach (keys%{$culHmModel}){ + return $_ if ($culHmModel->{$_}{name} && $culHmModel->{$_}{name} eq $model); + } +} sub CUL_HM_getRxType($) { #in:hash(chn or dev) out:binary coded Rx type # Will store result in device helper my ($hash) = @_; @@ -11094,6 +11184,11 @@ sub CUL_HM_tempListTmpl(@) { ################################################## attr myChannel levelRange 10,80
+
  • modelForce, + modelForce overwrites the model attribute. Doing that it converts the device and its channel to the new model.
    + Reason for this attribute is an eQ3 bug as some devices are delivered with wrong Module IDs.
    + ATTENTION: changing model id automatically starts reconfiguration of the device and its channels! channels may be deleted or incarnated
    +
  • model, subType
    These attributes are set automatically after a successful pairing. @@ -12501,6 +12596,12 @@ sub CUL_HM_tempListTmpl(@) { ################################################## Um das template nicht zu nutzen kann man es auf '0'setzen.
    Format ist <file>:<templatename>.
  • +
  • modelForce, + modelForce überschreibt das model attribut. Dabei wird das Device und seine Kanäle reconfguriert.
    + Grund für dieses Attribut ist ein eQ3 bug bei welchen Devices mit falscher ID ausgeliefert werden. Das Attribut + erlaubt dies zu ueberschreiben
    + ACHTUNG: Durch das Eintragen eines anderen model werden die Entites modifiziert, ggf. neu angelegt oder gelöscht.
    +
  • model, subType
    Diese Attribute werden bei erfolgreichem Pairing automatisch gesetzt.