From 8cbe4a9c002c7dd6322fb53efef8ba140c288815 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 9 Oct 2013 19:41:50 -0700 Subject: [PATCH] Insteon_TriggerLinc: Add Initial Support for TriggerLinc Devices Basically just a copy of code for RemoteLincs, however, TriggerLincs support even fewer commands so much of the code was cut down. I put the code in the Security.pm file as these are ostensible security devices, however as noted above, these are very similar to RemoteLincs. Although, they are not that dissimilar from Motion sensors which are also in this file. I don't own a TriggerLinc so this coding is all done blind. Thanks to @JaredF for his testing work. Closes #245 --- lib/Insteon/Security.pm | 216 +++++++++++++++++++++++++++++++++++++++- lib/read_table_A.pl | 6 ++ 2 files changed, 221 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/Security.pm b/lib/Insteon/Security.pm index ede4466e3..fe97e4014 100644 --- a/lib/Insteon/Security.pm +++ b/lib/Insteon/Security.pm @@ -703,5 +703,219 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +=head1 B + +=head2 SYNOPSIS + +Configuration: + +In user code: + + use Insteon::TriggerLinc; + $trigger = new Insteon::TriggerLinc('12.34.56:01',$myPLM); + +In items.mht: + + INSTEON_TRIGGERLINC, 12.34.56:01, $trigger, $trigger_group + +=head2 DESCRIPTION + +Provides support for Insteon TriggerLinc devices. These are relatively simple +devices that provide open and closed messages but not much else. Other than the +awake time, there are no other software configurable options. + +NOTE: There is a hardware configurable option which allows ON messages to be sent +as group 1 and OFF messages to be sent as group 2. If you enable this function +you will likely want to define and link the group 2 object by replacing ":01" +with ":02" in the above examples. + +=head3 Link Management + +As battery operated devices, these devices are generally asleep. If you want +MH to manage the links on these devices you need to wake them up, generally this +involves holding down the set button until the light flashes. + +Alternatively, if you set the awake time sufficiently high MH will be able to +initiate a communication with these devices for that many seconds after there +is activity (open/close) from these devices. This of course comes at the +expense of additional battery usage. + +=head2 INHERITS + +L, +L + +=head2 METHODS + +=over + +=cut + +package Insteon::TriggerLinc; + +use strict; +use Insteon::BaseInsteon; + +@Insteon::TriggerLinc::ISA = ('Insteon::BaseDevice','Insteon::DeviceController'); + +my %message_types = ( + %Insteon::BaseDevice::message_types +); + +=item C + +Instantiates a new object. + =cut -1 + +sub new +{ + my ($class,$p_deviceid,$p_interface) = @_; + + my $self = new Insteon::BaseDevice($p_deviceid,$p_interface); + $$self{message_types} = \%message_types; + bless $self,$class; + return $self; +} + +=item C + +Handles messages received from the device. Calls C. + +=cut + +sub set +{ + my ($self,$p_state,$p_setby,$p_response) = @_; + return if &main::check_for_tied_filters($self, $p_state); + + # Override any set_with_timer requests + if ($$self{set_timer}) { + &Timer::unset($$self{set_timer}); + delete $$self{set_timer}; + } + + my $setby_name = $p_setby; + $setby_name = $p_setby->get_object_name() if (ref $p_setby and $p_setby->can('get_object_name')); + &::print_log("[Insteon::TriggerLinc] " . $self->get_object_name() + . "::set_receive($p_state, $setby_name)") if $main::Debug{insteon}; + $self->set_receive($p_state,$p_setby); + return; +} + +=item C + +Sets the amount of time, in seconds, that the TriggerLinc will remain "awake" +after sending a command. While awake, the device can be queried by MH such as +with scan link table or sync links. + +=cut + +sub set_awake_time { + my ($self, $awake) = @_; + $awake = sprintf("%02x", $awake); + my $root = $self->get_root(); + my $extra = '000102' . $awake . '0000000000000000000000'; + $$root{_ext_set_get_action} = "set"; + my $message = new Insteon::InsteonMessage('insteon_ext_send', $root, 'extended_set_get', $extra); + $root->_send_cmd($message); + return; +} + +=item C + +Requests the status of various settings on the device. Currently this is only +used to obtain the awake time. If the device is awake, the awake time setting +will be printed to the log. + +=cut + +sub get_extended_info { + my ($self,$no_retry) = @_; + my $root = $self->get_root(); + my $extra = '000100000000000000000000000000'; + $$root{_ext_set_get_action} = "get"; + my $message = new Insteon::InsteonMessage('insteon_ext_send', $root, 'extended_set_get', $extra); + if ($no_retry){ + $message->retry_count(1); + } + $root->_send_cmd($message); + return; +} + +=item C<_process_message()> + +Checks for and handles unique TriggerLinc messages. +All other messages are transferred to L. + +=cut + +sub _process_message { + my ($self,$p_setby,%msg) = @_; + my $clear_message = 0; + my $root = $self->get_root(); + my $pending_cmd = ($$self{_prior_msg}) ? $$self{_prior_msg}->command : $msg{command}; + my $ack_setby = (ref $$self{m_status_request_pending}) ? $$self{m_status_request_pending} : $p_setby; + if ($msg{is_ack} && $self->_is_info_request($pending_cmd,$ack_setby,%msg)) { + $clear_message = 1; + $$self{m_status_request_pending} = 0; + $self->_process_command_stack(%msg); + } + elsif ($msg{command} eq "extended_set_get" && $msg{is_ack}){ + $self->default_hop_count($msg{maxhops}-$msg{hopsleft}); + #If this was a get request don't clear until data packet received + main::print_log("[Insteon::TriggerLinc] Extended Set/Get ACK Received for " . $self->get_object_name) if $main::Debug{insteon}; + if ($$self{_ext_set_get_action} eq 'set'){ + main::print_log("[Insteon::TriggerLinc] Clearing active message") if $main::Debug{insteon}; + $clear_message = 1; + $$self{_ext_set_get_action} = undef; + $self->_process_command_stack(%msg); + } + } + elsif ($msg{command} eq "extended_set_get" && $msg{is_extended}) { + if (substr($msg{extra},0,6) eq "000001") { + $self->default_hop_count($msg{maxhops}-$msg{hopsleft}); + #D3 = Awake Time; + my $awake = (hex(substr($msg{extra}, 6, 2))); + main::print_log("[Insteon::TriggerLinc] The awake seconds ". + "for device ". $self->get_object_name . " is set to: ". + $awake); + $clear_message = 1; + $self->_process_command_stack(%msg); + } else { + main::print_log("[Insteon::TriggerLinc] WARN: Corrupt Extended " + ."Set/Get Data Received for ". $self->get_object_name) if $main::Debug{insteon}; + } + } + else { + $clear_message = $self->SUPER::_process_message($p_setby,%msg); + } + return $clear_message; +} + +sub is_responder +{ + return 0; +} + +=back + +=head2 INI PARAMETERS + +None. + +=head2 AUTHOR + +Kevin Robert Keegan + +=head2 LICENSE + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +=cut + +1; diff --git a/lib/read_table_A.pl b/lib/read_table_A.pl index 8e28ae6c0..2cf4ab553 100644 --- a/lib/read_table_A.pl +++ b/lib/read_table_A.pl @@ -140,6 +140,12 @@ sub read_table_A { $other = join ', ', (map {"'$_'"} @other); # Quote data $object = "Insteon::MotionSensor(\'$address\', $other)"; } + elsif($type eq "INSTEON_TRIGGERLINC") { + require Insteon::Security; + ($address, $name, $grouplist, @other) = @item_info; + $other = join ', ', (map {"'$_'"} @other); # Quote data + $object = "Insteon::TriggerLinc(\'$address\', $other)"; + } elsif($type eq "INSTEON_IOLINC") { require Insteon::IOLinc; ($address, $name, $grouplist, @other) = @item_info;