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.
+