00_ZWCUL: add zwaveRouting (experimental)

git-svn-id: https://svn.fhem.de/fhem/trunk@10824 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2016-02-13 22:12:02 +00:00
parent 3dc1f2c5ae
commit bd8b3f215b
2 changed files with 111 additions and 50 deletions

View File

@ -25,6 +25,7 @@ sub ZWCUL_Write($$$);
sub ZWCUL_ProcessSendStack($); sub ZWCUL_ProcessSendStack($);
use vars qw(%zwave_id2class); use vars qw(%zwave_id2class);
my %sentIdx;
my %sets = ( my %sets = (
"reopen" => { cmd=>"" }, "reopen" => { cmd=>"" },
@ -217,6 +218,7 @@ ZWCUL_cmd($$@)
ZWCUL_tmp9600($hash, $a[0] ? "zm9" : 0); # expect random homeId ZWCUL_tmp9600($hash, $a[0] ? "zm9" : 0); # expect random homeId
return; return;
} }
if($cmdName eq "removeNode") { if($cmdName eq "removeNode") {
delete $hash->{addNode}; delete $hash->{addNode};
delete $hash->{removeNode}; delete $hash->{removeNode};
@ -224,6 +226,7 @@ ZWCUL_cmd($$@)
ZWCUL_tmp9600($hash, $a[0] ? "zr9" : 0); ZWCUL_tmp9600($hash, $a[0] ? "zr9" : 0);
return; return;
} }
if($cmdName eq "nodeInfo") { if($cmdName eq "nodeInfo") {
my $node = ZWCUL_getNode($hash, sprintf("%02x", $a[0])); my $node = ZWCUL_getNode($hash, sprintf("%02x", $a[0]));
return "Node with decimal id $a[0] not found" if(!$node); return "Node with decimal id $a[0] not found" if(!$node);
@ -275,24 +278,23 @@ ZWCUL_Write($$$)
Log3 $hash, 5, "ZWCUL_Write $fn $msg"; Log3 $hash, 5, "ZWCUL_Write $fn $msg";
if($msg =~ m/0013(..)(..)(.*)(....)/) { if($msg =~ m/0013(..)(..)(.*)(....)/) {
my ($t,$l,$p) = ($1,$2,$3); my ($targetId,$l,$p) = ($1,$2,$3);
my $th = $modules{ZWave}{defptr}{"$fn $t"}; my ($homeId,$route) = split(",",$fn);
if(!$th) {
Log3 $hash, 1, "ZWCUL: no device found for $fn $t";
return;
}
# Do not send wakeupNoMoreInformation in monitor mode $sentIdx{$targetId} = 0 if(!$sentIdx{$targetId} || $sentIdx{$targetId}==15);
return if($p eq "8408" && $hash->{monitor}); $sentIdx{$targetId}++;
$th->{sentIdx} = 0 if(!$th->{sentIdx} || $th->{sentIdx} == 15);
$th->{sentIdx}++;
my $s100 = ($hash->{baudRate} eq "100k"); my $s100 = ($hash->{baudRate} eq "100k");
$msg = sprintf("%s%s41%02x%02x%s%s", my $rf = 0x41;
$fn, $hash->{nodeIdHex}, $th->{sentIdx}, if($route) {
length($p)/2+($s100 ? 11 : 10), $th->{nodeIdHex}, $p); $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)); $msg .= ($s100 ? zwlib_checkSum_16($msg) : zwlib_checkSum_8($msg));
ZWCUL_SimpleWrite($hash, "zs".$msg); ZWCUL_SimpleWrite($hash, "zs".$msg);
@ -462,21 +464,13 @@ ZWCUL_Parse($$$$$)
return; return;
} }
if($hash->{addNode} && $T eq "ff" && $S eq "00" && if($hash->{addNode} && $T eq "ff" && $S eq "00" && $P =~ m/^0101/) {
$P =~ m/^0101(......)(..)..(.*)/) {
ZWCUL_assignId($hash, "00", $hash->{homeIdSet}, $hash->{addNode}); ZWCUL_assignId($hash, "00", $hash->{homeIdSet}, $hash->{addNode});
$hash->{addNodeParam} = $P; $hash->{addNodeParam} = $P;
return; return;
} }
$rmsg = sprintf("0004%s%s%02x%s", $S, $S, length($P)/2, $P); $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 } else { # ACK
if($hash->{removeNode} && $hash->{removeNode} eq $S) { ############# if($hash->{removeNode} && $hash->{removeNode} eq $S) { #############
@ -507,8 +501,8 @@ ZWCUL_Parse($$$$$)
} }
if($hash->{addNode} && $hash->{addNode} eq $S) { # Another hack if($hash->{addNode} && $hash->{addNode} eq $S) { # Another hack
Log3 $hash, 3, "ZWCUL node ".hex($S)." excluded from network"; Log3 $hash, 3,"ZWCUL node ".hex($S)." (hex $S) included into the network";
delete $hash->{removeNode}; delete $hash->{addNode};
ZWCUL_tmp9600($hash, 0); ZWCUL_tmp9600($hash, 0);
return; return;
} }
@ -701,13 +695,12 @@ ZWCUL_Ready($)
Activate (or deactivate) inclusion mode. The CUL will switch to dataRate 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 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 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. </li>
</li>
<li>addNodeId &lt;decimalNodeId&gt;<br> <li>addNodeId &lt;decimalNodeId&gt;<br>
Activate inclusion mode, and assign decimalNodeId to the next node. 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
</li> FHEM2FHEM:RAW attached ZWCUL, use addNodeId instead</li>
<li>removeNode [onNw|on|off]<br> <li>removeNode [onNw|on|off]<br>
Activate (or deactivate) exclusion mode. Like with addNode, the CUL will Activate (or deactivate) exclusion mode. Like with addNode, the CUL will

