diff --git a/fhem/FHEM/10_ZWave.pm b/fhem/FHEM/10_ZWave.pm
index 34e3c0f67..76c1d7b87 100755
--- a/fhem/FHEM/10_ZWave.pm
+++ b/fhem/FHEM/10_ZWave.pm
@@ -16,7 +16,7 @@ sub ZWave_Get($@);
sub ZWave_Parse($$@);
sub ZWave_Set($@);
sub ZWave_SetClasses($$$$);
-sub ZWave_addToSendStack($$);
+sub ZWave_addToSendStack($$$);
sub ZWave_secStart($);
sub ZWave_secEnd($);
sub ZWave_configParseModel($;$);
@@ -399,9 +399,9 @@ my %zwave_class = (
"..8506(..)" => '"assocGroups:".hex($1)' },
init => { ORDER=>10, CMD=> '"set $NAME associationAdd 1 $CTRLID"' } },
VERSION => { id => '86',
- set => { versionClassRequest => 'ZWave_versionClassRequest($hash,"%s")'},
get => { version => "11",
- versionClass => 'ZWave_versionClassGet("%s")' },
+ versionClass => 'ZWave_versionClassGet("%s")',
+ versionClassAll => 'ZWave_versionClassAllGet($hash)'},
parse => { "028611" => "cmdGet:version",
"078612(..........)" => 'sprintf("version:Lib %d Prot '.
'%d.%d App %d.%d", unpack("C*",pack("H*","$1")))',
@@ -791,6 +791,7 @@ ZWave_Cmd($$@)
$cmdFmt = sprintf($cmdFmt, @a) if($nArg);
my ($err, $ncmd) = eval($cmdFmt) if($cmdFmt !~ m/^\d/);
return $err if($err);
+ return $@ if($@);
$cmdFmt = $ncmd if(defined($ncmd));
return "" if($ncmd && $ncmd eq "EMPTY"); # configAll
}
@@ -834,13 +835,13 @@ ZWave_Cmd($$@)
}
}
- my $r = ZWave_addToSendStack($baseHash, $data);
+ my $r = ZWave_addToSendStack($baseHash, $type, $data);
if($r) {
return (AttrVal($name,"verbose",3) > 2 ? $r : undef);
}
my $val;
- if($type eq "get") { # Wait for result
+ if($type eq "get" && $hash->{CL}) { # Wait for the result for frontend cmd
no strict "refs";
my $iohash = $hash->{IODev};
my $fn = $modules{$iohash->{TYPE}}{ReadAnswerFn};
@@ -853,9 +854,11 @@ ZWave_Cmd($$@)
$data = "$cmd $id $data" if($re);
$val = ($data ? ZWave_Parse($iohash, $data, $type) : "no data returned");
- ZWave_processSendStack($hash) if($data && $cmd eq "neighborList");
- } else {
+ ZWave_processSendStack($hash, "next") # No radio traffic for neighborList
+ if($data && $cmd eq "neighborList");
+
+ } elsif($type ne "get") {
$cmd .= " ".join(" ", @a) if(@a);
readingsSingleUpdate($hash, "state", $cmd, 1);
}
@@ -1547,48 +1550,6 @@ ZWave_meterSupportedParse($$)
" $meter_reset_text";
}
-sub
-ZWave_versionClassRequest($$)
-{
- my ($hash, $answer) = @_;
- my $name = $hash->{NAME};
-
- if($answer =~ m/^048614(..)(..)$/i) { # Parse part
- my $v = $hash->{versionhash};
- $v->{$zwave_id2class{lc($1)}} = $2;
- foreach my $class (keys %{$v}) {
- next if($v->{$class} ne "");
- my $r = ZWave_Set($hash, $name, "versionClassRequest", $class);
- return;
- }
- $attr{$hash->{NAME}}{vclasses} =
- join(" ", map { "$_:$v->{$_}" } sort keys %{$v});
- delete($hash->{versionhash});
- }
-
- if($answer ne "%s" && $hash->{versionhash}) { # get next
- return("", sprintf('13%02x', hex($zwave_class{$answer}{id})))
- if($zwave_class{$answer});
- return("versionClassRequest needs no parameter", "");
- }
-
- return("versionClassRequest needs no parameter", "")
- if($answer ne "%s" && !$hash->{versionhash});
-
- return("another versionClassRequest is already running", "")
- if(defined($hash->{versionhash}));
-
- # User part: called with no parameters
- my %h = map { $_ => "" }
- grep { $_ !~ m/^MARK$/ && $_ !~ m/^UNKNOWN/ }
- split(" ", AttrVal($name, "classes", ""));
- $hash->{versionhash} = \%h;
- foreach my $class (keys %h) {
- next if($h{$class} ne "");
- return("", sprintf('13%02x', hex($zwave_class{$class}{id})));
- }
- return("Should not happen", "");
-}
sub
ZWave_versionClassGet($)
@@ -1603,6 +1564,35 @@ ZWave_versionClassGet($)
return ("Unknown class $class", "");
}
+sub
+ZWave_versionClassAllGet($@)
+{
+ my ($hash, $data) = @_;
+ my $name = $hash->{NAME};
+ my $hname = ".versionClassAllGet";
+
+ if(!$data) { # called by the user
+ $zwave_parseHook{"$hash->{nodeIdHex}:..8614"} = \&ZWave_versionClassAllGet;
+ delete($hash->{CL});
+ my @arr = split(" ", AttrVal($name, "classes", ""));
+ $hash->{$hname} = \@arr;
+ ZWave_Get($hash, $name, "versionClass", shift @{$hash->{$hname}});
+ $attr{$name}{vclasses} = "";
+ return("", "EMPTY");
+ }
+
+ return 0 if($data !~ m/^048614(..)(..)$/i); # ??
+ $attr{$name}{vclasses} .= " " if($attr{$name}{vclasses});
+ $attr{$name}{vclasses} .= $zwave_id2class{lc($1)}.":".hex($2);
+ if(!int(@{$hash->{$hname}})) {
+ delete($hash->{$hname});
+ return 1; # "veto" for parseHook
+ }
+ ZWave_Get($hash, $name, "versionClass", shift @{$hash->{$hname}});
+ $zwave_parseHook{"$hash->{nodeIdHex}:..8614"} = \&ZWave_versionClassAllGet;
+ return 1; # "veto" for parseHook
+}
+
sub
ZWave_multilevelParse($$$)
{
@@ -2583,8 +2573,7 @@ ZWave_configAllGet($)
my $mc = ZWave_configGetHash($hash);
return ("configAll: no model specific configs found", undef)
if(!$mc || !$mc->{config});
- #use Data::Dumper;
- #Log 1, Dumper $mc;
+ delete($hash->{CL});
foreach my $c (sort keys %{$mc->{get}}) {
ZWave_Get($hash, $hash->{NAME}, $c);
}
@@ -2598,6 +2587,7 @@ ZWave_associationAllGet($$)
if(!$data) { # called by the user
$zwave_parseHook{"$hash->{nodeIdHex}:..85"} = \&ZWave_associationAllGet;
+ delete($hash->{CL});
ZWave_Get($hash, $hash->{NAME}, "associationGroups");
return("", "EMPTY");
}
@@ -2879,7 +2869,7 @@ ZWave_secAddToSendStack($$)
my $len = sprintf("%02x", (length($cmd)-2)/2+1);
my $cmdEf = (AttrVal($name, "noExplorerFrames", 0) == 0 ? "25" : "05");
my $data = "13$id$len$cmd$cmdEf$id"; # 13==SEND_DATA
- ZWave_addToSendStack($hash, $data);
+ ZWave_addToSendStack($hash, "set", $data);
}
sub
@@ -3497,14 +3487,23 @@ ZWave_isWakeUp($)
return $h->{isWakeUp};
}
+# stack contains type:hexcode
+# type is: set / sentset, get / sentget / sentackget
+# sentset will be discarded after ack, sentget needs ack (->sentackget) then msg
+# next discards either state.
+# acktpye: next, ack or msg
sub
-ZWave_processSendStack($)
+ZWave_processSendStack($$)
{
- my ($hash) = @_;
+ my ($hash,$ackType) = @_;
my $ss = $hash->{SendStack};
return if(!$ss);
- if(index($ss->[0],"sent") == 0) {
+ if($ss->[0] =~ m/^sent(.*?):(.*)$/) {
+ if($1 eq "get" && $ackType eq "ack") {
+ $ss->[0] = "sentackget:$2";
+ return;
+ }
shift @{$ss};
RemoveInternalTimer($hash) if(!ZWave_isWakeUp($hash));
}
@@ -3514,30 +3513,32 @@ ZWave_processSendStack($)
return;
}
- IOWrite($hash, $hash->{homeId}, "00".$ss->[0]);
- $ss->[0] = "sent:".$ss->[0];
+ $ss->[0] =~ m/^([^:]*?):(.*)$/;
+ my ($type, $msg) = ($1, $2);
+ IOWrite($hash, $hash->{homeId}, "00$msg");
+ $ss->[0] = "sent$type:$msg";
$hash->{lastMsgSent} = gettimeofday();
$zwave_lastHashSent = $hash;
if(!ZWave_isWakeUp($hash)) {
- InternalTimer($hash->{lastMsgSent}+10, sub {
- Log 2, "ZWave: No ACK from $hash->{NAME} after 10s for $ss->[0]";
- ZWave_processSendStack($hash);
+ InternalTimer($hash->{lastMsgSent}+3, sub {
+ Log 2, "ZWave: No ACK from $hash->{NAME} after 3s for $ss->[0]";
+ ZWave_processSendStack($hash, "next");
}, $hash, 0);
}
}
sub
-ZWave_addToSendStack($$)
+ZWave_addToSendStack($$$)
{
- my ($hash, $cmd) = @_;
+ my ($hash, $type, $cmd) = @_;
if(!$hash->{SendStack}) {
my @empty;
$hash->{SendStack} = \@empty;
}
my $ss = $hash->{SendStack};
- push @{$ss}, $cmd;
+ push @{$ss}, "$type:$cmd";
if(ZWave_isWakeUp($hash)) {
# SECURITY XXX and neighborList
@@ -3549,14 +3550,14 @@ ZWave_addToSendStack($$)
} else { # clear commands without 0113 and 0013
my $now = gettimeofday();
- if(@{$ss} > 1 && $now-$hash->{lastMsgSent} > 10) {
+ if(@{$ss} > 1 && $now-$hash->{lastMsgSent} > 3) {
Log3 $hash, 2,
- "ERROR: $hash->{NAME}: cleaning commands without ack after 10s";
+ "ERROR: $hash->{NAME}: cleaning commands without ack after 3s";
delete $hash->{SendStack};
- return ZWave_addToSendStack($hash, $cmd);
+ return ZWave_addToSendStack($hash, $type, $cmd);
}
}
- ZWave_processSendStack($hash) if(@{$ss} == 1);
+ ZWave_processSendStack($hash, "next") if(@{$ss} == 1);
return undef;
}
@@ -3598,7 +3599,7 @@ ZWave_Parse($$@)
my $hash = $zwave_lastHashSent;
readingsSingleUpdate($hash, "SEND_DATA", "failed:$arg", 1);
Log3 $ioName, 2, "ERROR: cannot SEND_DATA to $hash->{NAME}: $arg";
- ZWave_processSendStack($hash);
+ ZWave_processSendStack($hash, "next");
} else {
Log3 $ioName, 2, "ERROR: cannot SEND_DATA: $arg (unknown device)";
@@ -3674,7 +3675,7 @@ ZWave_Parse($$@)
if($hash) {
if(ZWave_isWakeUp($hash)) {
ZWave_wakeupTimer($hash, 1);
- ZWave_processSendStack($hash);
+ ZWave_processSendStack($hash, "next");
}
if(!$ret) {
@@ -3694,7 +3695,7 @@ ZWave_Parse($$@)
Log3 $ioName, 4, "$ioName transmit $lmsg for $callbackid";
if($hash) {
readingsSingleUpdate($hash, "transmit", $lmsg, 0);
- ZWave_processSendStack($hash);
+ ZWave_processSendStack($hash, "ack");
}
return "";
@@ -3816,11 +3817,6 @@ ZWave_Parse($$@)
next;
}
- if($className eq "VERSION" && defined($hash->{versionhash})) {
- ZWave_versionClassRequest($hash, $arg);
- return "";
- }
-
my $ptr = ZWave_getHash($hash, $className, "parse");
if(!$ptr) {
push @event, "UNPARSED:$className $arg";
@@ -3853,7 +3849,11 @@ ZWave_Parse($$@)
if($arg =~ m/^028407/) { # wakeup:notification
ZWave_wakeupTimer($hash, 1);
- ZWave_processSendStack($hash);
+ ZWave_processSendStack($hash, "next");
+
+ } else {
+ ZWave_processSendStack($hash, "msg");
+
}
return "" if(!@event);
@@ -4433,14 +4433,6 @@ s2Hex($)
available (deleted) and 1 for set (occupied). code is a hexadecimal string.
-
Class VERSION
-