]";
}
my $name = $a[0];
my $type = lc($a[2]);
my $deviceid = $a[3];
my $devicelog = $a[4];
$type = uc($type);
my $my_type;
if ($type eq "WD18" || $type eq "GD18" || $type eq "SD18" || $type eq "COD18" || $type eq "GB10E" ) {
$my_type = "DS10A"; # device will be received as DS10A
} else {
$my_type = $type;
}
my $device_name = "TRX".$DOT.$my_type.$DOT.$deviceid;
if ($type ne "DS10A" && $type ne "SD90" && $type ne "MS10A" && $type ne "MS14A" && $type ne "KR18" && $type ne "KD101" && $type ne "VISONIC_WINDOW" && $type ne "VISONIC_MOTION" && $type ne "VISONIC_WINDOW_AUX" && $type ne "VISONIC_REMOTE" && $type ne "MEIANTECH" && $type ne "SA30" && $type ne "GD18" && $type ne "WD18" && $type ne "SD18" && $type ne "COD18" && $type ne "GB10E") {
Log3 $hash, 1,"TRX_SECURITY_Define() wrong type: $type";
return "TRX_SECURITY: wrong type: $type";
}
$hash->{TRX_SECURITY_deviceid} = $deviceid;
$hash->{TRX_SECURITY_devicelog} = $devicelog;
$hash->{TRX_SECURITY_type} = $type;
#$hash->{TRX_SECURITY_CODE} = $deviceid;
$modules{TRX_SECURITY}{defptr}{$device_name} = $hash;
if (int(@a) == 7) {
# there is a second deviceid:
#
my $deviceid2 = $a[5];
my $devicelog2 = $a[6];
my $device_name2 = "TRX_SECURITY".$DOT.$deviceid2;
$hash->{TRX_SECURITY_deviceid2} = $deviceid2;
$hash->{TRX_SECURITY_devicelog2} = $devicelog2;
#$hash->{TRX_SECURITY_CODE2} = $deviceid2;
$modules{TRX_SECURITY}{defptr2}{$device_name2} = $hash;
}
AssignIoPort($hash);
return undef;
}
#####################################
sub
TRX_SECURITY_Undef($$)
{
my ($hash, $name) = @_;
delete($modules{TRX_SECURITY}{defptr}{$name});
return undef;
}
#####################################
sub TRX_SECURITY_parse_X10Sec($$) {
my ($hash, $bytes) = @_;
my $error;
my $subtype = $bytes->[1];
my $device;
if ($subtype >= 3) {
$device = sprintf '%02x%02x%02x', $bytes->[3], $bytes->[4], $bytes->[5];
} else {
# that's how we do it on 43_RFXX10REC.pm
$device = sprintf '%02x%02x', $bytes->[5], $bytes->[3];
}
my %security_devtype =
( # HEXSTRING =>
0x00 => [ "DS10A", "Window" ], # X10 security door/window sensor
0x01 => [ "MS10A", "motion" ], # X10 security motion sensor
0x02 => [ "KR18", "key" ], # X10 security remote (no alive packets)
0x03 => [ "KD101", "smoke" ], # KD101 (no alive packets)
0x04 => [ "VISONIC_WINDOW", "window" ], # Visonic PowerCode door/window sensor – primary contact (with alive packets)
0x05 => [ "VISONIC_MOTION", "motion" ], # Visonic PowerCode motion sensor (with alive packets)
0x06 => [ "VISONIC_REMOTE", "key" ], # Visonic CodeSecure (no alive packets)
0x07 => [ "VISONIC_WINDOW_AUX", "window" ], # Visonic PowerCode door/window sensor – auxiliary contact (no alive packets)
);
my $dev_type;
my $dev_reading;
if (exists $security_devtype{$subtype}) {
my $rec = $security_devtype{$subtype};
if (ref $rec) {
($dev_type, $dev_reading ) = @$rec;
} else {
$error = "TRX_SECURITY: x10_devtype wrong for subtype=$subtype";
Log3 $hash, 1, "TRX_SECURITY_parse_X10Sec() ".$error;
return "";
}
} else {
$error = "TRX_SECURITY: error undefined subtype=$subtype";
Log3 $hash, 1, "TRX_SECURITY_parse_X10Sec() ".$error;
return "";
}
#--------------
my $device_name = "TRX".$DOT.$dev_type.$DOT.$device;
Log3 $hash, 5, "TRX_SECURITY_parse_X10Sec() device_name=$device_name";
my $firstdevice = 1;
my $def = $modules{TRX_SECURITY}{defptr}{$device_name};
if(!$def) {
$firstdevice = 0;
$def = $modules{TRX_SECURITY}{defptr2}{$device_name};
if (!$def) {
Log3 $hash, 1, "TRX_SECURITY_parse_X10Sec() UNDEFINED $device_name TRX_SECURITY $dev_type $device $dev_reading";
Log3 $hash, 3, "TRX_SECURITY_parse_X10Sec() Unknown device $device_name, please define it";
return "UNDEFINED $device_name TRX_SECURITY $dev_type $device $dev_reading";
}
}
# Use $def->{NAME}, because the device may be renamed:
my $name = $def->{NAME};
return "" if(IsIgnored($name));
my $data = $bytes->[6];
my $hexdata = sprintf '%02x', $data;
my %x10_security =
(
0x00 => ['X10Sec', 'normal', 'min_delay', '', ''],
0x01 => ['X10Sec', 'normal', 'max_delay', '', ''],
0x02 => ['X10Sec', 'alert', 'min_delay', '', ''],
0x03 => ['X10Sec', 'alert', 'max_delay', '', ''],
0x04 => ['X10Sec', 'alert', '', '', ''],
0x05 => ['X10Sec', 'normal', '', '', ''],
0x06 => ['X10Sec', 'alert', '', '', ''],
0x07 => ['X10Sec', 'Security-EndPanic', '', '', ''],
0x08 => ['X10Sec', 'IR', '', '', ''],
0x09 => ['X10Sec', 'Security-Arm_Away', 'min_delay', '', ''], # kr18
0x0a => ['X10Sec', 'Security-Arm_Away', 'max_delay', '', ''], # kr18
0x0b => ['X10Sec', 'Security-Arm_Home', 'min_delay', '', ''], # kr18
0x0c => ['X10Sec', 'Security-Arm_Home', 'max_delay', '', ''], # kr18
0x0d => ['X10Sec', 'Security-Disarm', 'min_delay', '', ''], # kr18
0x10 => ['X10Sec', 'ButtonA-off', '', '', ''], # kr18
0x11 => ['X10Sec', 'ButtonA-on', '', '', ''], # kr18
0x12 => ['X10Sec', 'ButtonB-off', '', '', ''], # kr18
0x13 => ['X10Sec', 'ButtonB-on', '', '', ''], # kr18
0x14 => ['X10Sec', 'dark', '', '', ''],
0x15 => ['X10Sec', 'light', '', '', ''],
0x16 => ['X10Sec', 'normal', '', 'batt_low', ''],
0x17 => ['X10Sec', 'pair KD101', '', '', ''],
0x80 => ['X10Sec', 'normal', 'max_delay', '', 'tamper'],
0x81 => ['X10Sec', 'normal', 'min_delay', '', 'tamper'],
0x82 => ['X10Sec', 'alert', 'max_delay', '', 'tamper'],
0x83 => ['X10Sec', 'alert', 'min_delay', '', 'tamper'],
0x84 => ['X10Sec', 'alert', '', '', 'tamper'],
0x85 => ['X10Sec', 'normal', '', '', 'tamper'],
);
my $command = "";
my $type = "";
my $delay = "";
my $battery = "";
my $rssi = "";
my $option = "";
my @res;
if (exists $x10_security{$data}) {
my $rec = $x10_security{$data};
if (ref $rec) {
($type, $command, $delay, $battery, $option) = @$rec;
} else {
$command = $rec;
}
} else {
Log3 $name, 1, "TRX_SECURITY_parse_X10Sec() undefined command cmd=$data device-nr=$device, hex=$hexdata";
return "";
}
my $battery_level = $bytes->[7] & 0x0f;
if (($battery eq "") && ($dev_type ne "KD101")) {
if ($battery_level == 0x9) { $battery = 'batt_ok'}
elsif ($battery_level == 0x0) { $battery = 'batt_low'}
else {
Log3 $name, 1,"TRX_SECURITY_parse_X10Sec() unknown battery_level=$battery_level";
}
}
if ($trx_rssi == 1) {
$rssi = sprintf("%d", ($bytes->[7] & 0xf0) >> 4);
Log3 $name, 5, "TRX_SECURITY_parse_X10Sec() $name devn=$device_name rssi=$rssi";
}
my $current = "";
my $n = 0;
my $tm = TimeNow();
my $val = "";
my $device_type = uc($def->{TRX_SECURITY_type});
Log3 $name, 5, "TRX_SECURITY_parse_X10Sec() $name devn=$device_name first=$firstdevice subtype=$subtype device_type=$device_type command=$command, delay=$delay, batt=$battery cmd=$hexdata";
my $sensor = "";
if ($device_type eq "SD90") {
$sensor = $firstdevice == 1 ? $def->{TRX_SECURITY_devicelog} : $def->{TRX_SECURITY_devicelog2};
} else {
$sensor = $def->{TRX_SECURITY_devicelog};
}
$current = $command;
if (($device_type eq "DS10A") || ($device_type eq "VISONIC_WINDOW") || ($device_type eq "VISONIC_WINDOW_AUX")) {
$current = "Error";
$current = "Open" if ($command eq "alert");
$current = "Closed" if ($command eq "normal");
} elsif ($device_type eq "WD18" || $device_type eq "GD18") {
$current = "Error";
$current = "normal" if ($command eq "alert");
$current = "alert" if ($command eq "normal");
$delay = "";
$option = "";
}
readingsBeginUpdate($def);
if (($device_type ne "KR18") && ($device_type ne "VISONIC_REMOTE")) {
if ($firstdevice == 1) {
$val .= $current;
}
if ($sensor ne "none") { readingsBulkUpdate($def, $sensor, $current); }
# KD101 does not show normal, so statechange does not make sense
if (($def->{STATE} ne $val) && ($device_type ne "KD101")) {
$sensor = "statechange";
readingsBulkUpdate($def, $sensor, $current);
}
} else {
# kr18 remote control or VISONIC_REMOTE
$current = $command;
#$sensor = $def->{TRX_SECURITY_devicelog};
#$val = $current;
#readingsBulkUpdate($def, $sensor, $current);
$current = "Security-Panic" if ($command eq "alert");
my @cmd_split = split(/-/, $current);
$sensor = $cmd_split[0];
$current = $cmd_split[1];
readingsBulkUpdate($def, $sensor, $current);
$val .= $current;
}
if ($battery ne "") {
$sensor = "battery";
$current = "Error";
$current = "ok" if ($battery eq "batt_ok");
$current = "low" if ($battery eq "batt_low");
readingsBulkUpdate($def, $sensor, $current);
}
if ($rssi ne "") {
$sensor = "rssi";
readingsBulkUpdate($def, $sensor, $rssi);
}
if ($delay ne '') {
$sensor = "delay";
$current = "Error";
$current = "min" if ($delay eq "min_delay");
$current = "max" if ($delay eq "max_delay");
readingsBulkUpdate($def, $sensor, $current);
}
if ($option ne '') {
$val .= " ".$option;
}
if (($firstdevice == 1) && $val) {
$def->{STATE} = $val;
readingsBulkUpdate($def, "state", $val);
}
readingsEndUpdate($def, 1);
return $name;
}
sub
TRX_SECURITY_Parse($$)
{
my ($iohash, $hexline) = @_;
$trx_rssi = 0;
if (defined($attr{$iohash->{NAME}}{rssi})) {
$trx_rssi = $attr{$iohash->{NAME}}{rssi};
Log3 $iohash, 5,"TRX_SECURITY_Parse() attr rssi = $trx_rssi";
}
my $time = time();
# convert to binary
my $msg = pack('H*', $hexline);
if ($time_old ==0) {
Log3 $iohash, 5, "TRX_SECURITY_Parse() decoding delay=0 hex=$hexline";
} else {
my $time_diff = $time - $time_old ;
Log3 $iohash, 5, "TRX_SECURITY_Parse() decoding delay=$time_diff hex=$hexline";
}
$time_old = $time;
# convert string to array of bytes. Skip length byte
my @rfxcom_data_array = ();
foreach (split(//, substr($msg,1))) {
push (@rfxcom_data_array, ord($_) );
}
my $num_bytes = ord($msg);
if ($num_bytes < 3) {
return "";
}
my $type = $rfxcom_data_array[0];
Log3 $iohash, 5, "TRX_SECURITY_Parse() X10Sec num_bytes=$num_bytes hex=$hexline type=$type";
my $res = "";
if ($type == 0x20) {
Log3 $iohash, 5, "TRX_SECURITY_Parse() X10Sec num_bytes=$num_bytes hex=$hexline";
$res = TRX_SECURITY_parse_X10Sec($iohash, \@rfxcom_data_array);
Log3 $iohash, 1, "TRX_SECURITY_Parse() unsupported hex=$hexline" if ($res eq "");
return $res;
} else {
Log3 $iohash, 1, "TRX_SECURITY_Parse() not implemented num_bytes=$num_bytes hex=$hexline";
}
return "";
}
1;
=pod
=item device
=item summary interprets messages of security sensors received by TRX
=item summary_DE interpretiert Nachrichten von Sicherheitssensoren des TRX
=begin html
TRX_SECURITY
The TRX_SECURITY module interprets X10, KD101 and Visonic security sensors received by a RFXCOM RFXtrx433 RF receiver. You need to define an RFXtrx433 receiver first. See TRX.
Define
define <name> TRX_SECURITY <type> <deviceid> <devicelog> [<deviceid2> <devicelog2>]
<type>
specifies one of the following security devices:
-
DS10A
(X10 security ds10a Door/Window Sensor or compatible devices. This device type reports the status of the switch [Open/Closed], status of the delay switch [min|max]], and battery status [ok|low].)
-
SD18
or COD18
(X10 security sd18 smoke Sensor and COD18 CO Sensor). These device types report the status of the sensor [alert/normal] and battery status [ok|low])
-
MS10A
(X10 security ms10a motion sensor. This device type reports the status of motion sensor [normal|alert] and battery status [ok|low].))
-
SD90
(Marmitek sd90 smoke detector. This device type reports the status of the smoke detector [normal|alert] and battery status [ok|low].)
-
KR18
(X10 security remote control. Report the Reading "Security" with values [Arm|Disarm], "ButtonA" and "ButtonB" with values [on|off] )
-
KD101
(KD101 smoke sensor. Report the Reading "smoke" with values [normal|alert])
-
VISONIC_WINDOW
(VISONIC security Door/Window Sensor or compatible devices. This device type reports the status of the switch [Open/Closed] and battery status [ok|low].)
-
VISONIC_MOTION
(VISONIC security motion sensor. This device type reports the status of motion sensor [normal|alert] and battery status [ok|low].))
<deviceid>
specifies the first device id of the device. X10 security (DS10A, MS10A) and SD90 have a a 16 bit device id which has to be written as a hex-string (example "5a54"). All other devices have a 24 bit device id.
<devicelog>
is the name of the Reading used to report. Suggested: "Window" or "Door" for ds10a, "motion" for motion sensors, "smoke" for sd90, sd18 and cod18. If you use "none" then no additional Reading is reported. Just the state is used to report the change.
<deviceid2>
is optional and specifies the second device id of the device if it exists. For example sd90 smoke sensors can be configured to report two device ids.
<devicelog2>
is optional for the name used for the Reading of <deviceid2>
. If you use "none" then no additional Reading is reported. Just the state is used to report the change.
Example:
define livingroom_window TRX_SECURITY ds10a 72cd Window
define motion_sensor1 TRX_SECURITY ms10a 55c6 motion
define smoke_sensor1 TRX_SECURITY sd90 54d3 Smoke 54d3 Smoketest
Set
set <name> <value>
where value
is one of:
alert # only for KD101
pair # only for KD101
Example:
set TRX_KD101_a5ca00 alert
Get
Attributes
=end html
=cut