From bd8b3f215ba259e73b82a64d38c74864a46717a5 Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Sat, 13 Feb 2016 22:12:02 +0000 Subject: [PATCH] 00_ZWCUL: add zwaveRouting (experimental) git-svn-id: https://svn.fhem.de/fhem/trunk@10824 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/00_ZWCUL.pm | 51 +++++++++----------- fhem/FHEM/10_ZWave.pm | 110 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 111 insertions(+), 50 deletions(-) diff --git a/fhem/FHEM/00_ZWCUL.pm b/fhem/FHEM/00_ZWCUL.pm index 26dcb5bac..f87be602b 100755 --- a/fhem/FHEM/00_ZWCUL.pm +++ b/fhem/FHEM/00_ZWCUL.pm @@ -25,6 +25,7 @@ sub ZWCUL_Write($$$); sub ZWCUL_ProcessSendStack($); use vars qw(%zwave_id2class); +my %sentIdx; my %sets = ( "reopen" => { cmd=>"" }, @@ -217,6 +218,7 @@ ZWCUL_cmd($$@) ZWCUL_tmp9600($hash, $a[0] ? "zm9" : 0); # expect random homeId return; } + if($cmdName eq "removeNode") { delete $hash->{addNode}; delete $hash->{removeNode}; @@ -224,6 +226,7 @@ ZWCUL_cmd($$@) ZWCUL_tmp9600($hash, $a[0] ? "zr9" : 0); return; } + if($cmdName eq "nodeInfo") { my $node = ZWCUL_getNode($hash, sprintf("%02x", $a[0])); return "Node with decimal id $a[0] not found" if(!$node); @@ -275,24 +278,23 @@ ZWCUL_Write($$$) Log3 $hash, 5, "ZWCUL_Write $fn $msg"; if($msg =~ m/0013(..)(..)(.*)(....)/) { - my ($t,$l,$p) = ($1,$2,$3); - my $th = $modules{ZWave}{defptr}{"$fn $t"}; - if(!$th) { - Log3 $hash, 1, "ZWCUL: no device found for $fn $t"; - return; - } + my ($targetId,$l,$p) = ($1,$2,$3); + my ($homeId,$route) = split(",",$fn); - # Do not send wakeupNoMoreInformation in monitor mode - return if($p eq "8408" && $hash->{monitor}); - - $th->{sentIdx} = 0 if(!$th->{sentIdx} || $th->{sentIdx} == 15); - $th->{sentIdx}++; + $sentIdx{$targetId} = 0 if(!$sentIdx{$targetId} || $sentIdx{$targetId}==15); + $sentIdx{$targetId}++; my $s100 = ($hash->{baudRate} eq "100k"); - $msg = sprintf("%s%s41%02x%02x%s%s", - $fn, $hash->{nodeIdHex}, $th->{sentIdx}, - length($p)/2+($s100 ? 11 : 10), $th->{nodeIdHex}, $p); + my $rf = 0x41; + if($route) { + $rf = 0x81; + $p = sprintf("00%d0%s%s",length($route)/2, $route, $p); + } + + $msg = sprintf("%s%s%02x%02x%02x%s%s", + $homeId, $hash->{nodeIdHex}, $rf, $sentIdx{$targetId}, + length($p)/2+($s100 ? 11 : 10), $targetId, $p); $msg .= ($s100 ? zwlib_checkSum_16($msg) : zwlib_checkSum_8($msg)); ZWCUL_SimpleWrite($hash, "zs".$msg); @@ -462,21 +464,13 @@ ZWCUL_Parse($$$$$) return; } - if($hash->{addNode} && $T eq "ff" && $S eq "00" && - $P =~ m/^0101(......)(..)..(.*)/) { + if($hash->{addNode} && $T eq "ff" && $S eq "00" && $P =~ m/^0101/) { ZWCUL_assignId($hash, "00", $hash->{homeIdSet}, $hash->{addNode}); $hash->{addNodeParam} = $P; return; } $rmsg = sprintf("0004%s%s%02x%s", $S, $S, length($P)/2, $P); - my $th = $modules{ZWave}{defptr}{"$H $S"}; - - if(!($S eq $hash->{nodeIdHex} && $H eq $hash->{homeIdSet}) && !$th) { - DoTrigger("global", "UNDEFINED ZWNode_${H}_$S ZWave $H ".hex($S)); - $th = $modules{ZWave}{defptr}{"$H $S"}; - } - } else { # ACK if($hash->{removeNode} && $hash->{removeNode} eq $S) { ############# @@ -507,8 +501,8 @@ ZWCUL_Parse($$$$$) } if($hash->{addNode} && $hash->{addNode} eq $S) { # Another hack - Log3 $hash, 3, "ZWCUL node ".hex($S)." excluded from network"; - delete $hash->{removeNode}; + Log3 $hash, 3,"ZWCUL node ".hex($S)." (hex $S) included into the network"; + delete $hash->{addNode}; ZWCUL_tmp9600($hash, 0); return; } @@ -701,13 +695,12 @@ ZWCUL_Ready($) Activate (or deactivate) inclusion mode. The CUL will switch to dataRate 9600 until terminating this mode with off, or a node is included. If onSec is specified, the ZWCUL networkKey ist set, and the device supports the - SECURITY class, then a secure inclusion is attempted. - + SECURITY class, then a secure inclusion is attempted.
  • addNodeId <decimalNodeId>
    Activate inclusion mode, and assign decimalNodeId to the next node. - To deactivate this mode, use addNode off. -
  • + To deactivate this mode, use addNode off. Note: addNode won't work for a + FHEM2FHEM:RAW attached ZWCUL, use addNodeId instead
  • removeNode [onNw|on|off]
    Activate (or deactivate) exclusion mode. Like with addNode, the CUL will diff --git a/fhem/FHEM/10_ZWave.pm b/fhem/FHEM/10_ZWave.pm index 5c498be1d..18e4644de 100755 --- a/fhem/FHEM/10_ZWave.pm +++ b/fhem/FHEM/10_ZWave.pm @@ -36,7 +36,8 @@ my %zwave_class = ( "..0105" => '"zwaveGetNodesInRange:noarg"', "..0106(.*)"=> '"zwaveNodeRangeInfo:$1"', "..0107(.*)"=> '"zwaveCommandComplete:$1"', - "..010801" => '"zwaveTransferPresentation"' + "..010801" => '"zwaveTransferPresentation"', + "..010c(.*)"=> '"zwaveAssignRoute:$1"' }}, BASIC => { id => '20', set => { basicValue => "01%02x", @@ -535,10 +536,25 @@ ZWave_Initialize($) $hash->{GetFn} = "ZWave_Get"; $hash->{DefFn} = "ZWave_Define"; $hash->{UndefFn} = "ZWave_Undef"; + $hash->{AttrFn} = "ZWave_Attr"; $hash->{ParseFn} = "ZWave_Parse"; - $hash->{AttrList} = "IODev do_not_notify:1,0 noExplorerFrames:1,0 ". - "ignore:1,0 dummy:1,0 showtime:1,0 classes vclasses ". - "secure_classes WNMI_delay $readingFnAttributes"; + no warnings 'qw'; + my @attrList = qw( + IODev + WNMI_delay + classes + do_not_notify:1,0 + dummy:1,0 + ignore:1,0 + noExplorerFrames:1,0 + secure_classes + showtime:1,0 + vclasses + zwaveRoute + ); + use warnings 'qw'; + $hash->{AttrList} = join(" ", @attrList)." ".$readingFnAttributes; + map { $zwave_id2class{lc($zwave_class{$_}{id})} = $_ } keys %zwave_class; $hash->{FW_detailFn} = "ZWave_fhemwebFn"; @@ -3467,7 +3483,9 @@ ZWave_wakeupTimer($$) my $nodeId = $hash->{nodeIdHex}; my $cmdEf = (AttrVal($hash->{NAME},"noExplorerFrames",0)==0 ? "25":"05"); # wakeupNoMoreInformation - IOWrite($hash, $hash->{homeId}, "0013${nodeId}028408${cmdEf}$nodeId"); + IOWrite($hash, + $hash->{homeId}.($hash->{route} ? ",".$hash->{route} : ""), + "0013${nodeId}028408${cmdEf}$nodeId"); } delete $hash->{wakeupAlive}; @@ -3515,15 +3533,17 @@ ZWave_processSendStack($$) $ss->[0] =~ m/^([^:]*?):(.*)$/; my ($type, $msg) = ($1, $2); - IOWrite($hash, $hash->{homeId}, "00$msg"); + IOWrite($hash, + $hash->{homeId}.($hash->{route}?",".$hash->{route}:""), + "00$msg"); $ss->[0] = "sent$type:$msg"; $hash->{lastMsgSent} = gettimeofday(); $zwave_lastHashSent = $hash; if(!ZWave_isWakeUp($hash)) { - InternalTimer($hash->{lastMsgSent}+3, sub { - Log 2, "ZWave: No ACK from $hash->{NAME} after 3s for $ss->[0]"; + InternalTimer($hash->{lastMsgSent}+5, sub { # zme generates NO_ACK after 4s + Log 2, "ZWave: No ACK from $hash->{NAME} after 5s for $ss->[0]"; ZWave_processSendStack($hash, "next"); }, $hash, 0); } @@ -3550,9 +3570,9 @@ ZWave_addToSendStack($$$) } else { # clear commands without 0113 and 0013 my $now = gettimeofday(); - if(@{$ss} > 1 && $now-$hash->{lastMsgSent} > 3) { + if(@{$ss} > 1 && $now-$hash->{lastMsgSent} > 5) { Log3 $hash, 2, - "ERROR: $hash->{NAME}: cleaning commands without ack after 3s"; + "ERROR: $hash->{NAME}: cleaning commands without ack after 5s"; delete $hash->{SendStack}; return ZWave_addToSendStack($hash, $type, $cmd); } @@ -3884,6 +3904,46 @@ ZWave_Undef($$) return undef; } +##################################### +sub +ZWave_computeRoute($;$) +{ + my ($spec,$attrVal) = @_; + for my $dev (devspec2array($spec)) { + my $av = AttrVal($dev, "zwaveRoute", $attrVal); + next if(!$av); + + my @h; + for my $r (split(" ", $av)) { + if(!$defs{$r} || $defs{$r}{TYPE} ne "ZWave") { + my $msg = "zwaveRoute: $r is not a ZWave device"; + Log 1, $msg; + return $msg; + } + push(@h, $defs{$r}{nodeIdHex}); + } + $defs{$dev}{route} = join("",@h); + } + return undef; +} + +sub +ZWave_Attr(@) +{ + my ($type, $devName, $attrName, @param) = @_; + + if($attrName eq "zwaveRoute") { + if($type eq "del") { + delete $defs{$devName}{route}; + return undef; + } + return ZWave_computeRoute($devName,join(" ",@param)) if($init_done); + InternalTimer(1, "ZWave_computeRoute", "TYPE=ZWave", 0); + } + return undef; +} + + ##################################### # Show the help from the device.xml, if the correct entry is selected sub @@ -4822,28 +4882,36 @@ s2Hex($) is in seconds, subseconds my be specified. Values outside of 0.2-5.0 are probably harmful.
  • -
  • do_not_notify
  • -
  • ignore
  • -
  • dummy
  • -
  • showtime
  • -
  • readingFnAttributes
  • -
  • classes +
  • classes This attribute is needed by the ZWave module, as the list of the possible set/get commands depends on it. It contains a space separated list of class names (capital letters).
  • -
  • secure_classes +
  • do_not_notify
  • +
  • dummy
  • +
  • ignore
  • +
  • noExplorerFrames + turn off the use of Explorer Frames +
  • +
  • readingFnAttributes
  • +
  • secure_classes This attribute is the result of the "set DEVICE secSupportedReport" command. It contains a space seperated list of the the command classes that are supported with SECURITY.
  • -
  • vclasses +
  • showtime
  • +
  • vclasses This is the result of the "get DEVICE versionClassAll" command, and contains the version information for each of the supported classes.
  • -
  • noExplorerFrames - turn off the use of Explorer Frames -
  • + +
  • zwaveRoute + space separated list of (ZWave) device names. They will be used in the + given order to route messages from the controller to this device. Specify + them in the order from the controller to the device. Do not specify the + controller and the device itself, only the routers inbetween. Used only + if the IODev is a ZWCUL device.
  • +