From 7981001f6aad2df016702187a86958bc9cfd77b6 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 25 Oct 2013 17:29:00 -0700 Subject: [PATCH 1/3] Insteon: Add Sync_All_Links Routine for Multigroup items; Add MultigroupDevice Package Added a package called MutigroupDevice in BaseInsteon.pm. The purpose of this package is to contain routines specific to all multigroup devices. Added Sync_All_links routines to MultigroupDevice. The routine will sync all links between any group on the device. Useful for KeyPadLincs and RemoteLincs and such. Fixes #85 --- lib/Insteon/BaseInsteon.pm | 147 +++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index b1b7259dc..82dacfa90 100644 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -2745,6 +2745,153 @@ You should have received a copy of the GNU General Public License along with thi =cut +#################################### +### ############### +### MultigroupDevice ############### +### ############### +#################################### + +=head1 B + +=head2 DESCRIPTION + +Contains functions which are unique to insteon devices which have more than +one group. This includes, KeyPadLincs, RemoteLincs, FanLincs, Thermostats +(i2 versions). + +=head2 INHERITS + +Nothing. + +This package is meant to provide supplemental support and should only be added +as a secondary inheritance to an object. + +=head2 METHODS + +=over + +=cut + +package Insteon::MultigroupDevice; + +=item C + +Syncs all links on the object, including all subgroups such as additional +buttons. + +Paramter B - Causes sync to walk through but not actually +send any commands to the devices. Useful with the insteon:3 debug setting for +troubleshooting. + +=cut + +sub sync_all_links +{ + my ($self, $audit_mode) = @_; + $self = $self->get_root(); + @{$$self{_sync_devices}} = (); + @{$$self{_sync_device_failures}} = (); + my $device_id = $self->device_id(); + my ($subgroup_object, $group, $dec_group); + + ::print_log("[Insteon::MultigroupDevice] Sync All Links on device " + .$self->get_object_name . " starting ..."); + # Find all subgroup items check groups from 02 - FF; + for ($dec_group = 02; $dec_group <= 255; $dec_group++) { + $group = sprintf("%02X", $dec_group); + $subgroup_object = Insteon::get_object($device_id, $group); + if (ref $subgroup_object){ + my %sync_req = ('sync_object' => $subgroup_object, + 'audit_mode' => ($audit_mode) ? 1 : 0); + ::print_log("[Insteon::MultigroupDevice] " + ."Adding " . $subgroup_object->get_object_name + ." to sync queue."); + push @{$$self{_sync_devices}}, \%sync_req + } + } + $$self{_sync_cnt} = scalar @{$$self{_sync_devices}}; + $self->_get_next_linksync(); +} + +=item C<_get_next_linksync()> + +Calls the sync_links() function for each device identified by sync_all_link. +This function will be called recursively since the callback passed to sync_links() +is this function again. Will also ask sync_links() to call +_get_next_linksync_failure() if sync_links() fails. + +=cut + +sub _get_next_linksync +{ + my ($self) = @_; + $self = $self->get_root(); + my $sync_req_ptr = shift(@{$$self{_sync_devices}}); + my %sync_req = ($sync_req_ptr) ? %$sync_req_ptr : undef; + my $current_sync_device; + if (%sync_req) { + $current_sync_device = $sync_req{'sync_object'}; + } + else { + $current_sync_device = undef; + } + + if ($current_sync_device) { + ::print_log("[Insteon::MultigroupDevice] Now syncing: " + . $current_sync_device->get_object_name . " (" + . ($$self{_sync_cnt} - scalar @{$$self{_sync_devices}}) + . " of ".$$self{_sync_cnt}.")"); + $current_sync_device->sync_links($sync_req{'audit_mode'}, + $self->get_object_name . '->_get_next_linksync()', + $self->get_object_name . '->_get_next_linksync_failure('.$current_sync_device->get_object_name.')'); + } + else { + ::print_log("[Insteon::MultigroupDevice] All links have completed syncing " + . "on device " . $self->get_object_name); + my $_sync_failure_cnt = scalar @{$$self{_sync_device_failures}}; + if ($_sync_failure_cnt) { + ::print_log("[Insteon::MultigroupDevice] However, some failures were noted:"); + for my $failed_obj (@{$$self{_sync_device_failures}}) { + ::print_log("[Insteon::MultigroupDevice] WARN: failure occurred when syncing " + . $failed_obj->get_object_name); + } + } + } +} + +=item C<_get_next_linksync()> + +Called by the failure callback in a device's sync_links() function. Will add +the failed device to the module global variable @_sync_device_failures. + +=cut + +sub _get_next_linksync_failure +{ + my ($self, $current_sync_device) = @_; + $self = $self->get_root(); + push @{$$self{_sync_device_failures}}, $current_sync_device; + ::print_log("[Insteon::MultigroupDevice] WARN: failure occurred when syncing " + . $current_sync_device->get_object_name . ". Moving on..."); + $self->_get_next_linksync(); +} + +=back + +=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 + #################################### ### ################# ### BaseController ################# From ed4ecba51c7277effbc16530ace6ff273224f26a Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 25 Oct 2013 17:39:00 -0700 Subject: [PATCH 2/3] Insteon: Add Sync All Links Voice Command to Multigroup Devices --- lib/Insteon/Controller.pm | 33 ++++++++++++++++++++++++++++- lib/Insteon/Lighting.pm | 44 ++++++++++++++++++++++++++++++++++----- lib/Insteon/Thermostat.pm | 13 +++++++++--- 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 4c1c67e30..93568a86f 100644 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -42,6 +42,7 @@ must first be put into "awake mode." L, L, +L =head2 METHODS @@ -54,7 +55,7 @@ package Insteon::RemoteLinc; use strict; use Insteon::BaseInsteon; -@Insteon::RemoteLinc::ISA = ('Insteon::BaseDevice','Insteon::DeviceController'); +@Insteon::RemoteLinc::ISA = ('Insteon::BaseDevice','Insteon::DeviceController', 'Insteon::MultigroupDevice'); my %message_types = ( %Insteon::BaseDevice::message_types, @@ -243,6 +244,36 @@ sub _process_message { return $clear_message; } +=item C + +Returns a hash of voice commands where the key is the voice command name and the +value is the perl code to run when the voice command name is called. + +Higher classes which inherit this object may add to this list of voice commands by +redefining this routine while inheriting this routine using the SUPER function. + +This routine is called by L to generate the +necessary voice commands. + +=cut + +sub get_voice_cmds +{ + my ($self) = @_; + my $object_name = $self->get_object_name; + my %voice_cmds = ( + %{$self->SUPER::get_voice_cmds} + ); + if ($self->is_root){ + %voice_cmds = ( + %voice_cmds, + 'sync all device links' => "$object_name->sync_all_links()", + 'AUDIT sync all device links' => "$object_name->sync_all_links(1)" + ); + } + return \%voice_cmds; +} + =back =head2 AUTHOR diff --git a/lib/Insteon/Lighting.pm b/lib/Insteon/Lighting.pm index 4b786516f..bfa473296 100644 --- a/lib/Insteon/Lighting.pm +++ b/lib/Insteon/Lighting.pm @@ -733,7 +733,8 @@ Provides support for the Insteon KeypadLinc Relay. =head2 INHERITS L, -L +L, +L =head2 METHODS @@ -746,7 +747,7 @@ package Insteon::KeyPadLincRelay; use strict; use Insteon::BaseInsteon; -@Insteon::KeyPadLincRelay::ISA = ('Insteon::BaseLight','Insteon::DeviceController'); +@Insteon::KeyPadLincRelay::ISA = ('Insteon::BaseLight','Insteon::DeviceController', 'Insteon::MultigroupDevice'); our %operating_flags = ( 'program_lock_on' => '00', @@ -876,7 +877,9 @@ sub get_voice_cmds 'set 8 button - backlight normal' => "$object_name->update_flags(\"02\")", 'set 6 button - backlight dim' => "$object_name->update_flags(\"08\")", 'set 6 button - backlight off' => "$object_name->update_flags(\"04\")", - 'set 6 button - backlight normal' => "$object_name->update_flags(\"00\")" + 'set 6 button - backlight normal' => "$object_name->update_flags(\"00\")", + 'sync all device links' => "$object_name->sync_all_links()", + 'AUDIT sync all device links' => "$object_name->sync_all_links(1)" ); } return \%voice_cmds; @@ -1036,7 +1039,8 @@ Provides support for the Insteon FanLinc. =head2 INHERITS L, -L +L, +L =head2 METHODS @@ -1049,7 +1053,7 @@ package Insteon::FanLinc; use strict; use Insteon::BaseInsteon; -@Insteon::FanLinc::ISA = ('Insteon::DimmableLight','Insteon::DeviceController'); +@Insteon::FanLinc::ISA = ('Insteon::DimmableLight','Insteon::DeviceController', 'Insteon::MultigroupDevice'); =item C @@ -1178,6 +1182,36 @@ sub is_acknowledged } } +=item C + +Returns a hash of voice commands where the key is the voice command name and the +value is the perl code to run when the voice command name is called. + +Higher classes which inherit this object may add to this list of voice commands by +redefining this routine while inheriting this routine using the SUPER function. + +This routine is called by L to generate the +necessary voice commands. + +=cut + +sub get_voice_cmds +{ + my ($self) = @_; + my $object_name = $self->get_object_name; + my %voice_cmds = ( + %{$self->SUPER::get_voice_cmds} + ); + if ($self->is_root){ + %voice_cmds = ( + %voice_cmds, + 'sync all device links' => "$object_name->sync_all_links()", + 'AUDIT sync all device links' => "$object_name->sync_all_links(1)" + ); + } + return \%voice_cmds; +} + =back =head2 AUTHOR diff --git a/lib/Insteon/Thermostat.pm b/lib/Insteon/Thermostat.pm index f7a6eef45..b66a7e14a 100755 --- a/lib/Insteon/Thermostat.pm +++ b/lib/Insteon/Thermostat.pm @@ -569,7 +569,7 @@ sub simple_message { package Insteon::Thermo_i2CS; use strict; -@Insteon::Thermo_i2CS::ISA = ('Insteon::Thermostat'); +@Insteon::Thermo_i2CS::ISA = ('Insteon::Thermostat', 'Insteon::MultigroupDevice'); our %message_types = ( %Insteon::Thermostat::message_types, @@ -1186,9 +1186,16 @@ sub get_voice_cmds my ($self) = @_; my $object_name = $self->get_object_name; my %voice_cmds = ( - %{$self->SUPER::get_voice_cmds}, - 'sync time' => "$object_name->sync_time()" + %{$self->SUPER::get_voice_cmds} ); + if ($self->is_root){ + %voice_cmds = ( + %{$self->SUPER::get_voice_cmds}, + 'sync time' => "$object_name->sync_time()", + 'sync all device links' => "$object_name->sync_all_links()", + 'AUDIT sync all device links' => "$object_name->sync_all_links(1)" + ); + } return \%voice_cmds; } From 65b63b0c1a80128d925da34478f61472f0842d6a Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 25 Oct 2013 17:39:00 -0700 Subject: [PATCH 3/3] Insteon: Multigroup Sync All Links to Scan Root Object Not sure why I omitted this before. --- lib/Insteon/BaseInsteon.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index 82dacfa90..daa008757 100644 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -2797,7 +2797,7 @@ sub sync_all_links ::print_log("[Insteon::MultigroupDevice] Sync All Links on device " .$self->get_object_name . " starting ..."); # Find all subgroup items check groups from 02 - FF; - for ($dec_group = 02; $dec_group <= 255; $dec_group++) { + for ($dec_group = 01; $dec_group <= 255; $dec_group++) { $group = sprintf("%02X", $dec_group); $subgroup_object = Insteon::get_object($device_id, $group); if (ref $subgroup_object){