diff --git a/fhem/FHEM/10_ZWave.pm b/fhem/FHEM/10_ZWave.pm index d31a09617..4b2634bb8 100644 --- a/fhem/FHEM/10_ZWave.pm +++ b/fhem/FHEM/10_ZWave.pm @@ -364,7 +364,8 @@ my %zwave_class = ( ZWAVEPLUS_INFO => { id => '5e', get => { zwavePlusInfo=>"01"}, parse => { "095e02(..)(..)(..)(....)(....)" - => 'ZWave_plusInfoParse($1,$2,$3,$4,$5)'} }, + => 'ZWave_plusInfoParse($1,$2,$3,$4,$5)'}, + init => { ORDER=>49, CMD => '"get $NAME zwavePlusInfo"' } }, ZIP_GATEWAY => { id => '5f' }, MULTI_CHANNEL => { id => '60', # Version 2, aka MULTI_INSTANCE set => { mcCreateAll => 'ZWave_mcCreateAll($hash,"")' }, @@ -445,7 +446,7 @@ my %zwave_class = ( => 'ZWave_mfsParse($hash,$1,$2,$3,1)', "0[8a]7205(....)(.{4})(.{4})(.*)" => 'ZWave_mfsParse($hash,$1,$2,$3,2)' }, - init => { ORDER=>49, CMD => '"get $NAME model"' } }, + init => { ORDER=> 1, CMD => '"get $NAME model"' } }, POWERLEVEL => { id => '73', set => { powerlevel => "01%02x%02x", powerlevelTest => "04%02x%02x%04x" }, @@ -542,7 +543,7 @@ my %zwave_class = ( '%d.%02d App %d.%d HW %d FWCounter %d FW %d.%d",'. 'unpack("C*",pack("H*","$1")))', "048614(..)(..)" => '"versionClass_".hex($1).":".hex($2)' }, - init => { ORDER=> 1, CMD => '"get $NAME versionClassAll"' } }, + init => { ORDER=> 2, CMD => '"get $NAME versionClassAll"' } }, INDICATOR => { id => '87', set => { indicatorOff => "0100", indicatorOn => "01FF", @@ -691,12 +692,11 @@ our %zwave_deviceSpecial; alarmAmbulanceOn=>"05000000000a030000", alarmPoliceOn =>"05000000000a010000", alarmDoorchimeOn=>"050000000006160000", - alarmBeepOn =>"05000000000a050000" } } }, - - ZME_KFOB => { - ZWAVEPLUS_INFO => { - # Example only. ORDER must be >= 50 - init => { ORDER=>50, CMD => '"get $NAME zwavePlusInfo"' } } } + alarmBeepOn =>"05000000000a050000" } } } +# ZME_KFOB => { +# ZWAVEPLUS_INFO => { +# # Example only. ORDER must be >= 50 +# init => { ORDER=>50, CMD => '"get $NAME zwavePlusInfo"' } } } ); my $zwave_cryptRijndael = 0; @@ -915,10 +915,33 @@ ZWave_execInits($$;$) my $homeReading = ReadingsVal($iodev->{NAME}, "homeId", "") if($iodev); my $CTRLID=hex($1) if($homeReading && $homeReading =~ m/CtrlNodeIdHex:(..)/); + # ZWavePlus devices with MCA need mcaAdd instead of associationAdd + my $cls = AttrVal($NAME, "classes", ""); + my $isMc = ($cls =~ m/ZWAVEPLUS_INFO/ && $cls =~ m/MULTI_CHANNEL_ASSOCIATION/); + my @cmd; + my $nih = $hash->{nodeIdHex}; foreach my $i (sort { $a->{ORDER}<=>$b->{ORDER} } @initList) { my $version = $hash->{".vclasses"}{$i->{CC}}; - push @cmd, eval $i->{CMD} if(!defined($version) || $version > 0); + if($isMc && $i->{CMD} =~ m/associationAdd 1/) { + $hash->{p1} = eval $i->{CMD}; # cannot access local variables + $hash->{p2} = eval '"set $NAME mcaAdd 1 0 $CTRLID 0"'; + next; + } + push @cmd, eval $i->{CMD} + if(!defined($version) || $version > 0); + } + + if($isMc) { + # Cannot access the stack here, only $hash (?) + $zwave_parseHook{"$nih:versionClassAll"} = sub(){ + my $mcaVers = $hash->{".vclasses"}{MULTI_CHANNEL_ASSOCIATION}; + return if(!$mcaVers); # called too early + AnalyzeCommand(undef, $hash->{$mcaVers < 3 ? "p1" : "p2"}); + delete($zwave_parseHook{"$hash->{nodeIdHex}:versionClassAll"}); + delete($hash->{p1}); + delete($hash->{p2}); + }; } push @cmd, ZWave_initFromModelfile($hash->{NAME}, $CTRLID, $cfg) @@ -1729,9 +1752,12 @@ ZWave_assocGroupCmdList($$) } my %zwm_unit = ( - energy=> ["kWh", "kVAh", "W", "pulseCount", "V", "A", "PowerFactor"], - gas => ["m3", "feet3", "undef", "pulseCount"], - water => ["m3", "feet3", "USgallons", "pulseCount"] + energy => ["kWh", "kVAh", "W", "pulseCount", "V", "A", "PowerFactor", "undef", + "kVar", "kVarh"], + gas => ["m3", "feet3", "undef", "pulseCount"], + water => ["m3", "feet3", "USgallons", "pulseCount"], + heating => ["kWh" ], + cooling => ["kWh" ] ); sub @@ -1750,7 +1776,7 @@ ZWave_meterParse($$) "undef" : $rate_type_text[$rate_type]); my $meter_type = ($v1 & 0x1f); - my @meter_type_text =("undef", "energy", "gas", "water", "undef"); + my @meter_type_text =("undef", "energy", "gas", "water", "heating", "cooling"); my $meter_type_text = ($meter_type > $#meter_type_text ? "undef" : $meter_type_text[$meter_type]); @@ -1759,6 +1785,7 @@ ZWave_meterParse($$) my $size = $v2 & 0x7; # 3 bits $scale |= (($v1 & 0x80) >> 5); + $scale = 8+hex(substr($v3, -2)) if($scale == 7); # V4 my $unit_text = ($meter_type_text eq "undef" ? "undef" : $zwm_unit{$meter_type_text}[$scale]); @@ -1772,14 +1799,14 @@ ZWave_meterParse($$) $v3 = substr($v3, 2*$size, length($v3)-(2*$size)); if (length($v3) < 4) { # V1 report - return "$meter_type_text: $mv $unit_text"; + return "$meter_type_text:$mv $unit_text"; } else { # V2 or greater report my $delta_time = hex(substr($v3, 0, 4)); $v3 = substr($v3, 4, length($v3)-4); if ($delta_time == 0) { # no previous meter value - return "$meter_type_text: $mv $unit_text"; + return "$meter_type_text:$mv $unit_text"; } else { # previous meter value present my $pmv = hex(substr($v3, 0, 2*$size)); @@ -1791,7 +1818,7 @@ ZWave_meterParse($$) } else { $delta_time .= " s"; }; - return "$meter_type_text: $mv $unit_text previous: $pmv delta_time: ". + return "$meter_type_text:$mv $unit_text previous: $pmv delta_time: ". "$delta_time"; # V2 report } } @@ -1806,19 +1833,18 @@ ZWave_meterGet($) return("", "01"); }; - if (($scale < 0) || ($scale > 6)) { - return("argument must be one of: 0 to 6",""); - } else { - $scale = $scale << 3; - return("",sprintf('01%02x', $scale)); - }; + if($scale < 7) { + return ("",sprintf('01%02x', $scale << 3)); + } else { # Version 4 + return ("",sprintf('01%02x%02x', 7<<3, $scale-8)); + } } #V2: 1b7:reset 1b65:resrvd, 1b4-0:type, 2b7-4:resrvd, 2b3-0:scale #V3: 1b7:reset 1b65:resrvd, 1b4-0:type, 2b:scale #V4: 1b7:reset 1b65:rate, 1b4-0:type, 2b7:mst, 2b6-0:scale1, 3b:#scaleBytes,... -# No V4 support... +# some V4 support... sub ZWave_meterSupportedParse($$) { @@ -1830,6 +1856,10 @@ ZWave_meterSupportedParse($$) my $meter_reset = $v1 & 0x80; my $meter_reset_text = $meter_reset ? "yes" : "no"; + my $meter_rate_type = ($v1 & 0x60) >> 5; + my @meter_rate_text = ("", ", import only (consumed)", + ", export only (produced)", ", both import and export"); + my $meter_rate_text = $meter_rate_text[$meter_rate_type]; my $meter_type = ($v1 & 0x1f); my @meter_type_text =("undef", "energy", "gas", "water", "undef"); @@ -1837,17 +1867,18 @@ ZWave_meterSupportedParse($$) "undef" : $meter_type_text[$meter_type]); my $scale = $v2 & 0x7f; - my $unit_text=""; - - for (my $i=0; $i <= 6; $i++) { - if ($scale & 2**$i) { - $unit_text .= ", " if (length($unit_text)>0); - $unit_text .= $i.":".$zwm_unit{$meter_type_text}[$i]; - }; - }; - - return "meterSupported: type: $meter_type_text scales: $unit_text resetable:". - " $meter_reset_text"; + my $l = 6; + if($v2 & 0x80 && $val =~ m/^....(..)(..)/) { + $l += 8; + $scale = hex($2)*256+$scale; + } + my @unit_text; + for (my $i=0; $i <= $l; $i++) { + last if(@{$zwm_unit{$meter_type_text}} <= $i); + push (@unit_text, "$i:".$zwm_unit{$meter_type_text}[$i]) if($scale & 2**$i); + } + return "meterSupported:type:$meter_type_text$meter_rate_text,". + " resetable:$meter_reset_text, scales: ".join(" ", @unit_text); } @@ -1890,6 +1921,11 @@ ZWave_versionClassAllGet($@) $hash->{".vclasses"}{$zwave_id2class{lc($1)}} = hex($2); $attr{$name}{vclasses} = join(" ", sort keys %h); } + + if($zwave_parseHook{"$hash->{nodeIdHex}:versionClassAll"}) { # Used by init + $zwave_parseHook{"$hash->{nodeIdHex}:versionClassAll"}->(); + } + return !$hash->{asyncGet}; # "veto" for parseHook/getAll } @@ -5409,11 +5445,12 @@ sub ZWave_firmware($$) { my ($hash, $args) = @_; - if($args) - { - return("Firmware update in progress. Please try update again later", "EMPTY") if(defined $hash->{FW_UPDATE_DATA}); + if($args) { + return("Firmware update in progress. Please try update again later", "EMPTY") + if(defined $hash->{FW_UPDATE_DATA}); my $classVersion = $hash->{".vclasses"}{FIRMWARE_UPDATE_MD}; - return("Firmware update with FIRMWARE_UPDATE_MD classversion > 4 not supported", "EMPTY") if($classVersion > 4); + return("Firmware update with FIRMWARE_UPDATE_MD classversion > 4 ". + "not supported", "EMPTY") if($classVersion > 4); my ($target, $fwFile) = split / /, $args; my $usage = "wrong argumets, need: "; return ($usage, "EMPTY") if (!$target || !$fwFile); @@ -5424,15 +5461,13 @@ ZWave_firmware($$) open(IN, $fName) || return "Cant open $fName: $!"; binmode(IN); my $buf; - while (1) - { - my $part = $l - length($buf); - my $success = read(IN, $buf, 100, length($buf)); - if( not defined $success) - { - return "Cant read $l bytes from $fName"; - } - last if not $success; + while (1) { + my $part = $l - length($buf); + my $success = read(IN, $buf, 100, length($buf)); + if( not defined $success) { + return "Cant read $l bytes from $fName"; + } + last if not $success; } close(IN); my $strbuff = unpack('H*',$buf); @@ -5444,19 +5479,18 @@ ZWave_firmware($$) $hash->{FW_UPDATE_DATA}->{CL} = $hash->{CL}; $hash->{FW_UPDATE_DATA}->{STAGE} = "INTERVIEW"; - Log3 $hash, 3, "ZWave_firmware: Target: $target FILE: $fName LENGTH: $l CRC $FwNewChkSum Version $classVersion"; - return("Firmware Update Version $classVersion does not support targets != 0", "EMPTY") if (int($target) != 0 && $classVersion < 3); + Log3 $hash, 3, "ZWave_firmware: Target: $target FILE: $fName ". + "LENGTH: $l CRC $FwNewChkSum Version $classVersion"; + return("Firmware Update Version $classVersion does not support targets != 0", + "EMPTY") if (int($target) != 0 && $classVersion < 3); } ZWave_firmwareSendCmd($hash, "01"); #send FIRMWARE_MD_GET - if(defined $hash->{FW_UPDATE_DATA}) - { + if(defined $hash->{FW_UPDATE_DATA}) { $zwave_parseHook{"$hash->{nodeIdHex}:..7a.*"} = \&ZWave_firmwareUpdateParse; return(ZWave_WibMsg($hash).", performing firmware update", "EMPTY"); - } - else - { + } else { return(ZWave_WibMsg($hash).", fetching firmware meta data", "EMPTY"); } } @@ -7088,7 +7122,7 @@ ZWave_firmwareUpdateParse($$$)
  • modelConfig:configLocation


  • Class METER -
  • energy:val [kWh|kVAh|pulseCount|powerFactor]
  • +
  • energy:val [kWh|kVAh|pulseCount|powerFactor|kVar|kVarh]
  • gas:val [m3|feet3|pulseCount]
  • water:val [m3|feet3|USgallons|pulseCount]
  • power:val W