View File

@ -36,7 +36,8 @@ my %zwave_class = (
"..0105" => '"zwaveGetNodesInRange:noarg"', "..0105" => '"zwaveGetNodesInRange:noarg"',
"..0106(.*)"=> '"zwaveNodeRangeInfo:$1"', "..0106(.*)"=> '"zwaveNodeRangeInfo:$1"',
"..0107(.*)"=> '"zwaveCommandComplete:$1"', "..0107(.*)"=> '"zwaveCommandComplete:$1"',
"..010801" => '"zwaveTransferPresentation"' "..010801" => '"zwaveTransferPresentation"',
"..010c(.*)"=> '"zwaveAssignRoute:$1"'
}}, }},
BASIC => { id => '20', BASIC => { id => '20',
set => { basicValue => "01%02x", set => { basicValue => "01%02x",
@ -535,10 +536,25 @@ ZWave_Initialize($)
$hash->{GetFn} = "ZWave_Get"; $hash->{GetFn} = "ZWave_Get";
$hash->{DefFn} = "ZWave_Define"; $hash->{DefFn} = "ZWave_Define";
$hash->{UndefFn} = "ZWave_Undef"; $hash->{UndefFn} = "ZWave_Undef";
$hash->{AttrFn} = "ZWave_Attr";
$hash->{ParseFn} = "ZWave_Parse"; $hash->{ParseFn} = "ZWave_Parse";
$hash->{AttrList} = "IODev do_not_notify:1,0 noExplorerFrames:1,0 ". no warnings 'qw';
"ignore:1,0 dummy:1,0 showtime:1,0 classes vclasses ". my @attrList = qw(
"secure_classes WNMI_delay $readingFnAttributes"; 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; map { $zwave_id2class{lc($zwave_class{$_}{id})} = $_ } keys %zwave_class;
$hash->{FW_detailFn} = "ZWave_fhemwebFn"; $hash->{FW_detailFn} = "ZWave_fhemwebFn";
@ -3467,7 +3483,9 @@ ZWave_wakeupTimer($$)
my $nodeId = $hash->{nodeIdHex}; my $nodeId = $hash->{nodeIdHex};
my $cmdEf = (AttrVal($hash->{NAME},"noExplorerFrames",0)==0 ? "25":"05"); my $cmdEf = (AttrVal($hash->{NAME},"noExplorerFrames",0)==0 ? "25":"05");
# wakeupNoMoreInformation # 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}; delete $hash->{wakeupAlive};
@ -3515,15 +3533,17 @@ ZWave_processSendStack($$)
$ss->[0] =~ m/^([^:]*?):(.*)$/; $ss->[0] =~ m/^([^:]*?):(.*)$/;
my ($type, $msg) = ($1, $2); 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"; $ss->[0] = "sent$type:$msg";
$hash->{lastMsgSent} = gettimeofday(); $hash->{lastMsgSent} = gettimeofday();
$zwave_lastHashSent = $hash; $zwave_lastHashSent = $hash;
if(!ZWave_isWakeUp($hash)) { if(!ZWave_isWakeUp($hash)) {
InternalTimer($hash->{lastMsgSent}+3, sub { InternalTimer($hash->{lastMsgSent}+5, sub { # zme generates NO_ACK after 4s
Log 2, "ZWave: No ACK from $hash->{NAME} after 3s for $ss->[0]"; Log 2, "ZWave: No ACK from $hash->{NAME} after 5s for $ss->[0]";
ZWave_processSendStack($hash, "next"); ZWave_processSendStack($hash, "next");
}, $hash, 0); }, $hash, 0);
} }
@ -3550,9 +3570,9 @@ ZWave_addToSendStack($$$)
} else { # clear commands without 0113 and 0013 } else { # clear commands without 0113 and 0013
my $now = gettimeofday(); my $now = gettimeofday();
if(@{$ss} > 1 && $now-$hash->{lastMsgSent} > 3) { if(@{$ss} > 1 && $now-$hash->{lastMsgSent} > 5) {
Log3 $hash, 2, Log3 $hash, 2,
"ERROR: $hash->{NAME}: cleaning commands without ack after 3s"; "ERROR: $hash->{NAME}: cleaning commands without ack after 5s";
delete $hash->{SendStack}; delete $hash->{SendStack};
return ZWave_addToSendStack($hash, $type, $cmd); return ZWave_addToSendStack($hash, $type, $cmd);
} }
@ -3884,6 +3904,46 @@ ZWave_Undef($$)
return 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 # Show the help from the device.xml, if the correct entry is selected
sub sub
@ -4822,28 +4882,36 @@ s2Hex($)
is in seconds, subseconds my be specified. Values outside of 0.2-5.0 are is in seconds, subseconds my be specified. Values outside of 0.2-5.0 are
probably harmful. probably harmful.
</li> </li>
<li><a href="#do_not_notify">do_not_notify</a></li> <li><a name="classes">classes</a>
<li><a href="#ignore">ignore</a></li>
<li><a href="#dummy">dummy</a></li>
<li><a href="#showtime">showtime</a></li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
<li><a href="#classes">classes</a>
This attribute is needed by the ZWave module, as the list of the possible 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 set/get commands depends on it. It contains a space separated list of
class names (capital letters). class names (capital letters).
</li> </li>
<li><a href="#secure_classes">secure_classes</a> <li><a href="#do_not_notify">do_not_notify</a></li>
<li><a href="#dummy">dummy</a></li>
<li><a href="#ignore">ignore</a></li>
<li><a href="#noExplorerFrames">noExplorerFrames</a>
turn off the use of Explorer Frames
</li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li>
<li><a name="secure_classes">secure_classes</a>
This attribute is the result of the "set DEVICE secSupportedReport" This attribute is the result of the "set DEVICE secSupportedReport"
command. It contains a space seperated list of the the command classes command. It contains a space seperated list of the the command classes
that are supported with SECURITY. that are supported with SECURITY.
</li> </li>
<li><a href="#vclasses">vclasses</a> <li><a href="#showtime">showtime</a></li>
<li><a name="vclasses">vclasses</a>
This is the result of the "get DEVICE versionClassAll" command, and This is the result of the "get DEVICE versionClassAll" command, and
contains the version information for each of the supported classes. contains the version information for each of the supported classes.
</li> </li>
<li><a href="#noExplorerFrames">noExplorerFrames</a>
turn off the use of Explorer Frames <li><a name="zwaveRoute">zwaveRoute</a>
</li> 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. </li>
</ul> </ul>
<br> <br>