From 76fbb433fae07a25cc61488ebae8934b4c32f789 Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Fri, 15 Jul 2016 14:11:43 +0000 Subject: [PATCH] 10_ZWave.pm: ALARM/NOTIFICATION patch from Andreas (Forum #53389) git-svn-id: https://svn.fhem.de/fhem/trunk@11794 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 3 +- fhem/FHEM/10_ZWave.pm | 487 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 399 insertions(+), 91 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index deca95f7e..607c63a44 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,6 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. - - feature 93_DbRep: new module added - reporting of database content + - changed: 10_ZWave: alarm Events text changed, comma replaced, Forum #53389 + - feature: 93_DbRep: new module added - reporting of database content written by DbLog, see commandref for details - feature: new module added: 52_I2C_SHT3x.pm (macs) - bugfix: 70_Jabber: log OTR empty message if debug-mode == 1 only diff --git a/fhem/FHEM/10_ZWave.pm b/fhem/FHEM/10_ZWave.pm index 386debecb..8b6e58d43 100755 --- a/fhem/FHEM/10_ZWave.pm +++ b/fhem/FHEM/10_ZWave.pm @@ -326,8 +326,23 @@ my %zwave_class = ( configAll => 'ZWave_configAllGet($hash)' }, parse => { "^..70..(..)(..)(.*)" => 'ZWave_configParse($hash,$1,$2,$3)'} }, ALARM => { id => '71', - get => { alarm => "04%02x" }, - parse => { "..7105(..)(..)(.*)" => 'ZWave_alarmParse($1,$2,$3)'} }, + set => { + alarmnotification => 'ZWave_ALARM_06_Set("%s")', # >=V2 + }, + get => { + alarmEventSupported => 'ZWave_ALARM_01_Get("%s")', # >=V3 + alarm => 'ZWave_ALARM_04_Get(1, "%s")', # >=V1 + alarmWithType => 'ZWave_ALARM_04_Get(2, "%s")', # >=V2 + alarmWithTypeEvent => 'ZWave_ALARM_04_Get(3, "%s")', # >=V3 + alarmTypeSupported => "07", # >=V2 + }, + parse => { + "..7102(.*)" => 'ZWave_ALARM_02_Report($1)', # >=V3 + "..7105(..)(..)(.*)" => + 'ZWave_ALARM_05_Report($hash, $1, $2, $3)', # >=V1 + "..7108(.*)" => 'ZWave_ALARM_08_Report($1)', # >=V2 + }, + }, MANUFACTURER_SPECIFIC => { id => '72', get => { model => "04" }, parse => { "0[8a]7205(....)(....)(....)(.*)" @@ -484,11 +499,15 @@ my %zwave_class = ( ); my %zwave_classVersion = ( - dimWithDuration => { min => 2 }, - meterReset => { min => 2 }, - meterSupported => { min => 2 }, - wakeupIntervalCapabilities => { min => 2 }, - + dimWithDuration => { min => 2 }, + meterReset => { min => 2 }, + meterSupported => { min => 2 }, + wakeupIntervalCapabilities => { min => 2 }, + alarmTypeSupported => { min => 2 }, + alarmnotification => { min => 2 }, + alarmWithType => { min => 2 }, + alarmWithTypeEvent => { min => 3 }, + alarmEventSupported => { min => 3 }, ); my %zwave_cmdArgs = ( @@ -549,7 +568,7 @@ my %zwave_pepperImg; my $p1_m = "([0-5][0-9])"; # mm 00-59 my $p2_hm = "([01][0-9]|2[0-3]):([0-5][0-9])"; # hh:mm my $p3_hms = "([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])"; # hh:mm:ss -my $p1_b = "([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])"; # byte:0-255, 1-3 digits +my $p1_b = "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])"; # byte:0-255, 1-3 digits my $p1_wd = "(mon|tue|wed|thu|fri|sat|sun)"; # 3 letter weekday # ymd: yyyy-mm-dd, yyyy 4 digits, mm 2 digits 01-12, dd 2 digits 01-31 my $p3_ymd = "([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])"; @@ -573,6 +592,7 @@ ZWave_Initialize($) classes do_not_notify:1,0 dummy:1,0 + extendedAlarmReadings:0,1,2 ignore:1,0 noExplorerFrames:1,0 eventForRaw @@ -2467,24 +2487,24 @@ my %zwave_alarmType = ( "0d"=>"HomeHealth" ); -my %zwave_alarmEvent = ( +my %zwave_alarmEvent = ( # no comma allowed in strings "0101"=>"detected", - "0102"=>"detected, Unknown Location", + "0102"=>"detected - Unknown Location", "0103"=>"Alarm Test", "0201"=>"detected", - "0202"=>"detected, Unknown Location", + "0202"=>"detected - Unknown Location", "0301"=>"detected", - "0302"=>"detected, Unknown Location", + "0302"=>"detected - Unknown Location", "0401"=>"Overheat detected", - "0402"=>"Overheat detected, Unknown Location", + "0402"=>"Overheat detected - Unknown Location", "0403"=>"Rapid Temperature Rise", - "0404"=>"Rapid Temperature Rise, Unknown Location", + "0404"=>"Rapid Temperature Rise - Unknown Location", "0405"=>"Underheat detected", - "0406"=>"Underheat detected, Unknown Location", + "0406"=>"Underheat detected - Unknown Location", "0501"=>"Leak detected", - "0502"=>"Leak detected, Unknown Location", + "0502"=>"Leak detected - Unknown Location", "0503"=>"Level Dropped", - "0504"=>"Level Dropped, Unknown Location", + "0504"=>"Level Dropped - Unknown Location", "0505"=>"Replace Filter", "0601"=>"Manual Lock Operation", "0602"=>"Manual Unlock Operation", @@ -2524,13 +2544,13 @@ my %zwave_alarmEvent = ( "064c"=>"Barrier associated with non-Z-wave remote control.", "0700"=>"Previous Events cleared", "0701"=>"Intrusion", - "0702"=>"Intrusion, Unknown Location", - "0703"=>"Tampering, product covering removed", - "0704"=>"Tampering, Invalid Code", + "0702"=>"Intrusion - Unknown Location", + "0703"=>"Tampering - product covering removed", + "0704"=>"Tampering - Invalid Code", "0705"=>"Glass Breakage", - "0706"=>"Glass Breakage, Unknown Location", + "0706"=>"Glass Breakage - Unknown Location", "0707"=>"Motion Detection", - "0708"=>"Motion Detection, Unknown Location", + "0708"=>"Motion Detection - Unknown Location", "0800"=>"Previous Events cleared", "0801"=>"Power has been applied", "0802"=>"AC mains disconnected", @@ -2587,31 +2607,221 @@ my %zwave_alarmEvent = ( "0d06"=>"Volatile Organic Compound level" ); +############################################## +### START: 0x71 ALARM (NOTIFICATION) + +### Renamed from ALARM to NOTIFICATION in V3 specification, +### for backward compatibility the name ALARM will be used +### regardless of the version of the class. + sub -ZWave_alarmParse($$$) -{ - my ($t,$l,$r) = @_; - - if($t=="00" && $r && $r =~ m/^..(..)(..)/) { # Forum #35178 - $l = $1; $t = $2; +ZWave_ALARM_01_Get($) { + # 0x7101 Alarm/Notification EventSupportedGet >= V3 + # alarmEventSupported + + my ($arg) = @_; + + foreach my $t (keys %zwave_alarmType) { + if (lc($zwave_alarmType{$t}) eq lc($arg)) { + return ("", "01".$t); + } } - - if(!$r || $r !~ m/......(..)(.*)/ || !$zwave_alarmType{$t}) { # V1 or unknown - return "alarm_type_$t:level $l"; - } - my ($e, $v4, $s) = ($1, $2, "alarm:$zwave_alarmType{$t}: "); - - if($l eq "00") { - $s .= "Event cleared: "; - $e = $1 if($v4 && $v4 =~ m/..(..)../); - } - - $s .= ($zwave_alarmEvent{"$t$e"} ? - $zwave_alarmEvent{"$t$e"} : "unknown event $e"); - $s .= ", arg $v4" if($v4 && $l ne "00"); - return $s; + return ("unknown notification type entered, see commandref", ""); } +sub +ZWave_ALARM_02_Report($) { + # 0x7102 Alarm/Notification EventSupportedReport >= V3 + # additional flagname "Appliance" in V4 + + my ($arg) = @_; + + if($arg !~ m/(..)(..)(.*)/) { + return ("wrong format received"); + } + + my $t = $1; + my $rt = "alarmEventSupported_"; + $rt .= ($zwave_alarmType{$t}) ? $zwave_alarmType{$t}.":" : + hex($t)."_unknown:"; + my $numBitMasks = $2 & 0x1f; + #my $res = ($2 & 0xe0) >> 5; # reserved field + + my $e = ""; + my $val = $3; + my $delimeter = ""; + + for (my $i=0; $i<$numBitMasks; $i++) { + my $supported = hex(substr($val, $i*2, 2)); + for (my $j=$i*8; $j<$i*8+8; $j++) { + if ($supported & (2 ** ($j-$i*8))) { + $e = sprintf("%s%02x", $t, $j); + $rt .= $delimeter; + $rt .= "(" . $j . ") "; + if (!$zwave_alarmEvent{$e}) { + $rt .= "unknown event"; + } else { + $rt .= $zwave_alarmEvent{$e}; + } + $delimeter = ", "; + } + } + } + return $rt; +} + +sub +ZWave_ALARM_04_Get($$) +{ + # 0x7104 Alarm/Notification alarmGet >= V1 + # alarm (V1), alarmWithType (V2), alarmWithTypeEvent (>=V3) + + my ($v, $arg) = @_; + my $rt = "04"; + + if ($v == 1) { + if($arg !~ m/^$p1_b$/) { + return ("wrong format, see commandref", ""); + } + $rt .= sprintf("%02x", $1); + return ("",$rt); + } elsif ($v == 2) { + if($arg !~ m/(.*)/) { + return ("wrong format, see commandref", ""); + } + foreach my $t (keys %zwave_alarmType) { + if (lc($zwave_alarmType{$t}) eq lc($1)) { + $rt .= sprintf("00%s", $t); + return ("", $rt); + } + } + } elsif ($v >= 3) { # V3=V4 + if($arg !~ m/(.*) $p1_b/) { + return ("wrong format, see commandref", ""); + } + foreach my $t (keys %zwave_alarmType) { + if (lc($zwave_alarmType{$t}) eq lc($1)) { + $rt .= sprintf("00%s%02x", $t, $2); + return ("", $rt); + } + } + } +} + +sub +ZWave_ALARM_05_Report($$$$) +{ + # 0x7105 Alarm/Notification Report >= V1 + # additional parameter in V2 and V3 + + my ($hash, $t, $l, $r) = @_; + my $name = $hash->{NAME}; + + my $rt0 = ""; + my $rt1 = ""; + my $at = ""; + my $level = ""; + my $eventname = ""; + my $ar = AttrVal($name, "extendedAlarmReadings",0); + + if (!$r) { #V1 Answer + $at = $zwave_alarmType{$t} ? $zwave_alarmType{$t} : + sprintf("%d_unknown", hex($t)); + $rt0 = "alarm_type_$t:level $l"; + $rt1 = "alarm_$at:level $l"; + } elsif ($r =~ m/(..)(..)(..)(..)(..)(.*)/) { + my ($zid, $ns, $t2, $e, $prop, $opt) = ($1, $2, $3, $4, $5, $6); + + if ($e ne "00") { + if (($t ne "00") && ($l eq "00")) { + $level = "Event cleared: "; + } + } else { + $level = "Event cleared: "; + my $len = hex($prop & 0x1f); + if (($len >= 1) && ($opt =~ m/(..)(.*)/)) { + $e = $1; + } + } + $eventname = $zwave_alarmEvent{"$t2$e"} ? $zwave_alarmEvent{"$t2$e"} + : sprintf("unknown event %d", hex($e)); + $at = $zwave_alarmType{$t2} ? $zwave_alarmType{$t2} : + sprintf("%d_unknown", hex($t2)); + my $nst = ($ns eq "ff") ? "notificationIsOn" : "notificationIsOff"; + my $o = ($opt && ($e ne "00")) ? ", arg $prop$opt" : ""; + + $rt0 = "alarm:$at: $level $eventname$o"; + $rt1 = "alarm_$at: $level $eventname$o, $nst"; + } + + if ($ar == 0) { + return ($rt0); + } elsif ($ar == 1) { + return ($rt1); + } elsif ($ar == 2) { + return ($rt0, $rt1); + } +} + +sub +ZWave_ALARM_06_Set($) { + # 0x7106 Alarm/Notification alarmSet (>=V2) + # alarmnotification + + my ($arg) = @_; + + if($arg !~ m/^(.*) (on|off)$/i) { + return ("wrong format, see commandref", ""); + } + my $status = (lc($2) eq "on") ? "FF" : "00"; + foreach my $t (keys %zwave_alarmType) { + if (lc($zwave_alarmType{$t}) eq lc($1)) { + return ("", "06".$t.$status); + } + } + return ("alarm/notification type not defined",""); +} + +sub +ZWave_ALARM_08_Report($) { + # 0x7108 Alarm/Notification TypeSupportedReport >= V2 + # additional flagname "Appliance" in V4 + + my ($arg) = @_; + + if($arg !~ m/(..)(.*)/) { + return ("wrong format received"); + } + + my $numBitMasks = $1 & 0x1f; + #my $res = ($1 & 0x60) >> 5; # reserved field + my $alarm_v1 = $1 & 0x80; # 0:standard types, 1:V1 non-standard + + if ($alarm_v1) { + return ("alarmTypeSupported:non-standard V1 Alarm Types used"); + } else { + my $rt = "alarmTypeSupported:"; + my $t = ""; + my $val = $2; + my $delimeter = ""; + + for (my $i=0; $i<$numBitMasks; $i++) { + my $supported = hex(substr($val, $i*2, 2)); + for (my $j=$i*8; $j<$i*8+8; $j++) { + if ($supported & (2 ** ($j-$i*8))) { + $t = sprintf("%02x", $j); + $rt .= sprintf("$delimeter$zwave_alarmType{$t}"); + $delimeter = " "; + } + } + } + return $rt; + } +} + +### END: 0x71 ALARM/NOTIFICATION +############################################## + sub ZWave_protectionParse($$) { @@ -4400,6 +4610,21 @@ s2Hex($)
  • sucRouteDel
    Delete static return routes to SUC/SIS node.
  • +

    Class ALARM (NOTIFICATION), V4 +
  • alarmnotification <alarmType> (on|off)
    + Enable (on) or disable (off) the sending of unsolicited reports for + the alarm type <alarmType>. A list of supported alarm types of the + device can be obtained with the "alarmTypeSupported" command. The + name of the alarm type is case insensitive. Sending of an unsolicted + notification only work to associated nodes, broadcasting is not + allowed, so associations have to be set up. This command is + specified in version 2.
  • +
  • Note:
    + The name of the class ALARM was renamend to NOTIFICATION in + version 3 of the Zwave specification. Due to backward compatibility + reasons the class will be always referenced as ALARM in FHEM, + regardless of the version.
  • +

    Class ASSOCIATION
  • associationAdd groupId nodeId ...
    Add the specified list of nodeIds to the association group groupId.
    Note: @@ -4590,6 +4815,13 @@ s2Hex($)
  • location LOCATION
    Store LOCATION in the EEPROM. Note: only ASCII is supported.
  • +

    Class NOTIFICATION +
  • Note:
    + The name of the class ALARM was renamend to NOTIFICATION in + version 3 of the Zwave specification. Due to backward compatibility + reasons the class will be always referenced as ALARM in FHEM, + regardless of the version. Please refer to class ALARM.
  • +

    Class POWERLEVEL
  • Class is only used in an installation or test situation
  • powerlevel level timeout/s
    @@ -4631,8 +4863,8 @@ s2Hex($)
  • scheduleEntryLockSet USER_ID ENABLED
    enables or disables schedules for a specified user ID (V1)
  • @@ -4646,9 +4878,10 @@ s2Hex($) STARTTIME ENDTIME
    erase or set a week day schedule for a specified user ID (V1)