diff --git a/fhem/FHEM/10_ZWave.pm b/fhem/FHEM/10_ZWave.pm index a5919b3b8..c3d2cec0f 100755 --- a/fhem/FHEM/10_ZWave.pm +++ b/fhem/FHEM/10_ZWave.pm @@ -86,8 +86,11 @@ my %zwave_class = ( get => { smStatus => "04" }, parse => { "..3105(..)(..)(.*)" => 'ZWave_multilevelParse($1,$2,$3)'} }, METER => { id => '32', - get => { meter => "01" }, - parse => { "..3202(.*)"=> 'ZWave_meterParse($hash, $1)' } }, + set => { meterReset => "05" }, + get => { meter => 'Zwave_meterGet("%s")', + meterSupported => "03" }, + parse => { "..3202(.*)" => 'ZWave_meterParse($hash, $1)', + "..3204(.*)" => 'ZWave_meterSupportedParse($hash, $1)' } }, COLOR_CONTROL => { id => '33', get => { ccCapabilityGet => '01', # no more args ccStatus => '03', # no more args @@ -355,11 +358,6 @@ use vars qw(%zwave_deviceSpecial); get => { position=>"010f2602020000", }, parse => { "0891010f260303(..)(..)" => 'sprintf("position:Blinds %d Slat %d",hex($1),hex($2))' } } }, - Philio_PAN04 => { - METER => { - get_ADD => { meterWatt => "0110", #Watt - meterVoltage=> "0120", #Voltage - meterAmpere => "0128" } } },#Ampere ZME_KFOB => { ZWAVEPLUS_INFO => { # Example only. ORDER must be >= 50 @@ -649,33 +647,130 @@ ZWave_HrvStatus($) return join("\n", @l); } +my %zwm_unit = ( + energy=> ["kWh", "kVAh", "W", "pulseCount", "V", "A", "PowerFactor"], + gas => ["m3", "feet3", "undef", "pulseCount"], + water => ["m3", "feet3", "USgallons", "pulseCount"] +); + sub ZWave_meterParse($$) { my ($hash,$val) = @_; return if($val !~ m/^(..)(..)(.*)$/); - my ($v1, $v2, $v3) = (hex($1) & 0x1f, hex($2), $3); - my @prectab = (1,10,100,1000,10000,100000,1000000, 10000000); - my $prec = $prectab[($v2 >> 5) & 0x7]; + my ($v1, $v2, $v3) = (hex($1), hex($2), $3); + + my $name = $hash->{NAME}; + + # rate_type currently not used / not reported + my $rate_type = ($v1 >> 5) & 0x3; + my @rate_type_text =("undef","consumed", "produced"); + my $rate_type_text = ($rate_type > $#rate_type_text ? + "undef" : $rate_type_text[$rate_type]); + + my $meter_type = ($v1 & 0x1f); + my @meter_type_text =("undef", "energy", "gas", "water", "undef"); + my $meter_type_text = ($meter_type > $#meter_type_text ? + "undef" : $meter_type_text[$meter_type]); + + my $precision = ($v2 >>5) & 0x7; + # no definition for text or numbers, used as -> (10 ** hex($precision)) + + # V3 use 3 bit, in V2 there are only 2 bit available + # V3 use bit 7 of first byte as bit 3 of scale my $scale = ($v2 >> 3) & 0x3; - my $size = ($v2 >> 0) & 0x7; - my @txt = ("undef", "energy", "gas", "water"); - my $txt = ($v1 > $#txt ? "undef" : $txt[$v1]); - my %unit = (energy => ["kWh", "kVAh", "W", "pulseCount"], - gas => ["m3", "feet3", "undef", "pulseCount"], - water => ["m3", "feet3", "USgallons", "pulseCount"]); - my $unit = $txt eq "undef" ? "undef" : $unit{$txt}[$scale]; - $txt = "power" if ($unit eq "W"); - $v3 = hex(substr($v3, 0, 2*$size))/$prec; + $scale |= (($v1 & 0x80) >> 5); + + my $unit_text = ($meter_type_text eq "undef" ? + "undef" : $zwm_unit{$meter_type_text}[$scale]); + + my $size = $v2 & 0x7; - my $modelId = ReadingsVal($hash->{NAME}, "modelId", ""); - $modelId = $zwave_modelIdAlias{$modelId} if($zwave_modelIdAlias{$modelId}); - if($modelId eq "Philio_PAN04") { - if($prec==100 && $scale==1 && $size==2) { $unit="A"; $txt="current" } - if($prec== 10 && $scale==0 && $size==2) { $unit="V"; $txt="voltage" } - } + $meter_type_text = "power" if ($unit_text eq "W"); + $meter_type_text = "voltage" if ($unit_text eq "V"); + $meter_type_text = "current" if ($unit_text eq "A"); + + my $mv = hex(substr($v3, 0, 2*$size)); + $mv = $mv / (10 ** $precision); + $mv -= (2 ** ($size*8)) if $mv >= (2 ** ($size*8-1)); + $v3 = substr($v3, 2*$size, length($v3)-(2*$size)); - return "$txt:$v3 $unit"; + if (length($v3) < 4) { # V1 report + 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"; + + } else { # previous meter value present + my $pmv = hex(substr($v3, 0, 2*$size)); + $pmv = $pmv / (10 ** $precision); + $pmv -= (2 ** ($size*8)) if $pmv >= (2 ** ($size*8-1)); + + if ($delta_time == 65535) { + $delta_time = "unknown"; + } else { + $delta_time .= " s"; + }; + return "$meter_type_text: $mv $unit_text previous: $pmv delta_time: ". + "$delta_time"; # V2 report + }; + }; +} + + +sub +Zwave_meterGet($) +{ + my ($scale) = @_; + + if ($scale eq "%s") { # no parameter specified, use V1 get without scale + return("", "01"); + }; + + if (($scale < 0) || ($scale > 6)) { + return("argument must be one of: 0 to 6",""); + } else { + $scale = $scale << 3; + #~ Log 1, "cmd" .sprintf('01%02x', $scale); + return("",sprintf('01%02x', $scale)); + }; + +} + + +sub +ZWave_meterSupportedParse($$) +{ + my ($hash,$val) = @_; + return if($val !~ m/^(..)(..)$/); + my ($v1, $v2) = (hex($1), hex($2)); + + my $name = $hash->{NAME}; + + my $meter_reset = $v1 & 0x80; + my $meter_reset_text = $meter_reset ? "yes" : "no"; + + my $meter_type = ($v1 & 0x1f); + my @meter_type_text =("undef", "energy", "gas", "water", "undef"); + my $meter_type_text = ($meter_type > $#meter_type_text ? + "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"; } sub @@ -1749,6 +1844,14 @@ s2Hex($)