From 43298d143b907717f2343ff41b8b0735e541d1fe Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 9 May 2013 21:53:27 -0700 Subject: [PATCH 01/49] Insteon_Remotelinc: Added Ability to Set Awake Time and To Request Battery Status The following likely only works for i2cs devices, I think all Remotelinc 2 devices are i2cs? It at least works on rev 1.4. - set_awake_time sets = sets the time in seconds that the remote will remain awake after sending a command. The default is 4, it can be set up to 254 seconds, with 255 being always awake. - get_extended_info = is primarily added to get the battery level. Battery level is returned as a byte, but the number does not immediately make sense. I will have to let the batter run down some to better understand what it means. At the moment, I have the code set to call get_extended_info whenever the all_link_report is received. This report represents the last message sent by the device before the awake time begins to run. In the future, an additional function can be added to only call get_extended_info if it hasn't been called in x hours. N.B. in order for set_awake_time to work properly, the engine version of the device must be known. hollie/misterhouse#172 --- lib/Insteon/Controller.pm | 62 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 45b77b9ad..263d96f28 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -9,7 +9,8 @@ use Insteon::BaseInsteon; my %message_types = ( %Insteon::BaseDevice::message_types, bright => 0x15, - dim => 0x16 + dim => 0x16, + extended_set_get => 0x2e ); sub new @@ -49,6 +50,65 @@ sub set return; } +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; +} + +sub get_extended_info { + my ($self) = @_; + 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); + $root->_send_cmd($message); + return; +} + +sub _process_message { + my ($self,$p_setby,%msg) = @_; + my $clear_message = 0; + if ($msg{command} eq 'link_cleanup_report'){ + #Queue an get_extended_info request + $self->get_extended_info(); + } + if ($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::RemoteLinc] 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::RemoteLinc] 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}); + #D10 = Battery; + main::print_log("[Insteon::RemoteLinc] The battery level ". + "for device ". $self->get_object_name . " is: ". + hex(substr($msg{extra}, 20, 2))); + $clear_message = 1; + $self->_process_command_stack(%msg); + } else { + main::print_log("[Insteon::RemoteLinc] 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; From 970c3343bc0643433ecf3da2d388e93403b1c70a Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 10 May 2013 18:35:25 -0700 Subject: [PATCH 02/49] Insteon_RemoteLinc: Add Perl Documentation --- lib/Insteon/Controller.pm | 101 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 263d96f28..dc5e8d0ca 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -1,3 +1,52 @@ +=head1 B + +=head2 SYNOPSIS + +Configuration: + +Depending on your device and your settings, your remote may offer 1, 4, or 8 +groups. Your configuration should vary depeninding on you remote style. + +In user code: + + use Insteon::RemoteLinc; + $remote_1 = new Insteon::RemoteLinc('12.34.56:01',$myPLM); + $remote_2 = new Insteon::RemoteLinc('12.34.56:02',$myPLM); + $remote_3 = new Insteon::RemoteLinc('12.34.56:03',$myPLM); + $remote_4 = new Insteon::RemoteLinc('12.34.56:04',$myPLM); + +In items.mht: + + INSTEON_REMOTELINC, 12.34.56:01, $remote_1, $remote_group + INSTEON_REMOTELINC, 12.34.56:02, $remote_2, $remote_group + INSTEON_REMOTELINC, 12.34.56:03, $remote_3, $remote_group + INSTEON_REMOTELINC, 12.34.56:04, $remote_4, $remote_group + +=head2 DESCRIPTION + +Provides basic support for Insteon RemoteLinc models 1 and 2. Basic support +includes, linking and receiving set commands from the device. More advanced +support is offered for RemoteLinc 2 in the form of battery level notifications. + +MisterHouse is only able to communicate with a RemoteLinc when it is in "awake +mode." The device is in "awake mode" while in its linking state. To put the +RemoteLinc into "awake mode", follow the instructions for placing the device into +linking mode. In short, the instructions are to hold down the set button for 4-10 +seconds until you hear a beep and see the light flash. The RemoteLinc will now +remain in "awake mode" for approximately 4 minutes. + +To scan the link table, sync links, or set settings on the device, the RemoteLinc +must first be put into "awake mode." + +=head2 INHERITS + +B, B + +=head2 METHODS + +=over + +=cut package Insteon::RemoteLinc; @@ -50,6 +99,21 @@ sub set return; } +=item C + +Only available for RemoteLinc 2 models. + +Sets the amount of time, in seconds, that the RemoteLinc will remain "awake" +after sending a command. MH uses the awake time to send batter level requests +to the device. If the device is not responding to the battery level requests, +consider increasing this value. However, keep in mind that a longer awake time +will result in more battery usage. + +The factory setting is 4 seconds, 10 seconds seems to work with MisterHouse +without causing adverse battery drain. + +=cut + sub set_awake_time { my ($self, $awake) = @_; $awake = sprintf("%02x", $awake); @@ -61,6 +125,20 @@ sub set_awake_time { return; } +=item C + +Only available for RemoteLinc 2 models. + +Requests the status of various settings on the device. Currently this is only +used to obtain the battery level. If the device is awake, the battery level +will be printed to the log. + +You likely do not need to directly call this message, rather MisterHouse will issue +this request when it sees activity from the device and the C has +expired. + +=cut + sub get_extended_info { my ($self) = @_; my $root = $self->get_root(); @@ -114,4 +192,27 @@ sub is_responder return 0; } +=back + +=head2 INI PARAMETERS + +None. + +=head2 AUTHOR + +Bruce Winter, Gregg Limming, Kevin Robert Keegan + +=head2 SEE ALSO + + + +=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 \ No newline at end of file From b89d698bfe9d6b3eaf406ddbb2e1bdbce5bbeccc Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 10 May 2013 18:39:25 -0700 Subject: [PATCH 03/49] Insteon_RemoteLinc: Add Set Battery Timer --- lib/Insteon/Controller.pm | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index dc5e8d0ca..06eda228f 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -68,6 +68,9 @@ sub new my $self = new Insteon::BaseDevice($p_deviceid,$p_interface); $$self{message_types} = \%message_types; + if ($self->is_root){ + $self->restore_data('battery_timer', 'last_battery_time'); + } bless $self,$class; return $self; } @@ -104,7 +107,7 @@ sub set Only available for RemoteLinc 2 models. Sets the amount of time, in seconds, that the RemoteLinc will remain "awake" -after sending a command. MH uses the awake time to send batter level requests +after sending a command. MH uses the awake time to send battery level requests to the device. If the device is not responding to the battery level requests, consider increasing this value. However, keep in mind that a longer awake time will result in more battery usage. @@ -134,7 +137,7 @@ used to obtain the battery level. If the device is awake, the battery level will be printed to the log. You likely do not need to directly call this message, rather MisterHouse will issue -this request when it sees activity from the device and the C has +this request when it sees activity from the device and the C has expired. =cut @@ -149,6 +152,27 @@ sub get_extended_info { return; } +=item C + +Only available for RemoteLinc 2 models. + +Sets the minimum amount of time between battery level requests. When this time +expires, Misterhouse will request the battery level from the device the next time +MisterHouse sees activity from the device. Misterhouse will continue to request +the battery level until it gets a response from the device. + +This setting will be saved between MisterHouse reboots. + +=cut + +sub set_battery_timer { + my ($self, $minutes) = @_; + my $root = $self->get_root(); + $$root{battery_timer} = $minutes; + ::print_log("[Insteon::RemoteLinc] Set battery timer to $minutes minutes"); + return; +} + sub _process_message { my ($self,$p_setby,%msg) = @_; my $clear_message = 0; From c2fb74cf998c4be15156754b729fd68fd81c08ca Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 10 May 2013 18:41:25 -0700 Subject: [PATCH 04/49] Insteon_RemoteLinc: Add Check for If Battery Timer Expired --- lib/Insteon/Controller.pm | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 06eda228f..6ca200100 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -173,10 +173,20 @@ sub set_battery_timer { return; } +sub _is_battery_time_expired { + my ($self) = @_; + my $root = $self->get_root(); + if (defined $$root{battery_timer} && + (time - ($$root{last_battery_time} * 60)) > $$root{battery_timer}) { + return 1; + } + return 0; +} + sub _process_message { my ($self,$p_setby,%msg) = @_; my $clear_message = 0; - if ($msg{command} eq 'link_cleanup_report'){ + if ($msg{command} eq 'link_cleanup_report' && $self->_is_battery_time_expired){ #Queue an get_extended_info request $self->get_extended_info(); } From 42ec1da33e92b7f9726716da7809f0bfebe5ee2c Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 10 May 2013 18:41:25 -0700 Subject: [PATCH 05/49] Insteon_RemoteLinc: Cleanup Battery Timer --- lib/Insteon/Controller.pm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 6ca200100..1f4914e3d 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -161,6 +161,8 @@ expires, Misterhouse will request the battery level from the device the next tim MisterHouse sees activity from the device. Misterhouse will continue to request the battery level until it gets a response from the device. +Setting to 0 will disable automatic battery level requests. + This setting will be saved between MisterHouse reboots. =cut @@ -168,15 +170,16 @@ This setting will be saved between MisterHouse reboots. sub set_battery_timer { my ($self, $minutes) = @_; my $root = $self->get_root(); - $$root{battery_timer} = $minutes; - ::print_log("[Insteon::RemoteLinc] Set battery timer to $minutes minutes"); + $$root{battery_timer} = sprintf("%u", $minutes); + ::print_log("[Insteon::RemoteLinc] Set battery timer to ". + $$root{battery_timer}." minutes"); return; } sub _is_battery_time_expired { my ($self) = @_; my $root = $self->get_root(); - if (defined $$root{battery_timer} && + if ($$root{battery_timer} > 0 && (time - ($$root{last_battery_time} * 60)) > $$root{battery_timer}) { return 1; } From 05e702f0af8de8c9ad574b74d32509d3ba63095f Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 10 May 2013 18:45:25 -0700 Subject: [PATCH 06/49] Insteon_RemoteLinc: Add the Low Battery Level Indicator --- lib/Insteon/Controller.pm | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 1f4914e3d..fac8a93e5 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -69,7 +69,7 @@ sub new my $self = new Insteon::BaseDevice($p_deviceid,$p_interface); $$self{message_types} = \%message_types; if ($self->is_root){ - $self->restore_data('battery_timer', 'last_battery_time'); + $self->restore_data('battery_timer', 'last_battery_time', 'low_battery_level'); } bless $self,$class; return $self; @@ -161,7 +161,7 @@ expires, Misterhouse will request the battery level from the device the next tim MisterHouse sees activity from the device. Misterhouse will continue to request the battery level until it gets a response from the device. -Setting to 0 will disable automatic battery level requests. +Setting to 0 will disable automatic battery level requests. 1440 equals a day. This setting will be saved between MisterHouse reboots. @@ -176,6 +176,25 @@ sub set_battery_timer { return; } +=item C + +Only available for RemoteLinc 2 models. + +If the battery level falls below this percentage, the C +command is run. + +=cut + +sub set_low_battery_level { + my ($self, $level) = @_; + $level =~ s/(\d+)%?/$1/; + my $root = $self->get_root(); + $$root{low_battery_level} = sprintf("%u", $level); + ::print_log("[Insteon::RemoteLinc] Set low battery level to ". + $$root{low_battery_level}."%"); + return; +} + sub _is_battery_time_expired { my ($self) = @_; my $root = $self->get_root(); From d3d70f54d9e1f034bc9f01bc42a03c9cfbcdec81 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 10 May 2013 18:45:25 -0700 Subject: [PATCH 07/49] Insteon_RemoteLinc: Add Set Low Battery Event --- lib/Insteon/Controller.pm | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index fac8a93e5..561ddd8af 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -183,6 +183,8 @@ Only available for RemoteLinc 2 models. If the battery level falls below this percentage, the C command is run. +This setting will be saved between MisterHouse reboots. + =cut sub set_low_battery_level { @@ -195,6 +197,30 @@ sub set_low_battery_level { return; } +=item C + +Only available for RemoteLinc 2 models. + +If the battery level falls below the percentage defined by C +this command is evaluated. Works very similar to a C +eval. + +Example: + + $remote->battery_low_event('speak "Warning, Remote battery is low."'); + +This setting will be saved between MisterHouse reboots. + +=cut + +sub battery_low_event { + my ($self, $eval) = @_; + my $root = $self->get_root(); + $$root{low_battery_event} = $eval; + ::print_log("[Insteon::RemoteLinc] Set low battery event."); + return; +} + sub _is_battery_time_expired { my ($self) = @_; my $root = $self->get_root(); From 78db98be6684f4e571697e318d6d3731a5ffc3c0 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 10 May 2013 18:55:25 -0700 Subject: [PATCH 08/49] Insteon_RemoteLinc: Add Eval to Battery Low Level Event --- lib/Insteon/Controller.pm | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 561ddd8af..952479ab9 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -69,7 +69,8 @@ sub new my $self = new Insteon::BaseDevice($p_deviceid,$p_interface); $$self{message_types} = \%message_types; if ($self->is_root){ - $self->restore_data('battery_timer', 'last_battery_time', 'low_battery_level'); + $self->restore_data('battery_timer', 'last_battery_time', + 'low_battery_level', 'low_battery_event'); } bless $self,$class; return $self; @@ -183,6 +184,8 @@ Only available for RemoteLinc 2 models. If the battery level falls below this percentage, the C command is run. +Setting to 0 will prevent any low battery events from occuring. + This setting will be saved between MisterHouse reboots. =cut @@ -209,6 +212,8 @@ Example: $remote->battery_low_event('speak "Warning, Remote battery is low."'); +See C for more examples. + This setting will be saved between MisterHouse reboots. =cut @@ -231,9 +236,20 @@ sub _is_battery_time_expired { return 0; } +sub _is_battery_low { + my ($self, $percent) = @_; + my $root = $self->get_root(); + if ($$root{low_battery_level} > 0 && + ($$root{low_battery_level} > $percent)) { + return 1; + } + return 0; +} + sub _process_message { my ($self,$p_setby,%msg) = @_; my $clear_message = 0; + my $root = $self->get_root(); if ($msg{command} eq 'link_cleanup_report' && $self->_is_battery_time_expired){ #Queue an get_extended_info request $self->get_extended_info(); @@ -252,10 +268,18 @@ sub _process_message { 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}); - #D10 = Battery; + #D10 = Battery; + my $percent = hex(substr($msg{extra}, 20, 2)); main::print_log("[Insteon::RemoteLinc] The battery level ". "for device ". $self->get_object_name . " is: ". - hex(substr($msg{extra}, 20, 2))); + $percent . "%"); + if ($self->_is_battery_low){ + package main; + eval $$root{low_battery_event}; + ::print_log("[Insteon::RemoteLinc] " . $self->{device}->get_object_name . ": error during low battery event eval $@") + if $@; + package Insteon::RemoteLinc; + } $clear_message = 1; $self->_process_command_stack(%msg); } else { From 2f14a4b8d24ddc86c137919408e7ac87ac8cc100 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 10 May 2013 18:56:44 -0700 Subject: [PATCH 09/49] Insteon_Remotelinc: Change Battery Level to Volts; Cleanup Coding Errors I think that the battery level is reported is volts * 50. Online it lists the battery voltage as 3.7 and I am getting numbers like 177 right now. Finally, one stray comment from Insteon suggested that they believe 0xA3 or 163 to be the low voltage warning level. --- lib/Insteon/Controller.pm | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 952479ab9..537273afd 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -177,14 +177,15 @@ sub set_battery_timer { return; } -=item C +=item C Only available for RemoteLinc 2 models. -If the battery level falls below this percentage, the C -command is run. +If the battery level falls below this voltage, the C +command is run. The theoretical maximum voltage of the battery is 3.70 volts. +The recommended low battery setting by Insteon is 3.26 volts. -Setting to 0 will prevent any low battery events from occuring. +Setting to 0 will prevent any low battery events from occuring. This setting will be saved between MisterHouse reboots. @@ -192,11 +193,10 @@ This setting will be saved between MisterHouse reboots. sub set_low_battery_level { my ($self, $level) = @_; - $level =~ s/(\d+)%?/$1/; my $root = $self->get_root(); - $$root{low_battery_level} = sprintf("%u", $level); + $$root{low_battery_level} = sprintf("%.2f", $level); ::print_log("[Insteon::RemoteLinc] Set low battery level to ". - $$root{low_battery_level}."%"); + $$root{low_battery_level}." volts."); return; } @@ -230,17 +230,17 @@ sub _is_battery_time_expired { my ($self) = @_; my $root = $self->get_root(); if ($$root{battery_timer} > 0 && - (time - ($$root{last_battery_time} * 60)) > $$root{battery_timer}) { + (time - $$root{last_battery_time}) > ($$root{battery_timer} * 60)) { return 1; } return 0; } sub _is_battery_low { - my ($self, $percent) = @_; + my ($self, $voltage) = @_; my $root = $self->get_root(); if ($$root{low_battery_level} > 0 && - ($$root{low_battery_level} > $percent)) { + ($$root{low_battery_level} > $voltage)) { return 1; } return 0; @@ -269,11 +269,14 @@ sub _process_message { if (substr($msg{extra},0,6) eq "000001") { $self->default_hop_count($msg{maxhops}-$msg{hopsleft}); #D10 = Battery; - my $percent = hex(substr($msg{extra}, 20, 2)); + my $voltage = (hex(substr($msg{extra}, 20, 2))/50); main::print_log("[Insteon::RemoteLinc] The battery level ". "for device ". $self->get_object_name . " is: ". - $percent . "%"); - if ($self->_is_battery_low){ + $voltage . " of 3.70 volts."); + $$root{last_battery_time} = time; + if ($self->_is_battery_low($voltage)){ + main::print_log("[Insteon::RemoteLinc] The battery level ". + "is below the set threshold running low battery event."); package main; eval $$root{low_battery_event}; ::print_log("[Insteon::RemoteLinc] " . $self->{device}->get_object_name . ": error during low battery event eval $@") From d77f0373d856611ecd74391573db2c755f6a014e Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Sat, 11 May 2013 09:18:19 -0700 Subject: [PATCH 10/49] Insteon_RemoteLinc: Add RemoteLinc_Battery Object This is a generic object that is "tied" to the battery events in the parent RemoteLinc. It can be used to display the battery voltage on the RemoteLinc on the MH web page or to directly tie events to rather than using the low_battery_event code. --- lib/Insteon/Controller.pm | 65 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 537273afd..c52f30784 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -183,7 +183,8 @@ Only available for RemoteLinc 2 models. If the battery level falls below this voltage, the C command is run. The theoretical maximum voltage of the battery is 3.70 volts. -The recommended low battery setting by Insteon is 3.26 volts. +Although practical experience shows it to be closer to 3.65 volts. The +recommended low battery setting by Insteon is 3.26 volts. Setting to 0 will prevent any low battery events from occuring. @@ -274,6 +275,10 @@ sub _process_message { "for device ". $self->get_object_name . " is: ". $voltage . " of 3.70 volts."); $$root{last_battery_time} = time; + if (ref $$root{battery_object} && $$root{battery_object}->can('set_receive')) + { + $$root{battery_object}->set_receive($voltage, $root); + } if ($self->_is_battery_low($voltage)){ main::print_log("[Insteon::RemoteLinc] The battery level ". "is below the set threshold running low battery event."); @@ -303,6 +308,64 @@ sub is_responder =back +=head1 B + +=head2 SYNOPSIS + +Configuration: + +Currently the object can only be defined in the user code. + +In user code: + + use Insteon::RemoteLinc_Battery; + $remote_battery = new Insteon::RemoteLinc_Battery($remote); + +Where $remote is the RemoteLinc device you wish to monitor. + +=head2 DESCRIPTION + +This basic class creates a simple object that displays the current battery voltage +as its state. This is helpful if you want to be able to view the battery level +through a web page. Battery level tracking is likely only available on RemoteLinc 2 +devices. + +This objects state will be updated based on interval defined for C +in the parent B object. + +Once created, you can tie_events directly to this object rather than using the +battery_low_event code in the parent B object. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + +package Insteon::RemoteLinc_Battery; +use strict; + +@Insteon::RemoteLinc_Battery::ISA = ('Generic_Item'); + +sub new { + my ($class, $parent) = @_; + my $self = new Generic_Item(); + bless $self, $class; + $$parent{battery_object} = $self; + return $self; +} + +sub set_receive { + my ($self, $p_state) = @_; + $self->SUPER::set($p_state); +} + +=back + =head2 INI PARAMETERS None. From 58dffe58b406907439d1c87b3ee9201cdfdf9eae Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Sat, 11 May 2013 09:29:50 -0700 Subject: [PATCH 11/49] Insteon_RemoteLinc: Make Battery Parent is the Root Item --- lib/Insteon/Controller.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index c52f30784..cbde9353a 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -354,8 +354,9 @@ use strict; sub new { my ($class, $parent) = @_; my $self = new Generic_Item(); + my $root = $parent->get_root(); bless $self, $class; - $$parent{battery_object} = $self; + $$root{battery_object} = $self; return $self; } From 2e2079f06eb30a40a8b7bdab65f601f3f1b47370 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 15 May 2013 20:07:45 -0700 Subject: [PATCH 12/49] Insteon_RemoteLinc: Remove Low Battery and Event Routines No need to reinvent the wheel, low batter events can be tracked using the child objects and tied events --- lib/Insteon/Controller.pm | 73 +++++---------------------------------- 1 file changed, 9 insertions(+), 64 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index cbde9353a..af2c7cab6 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -69,8 +69,8 @@ sub new my $self = new Insteon::BaseDevice($p_deviceid,$p_interface); $$self{message_types} = \%message_types; if ($self->is_root){ - $self->restore_data('battery_timer', 'last_battery_time', - 'low_battery_level', 'low_battery_event'); + $self->restore_data('battery_timer', 'last_battery_time'); + $$self{queue_timer} = new Timer; } bless $self,$class; return $self; @@ -177,56 +177,6 @@ sub set_battery_timer { return; } -=item C - -Only available for RemoteLinc 2 models. - -If the battery level falls below this voltage, the C -command is run. The theoretical maximum voltage of the battery is 3.70 volts. -Although practical experience shows it to be closer to 3.65 volts. The -recommended low battery setting by Insteon is 3.26 volts. - -Setting to 0 will prevent any low battery events from occuring. - -This setting will be saved between MisterHouse reboots. - -=cut - -sub set_low_battery_level { - my ($self, $level) = @_; - my $root = $self->get_root(); - $$root{low_battery_level} = sprintf("%.2f", $level); - ::print_log("[Insteon::RemoteLinc] Set low battery level to ". - $$root{low_battery_level}." volts."); - return; -} - -=item C - -Only available for RemoteLinc 2 models. - -If the battery level falls below the percentage defined by C -this command is evaluated. Works very similar to a C -eval. - -Example: - - $remote->battery_low_event('speak "Warning, Remote battery is low."'); - -See C for more examples. - -This setting will be saved between MisterHouse reboots. - -=cut - -sub battery_low_event { - my ($self, $eval) = @_; - my $root = $self->get_root(); - $$root{low_battery_event} = $eval; - ::print_log("[Insteon::RemoteLinc] Set low battery event."); - return; -} - sub _is_battery_time_expired { my ($self) = @_; my $root = $self->get_root(); @@ -237,23 +187,18 @@ sub _is_battery_time_expired { return 0; } -sub _is_battery_low { - my ($self, $voltage) = @_; - my $root = $self->get_root(); - if ($$root{low_battery_level} > 0 && - ($$root{low_battery_level} > $voltage)) { - return 1; - } - return 0; -} - sub _process_message { my ($self,$p_setby,%msg) = @_; my $clear_message = 0; my $root = $self->get_root(); - if ($msg{command} eq 'link_cleanup_report' && $self->_is_battery_time_expired){ + if ($root->_is_battery_time_expired){ #Queue an get_extended_info request - $self->get_extended_info(); + if ($$root{queue_timer}->active){ + $$root{queue_timer}-restart(); + } + else { + $$root{queue_timer}->set(3, '$root->get_extended_info()'); + } } if ($msg{command} eq "extended_set_get" && $msg{is_ack}){ $self->default_hop_count($msg{maxhops}-$msg{hopsleft}); From ed84054c6335aa8a736a04deef066c4eca649a57 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 23 May 2013 20:59:25 -0700 Subject: [PATCH 13/49] Insteon_RemoteLinc: Fix Typos --- lib/Insteon/Controller.pm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index af2c7cab6..3fcaf60d2 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -17,10 +17,10 @@ In user code: In items.mht: - INSTEON_REMOTELINC, 12.34.56:01, $remote_1, $remote_group - INSTEON_REMOTELINC, 12.34.56:02, $remote_2, $remote_group - INSTEON_REMOTELINC, 12.34.56:03, $remote_3, $remote_group - INSTEON_REMOTELINC, 12.34.56:04, $remote_4, $remote_group + INSTEON_REMOTELINC, 12.34.56:01, remote_1, remote_group + INSTEON_REMOTELINC, 12.34.56:02, remote_2, remote_group + INSTEON_REMOTELINC, 12.34.56:03, remote_3, remote_group + INSTEON_REMOTELINC, 12.34.56:04, remote_4, remote_group =head2 DESCRIPTION From 2f18a353ee015d50891ce31759ff0d91fee87ba3 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 23 May 2013 21:01:43 -0700 Subject: [PATCH 14/49] Insteon_RemoteLinc: Only Send Battery Request Once If the device doesn't hear the first request, it won't be awake to hear subsequent ones. Sending subsequent messages only slows things down. --- lib/Insteon/Controller.pm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 3fcaf60d2..cb87d19f8 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -144,11 +144,14 @@ expired. =cut sub get_extended_info { - my ($self) = @_; + 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; } @@ -197,7 +200,7 @@ sub _process_message { $$root{queue_timer}-restart(); } else { - $$root{queue_timer}->set(3, '$root->get_extended_info()'); + $$root{queue_timer}->set(3, '$root->get_extended_info(1)'); } } if ($msg{command} eq "extended_set_get" && $msg{is_ack}){ From 55605c25874df3baef4f7fecaf56f2328f0d23be Mon Sep 17 00:00:00 2001 From: Jim Duda Date: Fri, 24 May 2013 21:07:18 -0400 Subject: [PATCH 15/49] Reset the crash_cnt state variable when selecting the reset language files command. --- lib/PocketSphinx.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/PocketSphinx.pm b/lib/PocketSphinx.pm index 6bedacccb..c0beab069 100644 --- a/lib/PocketSphinx.pm +++ b/lib/PocketSphinx.pm @@ -198,6 +198,7 @@ sub reset_language_files { my ($self) = @_; $PocketSphinx_state = "reset"; $self->{disabled} = 0; + $self->{crash_cnt} = 0; } #============================================================================================ From 9f37b53906a10eb55f61d17c9a6367fcf77b122d Mon Sep 17 00:00:00 2001 From: Jim Duda Date: Fri, 24 May 2013 21:10:48 -0400 Subject: [PATCH 16/49] Avoid a divide by zero error by first checking for zero humidity. --- lib/Weather_Common.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Weather_Common.pm b/lib/Weather_Common.pm index 5dcc5119c..e240dcebf 100644 --- a/lib/Weather_Common.pm +++ b/lib/Weather_Common.pm @@ -293,7 +293,10 @@ sub convert_humidity_to_dewpoint { return unless defined $humidity and defined $temp_celsius; # http://en.wikipedia.org/wiki/Dew_point - my $gamma = ( (17.271 * $temp_celsius) / (237.7 + $temp_celsius) ) + log($humidity/100); + my $gamma = ( (17.271 * $temp_celsius) / (237.7 + $temp_celsius) ); + if ($humidity != 0) { + $gamma += log($humidity/100); + } my $dew_point = (237.7 * $gamma) / (17.271 - $gamma); # old calculations From 7aaca1489730568a06ac9191447a0839cdc81dcd Mon Sep 17 00:00:00 2001 From: Jim Duda Date: Fri, 24 May 2013 21:51:30 -0400 Subject: [PATCH 17/49] Major overhaul of this module. Uses Socket_Item instead of direct socket connection to avoid pauses in main loop. Stores device state in Generic_Item state variable now. PIO, Latches, and Sense now use state values of ON and OFF. --- bin/mh.ini | 9 +- lib/Owfs_Item.pm | 1871 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 1401 insertions(+), 479 deletions(-) diff --git a/bin/mh.ini b/bin/mh.ini index 128f172d3..69d51a153 100644 --- a/bin/mh.ini +++ b/bin/mh.ini @@ -2115,8 +2115,14 @@ xbmc_notify_address= @ Web port of your XBMC installation (Defaults to 8080 if unset) xbmc_notify_port=8080 +@ Host of your One Wire File System owserver +owfs_host=localhost +@ Port of your One Wire File System owserver +owfs_port=4304 +@ Unit of measure for owserver ( C, [F], K, R) +owfs_uom_temp = F # ****************************************************************************** # @@ -2444,4 +2450,5 @@ xbmc_notify_port=8080 # Revision 1.2 1998/08/29 20:45:35 winter # - add net parms. add cm11_serial parm. # -# + +# \ No newline at end of file diff --git a/lib/Owfs_Item.pm b/lib/Owfs_Item.pm index 4c017270d..e7506e22d 100644 --- a/lib/Owfs_Item.pm +++ b/lib/Owfs_Item.pm @@ -1,26 +1,28 @@ =begin comment -Owfs_Item.pm +Owfs_Item.pm 03/10/2007 Created by Jim Duda (jim@duda.tzo.com) Use this module to interface with the OWFS (one-wire filesystem) software. The OWFS software handles all the real-time processing of the one-wire itself, -offering a simple PERL API interface. +offering a simple PERL API interface. The Owfs_Item only requires the owserver +portion of owfs to be accessable. Requirements: - Download and install OWFS (tested against release owfs-2.7p21) + Download and install OWFS (tested against release owfs-2.9p0). + Only the owserver portion is required for Misterhouse. http://www.owfs.org Setup: -In your code module, instantation the Owfs_Item class to interface with some +In your code module, instantation the Owfs_Item class (or extension) to interface with some one-wire element. The one-wire device can be found using the OWFS html interface. configure mh.private.ini -owfs_port = 3030 # defined port where the owfs server is listening +owfs_port = 4304 # defined port where the owfs server is listening # (owserver defaults to 4304) Example Usage: @@ -33,16 +35,49 @@ Example Usage: $frontDoorBell = new Owfs_Item ( "12.487344000000", "Front DoorBell"); $sensor = new Owfs_Item ( "05.4D212A000000"); - Owfs_Item can be used as a baseclass and extended for specific one wire devices. - For example, refer to package Owfs_DS2450 which describes a one wire A/D device. - Any of the fields in the one-wire device can be access via the set and get methods. - $sensor->set ("power", 1 ); - $sensor->get ("alarm"); + $sensor->set ( "power", 1 ); + $sensor->get ( "alarm" ); + + The get method only "requests" the property be fetched. The property will be + placed into the object state and can be accessed via: + + if (my $state = said $sensor) { + ... + } + + or; + + if (my $state = state_now $sensor) { + ... + } + + if (my $state = state_changed $sensor) { + ... + } + + or; + + my $state = $sensor->state( ); + + Owfs_Item can be used as a baseclass and extended for specific one wire devices. + For example, refer to package Owfs_DS2450 which describes a one wire A/D device. + Extended devices will have different API routines and will typically not use + the set/get methods. =cut +# TODO +# document +# test raw Owfs_Item +# test others +# celcius/fahrenheit +# maintain inventory +# dump inventory +# inventory of all items, not just those requested +# table A + #======================================================================================= # # Generic Owfs_Item @@ -51,162 +86,992 @@ Example Usage: # #======================================================================================= +use Timer; +use Socket_Item; + package Owfs_Item; +use strict; @Owfs_Item::ISA = ('Generic_Item'); -use OW; +our (%objects_by_id); # database of all discovered objects by id +our $socket; # single Socket_Item which serves all Owfs_Item objects +our @queue; # Queue of commands for owserver, commands handled one at a time +our $socket_state = 0; # State variable for handling socket interface +our $socket_inactive = 0; # State variable for handling socket interface + +################################################################################### +# Static variables used for owserver interface +################################################################################### + +our $msg_read = 2 ; # Command codes for owserver interface +our $msg_write = 3 ; +our $msg_dir = 4 ; +our $msg_presence = 6 ; +our $msg_dirall = 7 ; +our $msg_get = 8 ; + +our $persistence_bit = 0x04 ; +# PresenceCheck, Return bus list, and apply aliases +our $default_sg = 0x100 + 0x2 + 0x8 ; +our $default_block = 4096 ; + +our $tempscale = 0 ; +our $addr = ""; +TEMPSCALE: { + $tempscale = 0x00000 , last TEMPSCALE if $addr =~ /-C/ ; + $tempscale = 0x10000 , last TEMPSCALE if $addr =~ /-F/ ; + $tempscale = 0x20000 , last TEMPSCALE if $addr =~ /-K/ ; + $tempscale = 0x30000 , last TEMPSCALE if $addr =~ /-R/ ; +} -my (%objects_by_id); -my $port = undef; +our $format = 0 ; +FORMAT: { + $format = 0x2000000 , last FORMAT if $addr =~ /-ff\.i\.c/ ; + $format = 0x4000000 , last FORMAT if $addr =~ /-ffi\.c/ ; + $format = 0x3000000 , last FORMAT if $addr =~ /-ff\.ic/ ; + $format = 0x5000000 , last FORMAT if $addr =~ /-ffic/ ; + $format = 0x0000000 , last FORMAT if $addr =~ /-ff\.i/ ; + $format = 0x1000000 , last FORMAT if $addr =~ /-ffi/ ; + $format = 0x2000000 , last FORMAT if $addr =~ /-f\.i\.c/ ; + $format = 0x4000000 , last FORMAT if $addr =~ /-fi\.c/ ; + $format = 0x3000000 , last FORMAT if $addr =~ /-f\.ic/ ; + $format = 0x5000000 , last FORMAT if $addr =~ /-fic/ ; + $format = 0x0000000 , last FORMAT if $addr =~ /-f\.i/ ; + $format = 0x1000000 , last FORMAT if $addr =~ /-fi/ ; +} +################################################################################### + +# BaseClass constructor sub new { my ($class, $device, $location) = @_; my $self = { }; bless $self,$class; - $device =~ /(.*)\.(.*)/; - my $family = $1; - my $id = $2; - - # Initialize the OWFS perl interface ( server tcp port ) - if (!defined $port) { - $port = 3030; - $port = "$main::config_parms{owfs_port}" if exists $main::config_parms{owfs_port}; - &main::print_log ("Owfs_Item:: Initializing port: $port $location") if $main::Debug{owfs}; - OW::init ( "$port" ); + # Create one Socket_Item for ALL Owfs_Item devices to share + if (!$socket) { + &::MainLoop_pre_add_hook(\&Owfs_Item::_run_loop, 'persistent'); + my $host = "localhost"; + my $port = "4304"; + $host = "$main::config_parms{owfs_host}" if exists $main::config_parms{owfs_host}; + $port = "$main::config_parms{owfs_port}" if exists $main::config_parms{owfs_port}; + &main::print_log ("Owfs_Item::new Initializing host:port: $host:$port") if $main::Debug{owfs}; + $socket = new Socket_Item(undef, undef, "$host:$port", undef, 'tcp', 'raw', undef); + @queue = (); } + # Object identification + $device =~ /(.*)\.(.*)/; $self->{device} = $device; $self->{location} = $location; - $self->{present} = undef; - $self->{root} = &_find ( $family, $id, 0, "/" ); - $self->{path} = $self->{root} . $family . "." . $id . "/"; - if (defined $self->{path}) { - $objects_by_id{path} = $self; - &_load ( $self, $self->{path} ); + $self->{family} = $1; + $self->{id} = $2; + $self->{root} = undef; + + # State variables for _discovery + $self->{dir_tokens} = (); + $self->{dir_level} = 0; + $self->{present} = 0; + $self->{failcnt} = 0; + + # State variables for get/set operations + $self->{path} = undef; + $self->{token} = undef; + $self->{value} = undef; + + # State variables for debug + $self->{debug} = 0; + + # Initialize object state + $self->{state} = ''; # Will only be listed on web page if state is defined + + # Schedule item discovery + $self->{discover_timer} = new Timer; + $self->{discover_timer}->set(5, sub {Owfs_Item::_discover($self);}); + + my $uom = "F"; + $uom = "$main::config_parms{owfs_uom_temp}" if exists $main::config_parms{owfs_uom_temp}; + + my $tempscale = 0; + if ($uom =~ /C/) { + $tempscale = 0x00000; + } elsif ($uom =~ /F/) { + $tempscale = 0x10000; + } elsif ($uom =~ /K/) { + $tempscale = 0x20000; + } elsif ($uom =~ /R/) { + $tempscale = 0x30000; } - $$self{state} = ''; # Will only be listed on web page if state is defined - &dump ( $self ) if ($main::Debug{owfs}); + # owserver state variables + $self->{PERSIST} = $persistence_bit; + $self->{SG} = $default_sg + $tempscale + $format; + $self->{VER} = 0 ; return $self; } -sub set { - my ($self, $token, $data) = @_; - my $path = $self->{path} . $token; - &main::print_log ("Owfs_Item::set $path $data") if $main::Debug{owfs}; - my $result = OW::put($path, "$data") or return ; - return $result; +sub get_device { + my ($self) = @_; + return $self->{device}; } -sub set_root { - my ($self, $token, $data) = @_; - my $path = $self->{root} . $token; - &main::print_log ("Owfs_Item::set_root $path $data") if $main::Debug{owfs}; - my $result = OW::put($path, "$data" ) or return ; - return $result; +sub get_location { + my ($self) = @_; + return $self->{location}; } -sub get { - my ($self, $token) = @_; - my $path = $self->{path} . $token; - my $result = OW::get($path) or return ; - &main::print_log ("Owfs_Item::get $path $result") if $main::Debug{owfs}; - return $result; +sub get_family { + my ($self) = @_; + return $self->{family}; } -sub get_present { - my ($self) = @_; - $self->{present} = $self->get("present"); - return $self->{present}; +sub get_id { + my ($self) = @_; + return $self->{id}; } -sub get_root { - my ($self, $token) = @_; - my $path = $self->{root} . $token; - my $result = OW::get($path) or return ; - &main::print_log ("Owfs_Item::get_root $path $result") if $main::Debug{owfs}; - return $result; +sub get_present { + my ($self) = @_; + return $self->{present}; } sub set_key { - my ($self, $key, $data) = @_; - $self->{$key} = $data; + my ($self, $key, $data) = @_; + $self->{$key} = $data; } sub get_key { - my ($self, $key) = @_; - return ($self->{$key}); + my ($self, $key) = @_; + return ($self->{$key}); } -sub get_device { - my ($self) = @_; - return $self->{device}; +# This method is called when the response for a read request to owserver returns. +sub process_read_response { + my ($self, $response) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $debug = $self->{debug} || $main::Debug{owfs}; + &main::print_log ("Owfs_Item::process_read_response $device $location response: $response") if $debug; + if ($response ne $self->state( )) { + $self->SUPER::set($response, 'owfs'); + } } -sub get_location { - my ($self) = @_; - return $self->{location}; -} - -sub dump { - my $self = shift; - &main::print_log ( "\n") if $main::Debug{owfs}; - &main::print_log ( "root: \t\t$$self{root}") if $main::Debug{owfs}; - &main::print_log ( "path: \t\t$$self{path}") if $main::Debug{owfs}; - &main::print_log ( "family: \t$$self{family}") if $main::Debug{owfs}; - &main::print_log ( "id: \t\t$$self{id}") if $main::Debug{owfs}; - &main::print_log ( "type: \t\t$$self{type}") if $main::Debug{owfs}; - - for my $key (sort keys %$self) { - next if ($key eq "root"); - next if ($key eq "path"); - next if ($key eq "family"); - next if ($key eq "id"); - next if ($key eq "type"); - &main::print_log ( "$key:\t\t$$self{$key}") if $main::Debug{owfs}; - } - &main::print_log ( "\n") if $main::Debug{owfs}; +# This method is called when the response for a write request to owserver returns. +sub process_write_response { + my ($self, $response) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $token = $self->{token}; + my $value = $self->{value}; + my $type = $self->isa('Owfs_Item'); + if ($response) { + if ($value ne $self->state( )) { + $self->SUPER::set($value, 'owfs'); + } + } + my $debug = $self->{debug} || $main::Debug{owfs}; + &main::print_log ("Owfs_Item::process_write_response type: $type $device $location response: $response token: $token value: $value") if $debug; +} + +# This method is called when the response for a directory request to owserver returns. This method is +# used during device discovery. +sub process_dir_response { + my ($self, $response) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $family = $self->{family}; + my $level = $self->{dir_level}; + my $id = $self->{id}; + my $path = $self->{dir_path}; + my @tokens = split(',',$response); + push @{$self->{dir_tokens}}, @tokens; + &main::print_log ( "Owfs_Item::process_dir_response family: $family id: $id level: $level path: $path tokens: @tokens") if $main::Debug{owfs}; + while ( scalar(@{$self->{dir_tokens}}) ) { + my $token = shift @{$self->{dir_tokens}}; + &main::print_log ( "Owfs_Item::process_dir_response family: $family id: $id level: $level path: $path token: $token") if $main::Debug{owfs}; + if ( $token =~ /\/([0123456789abcdefABCDEF\.]+|aux|main)$/ ) { + my $leaf = $1; + &main::print_log ( "Owfs_Item::process_dir_response family: $family id: $id level: $level path: $path token: $token leaf: $leaf") if $main::Debug{owfs}; + $leaf =~ /(.+)\.(.+)$/; + if ((uc $family eq uc $1) && (uc $id eq uc $2)) { + $self->{root} = $path; + if ($self->{root} ne "/") { + $self->{root} .= "/"; + } + $self->{path} = $token . "/"; + $self->{present} = 1; + $objects_by_id{$id} = $self; + &main::print_log ("Owfs_Item::DEVICE_DISCOVERY: device: $device location: $location family: $family id: $id root: $path path: $token"); # if $main::Debug{owfs}; + $self->discovered( ); + return; + } elsif (($1 eq "1F") || ($leaf =~ /aux$/) || ($leaf =~ /main$/)) { + my $val = $self->_find ($family, $id, $level+1, $token); + } + } + } +} + +# This method is called to schedule a write command be sent to the owserver for the object. +sub set { + my ($self, $token, $value) = @_; + return if (!defined $self->{path}); + my $path = $self->{path} . $token; + my $debug = $self->{debug} || $main::Debug{owfs}; + &main::print_log ("Owfs_Item::set path: $path value: $value") if $debug; + my $path_length = length($path)+1; + #$value .= ' '; + my $value_length = length($value); + my $payload = pack( 'Z'.$path_length.'A'.$value_length,$path,$value ); + $self->{token} = $token; + $self->{value} = $value; + $self->_ToServer($path,length($payload)+1, $msg_write, $value_length, 0, $payload); +} + +# This method is called to schedule a read command be sent to the owserver for the object. +sub get { + my ($self, $token) = @_; + return if (!defined $self->{path}); + my $path = $self->{path} . $token; + &main::print_log ("Owfs_Item::get path: $path") if $main::Debug{owfs}; + $self->{token} = $token; + $self->{value} = undef; + $self->_ToServer($path,length($path)+1,$msg_read,$default_block,0,$path); +} + +# This method is called to schedule a directory command be sent to the owserver for the object. +# This method is used for item discovery. +sub _dir { + my ($self, $path) = @_; + # new msg_dirall method -- single packet + &main::print_log ("Owfs_Item::dir path: $path") if $main::Debug{owfs}; + $self->{dir_path} = $path; + $self->{token} = undef; + $self->{value} = undef; + $self->_ToServer($path,length($path)+1,$msg_dirall,$default_block,0,$path); +} + +# This method is called to schedule a write command be sent to the owserver for the object. +# The path used will be the device root instead of the device itself. If the $token value +# is preceeded with a "/", then the token value will be used as a raw path. +sub _set_root { + my ($self, $token, $value) = @_; + my $root = $self->{root}; + return if (!defined $root); + my $path = $self->{root} . $token; + if ($token =~ /^\//) { + $path = $token; + } + &main::print_log ("Owfs_Item::_set_root root: $root path: $path value: $value") if $main::Debug{owfs}; + my $path_length = length($path)+1 ; + #$value .= ' '; + my $value_length = length($value) ; + my $payload = pack( 'Z'.$path_length.'A'.$value_length,$path,$value ) ; + $self->{token} = $token; + $self->{value} = $value; + $self->_ToServer($path,length($payload)+1, $msg_write, $value_length, 0, $payload); +} + +# This method is called to schedule a read command be sent to the owserver for the object. +# The path used will be the device root instead of the device itself. If the $token value +# is preceeded with a "/", then the token value will be used as a raw path. +sub _get_root { + my ($self, $token) = @_; + my $root = $self->{root}; + return if (!defined $root); + my $path = $self->{root} . $token; + &main::print_log ("Owfs_Item::_get_root path: $path") if $main::Debug{owfs}; + $self->{token} = $token; + $self->{value} = undef; + $self->_ToServer($path,length($path)+1,$msg_read,$default_block,0,$path) ; +} + +# This method is used to search the one-wire tree for the specific object as defined +# by the $device passed during construction. +sub _discover { + my ($self) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $family = $self->{family}; + my $id = $self->{id}; + &main::print_log ( "Owfs_Item::_discover family: $family id: $id") if $main::Debug{owfs}; + return if (defined $self->{path}); + $self->_find ( $family, $id, 0, "/" ); + if (!$self->get_present( )) { + $self->{discover_timer}->set(5, sub {Owfs_Item::_discover($self);}); + } +} + +# This method is called whenever the object has been discovered. Useful for initialization. +sub discovered { + my ($self) = @_; } +# This method is part of _discover. It provides an interim method to allow for recursion to work. sub _find { - my ($family, $id,$lev,$path) = @_; - my $result = OW::get($path) or return ; - #&main::print_log ( "_find:: family: $family id: $id lev: $lev path: $path") if $main::Debug{owfs}; - my @tokens = split(',',$result); - foreach my $token (@tokens) { - if ( $token =~ /\/$/ ) { - $token =~ /(.+)\.(.+)\/$/; - if (($family eq $1) && ($id eq $2)) { - return ( $path ); - } elsif (($1 eq "1F") || ($token =~ /aux\/$/) || ($token =~ /main\/$/)) { - my $val = &_find ($family, $id, $lev+1, $path.$token); - if ( defined $val ) { - return ( $val ); - } - } - } - } - return undef; -} - -sub _load { - my ($self, $path) = @_; -# &main::print_log ( "_load:: path: $path") if $main::Debug{owfs}; - my $result = OW::get($path) or return ; - my @tokens = split(',',$result); - foreach my $token (@tokens) { - $self->{$token} = OW::get($path.$token); - } -} - -sub _remove { - my $self = shift; - for my $key (keys %$self) { - delete $$self{$key}; - } + my ($self,$family,$id,$level,$path) = @_; + &main::print_log ( "Owfs_Item::_find family: $family id: $id") if $main::Debug{owfs}; + $self->{dir_level} = $level; + $self->_dir($path); +} + +# This method is called when a device which had been previously discovered has been lost. This +# method will schedule the _discover mechanism to run again. The _lost and _discover methods +# allow for dynamic removal and insertion. +sub _lost { + my ($self) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $family = $self->{family}; + my $id = $self->{id}; + my $path = $self->{path}; + &main::print_log ("Owfs_Item::DEVICE_LOST: device: $device location: $location family: $family id: $id path: $path"); # if $main::Debug{owfs}; + $self->{root} = undef; + $self->{path} = undef; + $self->{present} = 0; + $self->{discover_timer}->set(5, sub {Owfs_Item::_discover($self);}); + $self->{failcnt} = 0; + $self->{state} = undef; +} + +# The method can be used to dump the state of any Owfs_Item object. +sub _dump { + my ($self) = @_; + &main::print_log ( "\n") if $main::Debug{owfs}; + &main::print_log ( "path: \t\t$$self{path}") if $main::Debug{owfs}; + &main::print_log ( "family: \t$$self{family}") if $main::Debug{owfs}; + &main::print_log ( "id: \t\t$$self{id}") if $main::Debug{owfs}; + &main::print_log ( "type: \t\t$$self{type}") if $main::Debug{owfs}; + for my $key (sort keys %$self) { + next if ($key eq "root"); + next if ($key eq "path"); + next if ($key eq "family"); + next if ($key eq "id"); + next if ($key eq "type"); + &main::print_log ( "$key:\t\t$$self{$key}") if $main::Debug{owfs}; + } + &main::print_log ( "\n") if $main::Debug{owfs}; +} + +# This is a helper method to remove extra white space characters. +sub _chomp_plus { + my ($self,$string) = @_; + $string =~ s/^\s+//; + chomp $string; + return $string; +} + +# This is a helper method to convert states as required. This method is overloaded +# in the sub class as necessary. +sub convert_state { + my ($self, $value) = @_; + return $value; +} + +# This method is a direct port from the OWNet.pm module from owfs. This is the lower layer interface +# to the owserver socket port. +sub _ToServer { + my ($self, $path, $payload_length, $msg_type, $size, $offset, $payload_data) = @_ ; + my $f = "N6Z$payload_length"; + #$f .= 'Z'.$payload_length if ( $payload_length > 0 ) ; + my $message = pack($f,$self->{VER},$payload_length,$msg_type,$self->{SG}|$self->{PERSIST},$size,$offset,$payload_data); + &main::print_log ( "Owfs_Item::_ToServer path: $path payload_length: $payload_length payload_data: $payload_data message: $message") if $main::Debug{owfs}; + my $token = $self->{token}; + my $value = $self->{value}; + my $hashref = { msg_type => $msg_type, self => $self, path => $path, token => $token, value => $value, message => $message }; + push @queue, $hashref; + my $num = scalar(@queue); + &main::print_log ( "Owfs_Item::_ToServer num: $num") if $main::Debug{owfs}; + if ($num > 100) { + &main::print_log ( "Owfs_Item::_ToServer high outstanding requests! num: $num"); + } + if ($main::Debug{owfs} && (scalar(@queue) > 1)) { + foreach my $ref (@queue) { + my $msg_type = $ref->{msg_type}; + my $path = $ref->{path}; + &main::print_log ( "Owfs_Item::_ToServer msg_type: $msg_type path: $path"); + } + } + if (scalar(@queue) eq 1) { + &main::print_log ( "Owfs_Item::_ToServer path: $path message: $message sending socket....") if $main::Debug{owfs}; + start $socket unless active $socket; + $socket->set ( $message ); + } +} + +# This method is a direct port from the OWNet.pm module from owfs. This is the lower layer interface +# to the owserver socket port. +sub _FromServerLow { + my ($self, $length_wanted) = @_; + my $length = length($self->{record}); + &main::print_log ( "Owfs_Item::_FromServerLow length_wanted: $length_wanted length: $length") if $main::Debug{owfs}; + return '' if $length_wanted == 0; + my $remaininglength = $length_wanted; + my $fullread = ''; + return if length($self->{record}) < $length_wanted; + my $result = substr($self->{record},0,$length_wanted); + $self->{record} = substr($self->{record},$length_wanted); + return $result; +} + +# This method is a direct port from the OWNet.pm module from owfs. This is the lower layer interface +# to the owserver socket port. +sub _FromServer { + my ($self) = @_; + my ( $version, $payload_length, $return_status, $sg, $size, $offset, $payload_data ); + while (active $socket) { + &main::print_log ( "Owfs_Item::_FromServer socket_state: $socket_state") if $main::Debug{owfs}; + if ($socket_state == 0) { + do { + my $r = _FromServerLow( $self, 24 ); + if (!defined $r) { + &main::print_log ( "Owfs_Item::_FromServer Trouble getting header") if $main::Debug{owfs}; + return; + } + ($version, $payload_length, $return_status, $sg, $size, $offset) = unpack('N6', $r ); + my @things = ($version, $payload_length, $return_status, $sg, $size, $offset); + &main::print_log ( "Owfs_Item::_FromServer things: @things") if $main::Debug{owfs}; + # returns unsigned (though originals signed + # assume anything above 66000 is an error + if ($return_status > 66000) { + &main::print_log ( "Owfs_Item::_FromServer Trouble getting payload") if $main::Debug{owfs}; + return ($version, $payload_length, $return_status, $sg, $size, $offset, $payload_data ) ; + } + } while ($payload_length > 66000); + $socket_state = 1; + } + else { + $payload_data = $self->_FromServerLow( $payload_length ) ; + if (!defined $payload_data) { + &main::print_log ( "Owfs_Item::_FromServer Trouble getting payload") if $main::Debug{owfs}; + return; + } + $payload_data = substr($payload_data,0,$size) ; + $socket_state = 0; + return ($version, $payload_length, $return_status, $sg, $size, $offset, $payload_data ) ; + } + } +} + +# This method runs one during the misterhouse main loop. Its purpose is to handle the return responses +# from the Socket_Item attached to the owserver. The results are dispatched back to the objects using +# the process_write/read/dir_response methods. After each response is handled by the object, the next +# command will be popped from the queue and sent to owserver. The owserver interface is only given +# one command at a time to process. +sub _run_loop { + + # State Machine + return if !scalar(@queue); + + my $hashref = $queue[0]; + my $self = $hashref->{self}; + my $msg_type = $hashref->{msg_type}; + my $path = $hashref->{path}; + my $token = $hashref->{token}; + my $value = $hashref->{value}; + my $device = $self->{device}; + my $location = $self->{location}; + my $popped = 0; + + # Detect state change from inactive to active + if ($socket->inactive_now( )) { + $socket_inactive = 1; + $socket_state = 0; + &main::print_log ( "Owfs_Item::_run_loop socket INACTIVE") if $main::Debug{owfs}; + } + + if ($socket->active_now( )) { + $socket_state = 0; + if ($socket_inactive) { + $popped = 1; + } + $socket_inactive = 0; + &main::print_log ( "Owfs_Item::_run_loop socket ACTIVE") if $main::Debug{owfs}; + } + + start $socket unless active $socket; + + # Read Response + if ($msg_type eq $msg_read) { + if (my $record = said $socket) { + $self->{record} .= $record; + my $len1 = length($record); + my $len2 = length($self->{record}); + &main::print_log ( "Owfs_Item::_run_loop len1: $len1 len2: $len2") if $main::Debug{owfs}; + my @response = _FromServer($self) ; + if (!@response) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path EMPTY") if $main::Debug{owfs}; + } else { + if ($response[2] > 66000) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path ERROR"); # if $main::Debug{owfs}; + $self->{failcnt}++; + if ($self->{failcnt} >= 5) { + $self->_lost( ); + } + $self->process_read_response( ); + } else { + # process response + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path response: $response[6]") if $main::Debug{owfs}; + $self->{failcnt} = 0; + $self->process_read_response($response[6]); + } + shift @queue; + $popped = 1; + } + } + } + + # Write Response + elsif ($msg_type eq $msg_write) { + if (my $record = said $socket) { + $self->{record} .= $record; + my $len1 = length($record); + my $len2 = length($self->{record}); + &main::print_log ( "Owfs_Item::_run_loop len1: $len1 len2: $len2") if $main::Debug{owfs}; + my @response = _FromServer($self) ; + if (!@response) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path EMPTY") if $main::Debug{owfs}; + } else { + if ($response[2] > 66000) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path ERROR"); # if $main::Debug{owfs}; + $self->{failcnt}++; + if ($self->{failcnt} >= 5) { + $self->_lost( ); + } + $self->process_write_response( ); + } else { + # process response + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path response: $response[2]") if $main::Debug{owfs}; + $self->{failcnt} = 0; + $self->process_write_response($response[2] >= 0); + } + shift @queue; + $popped = 1; + } + } + } + + # Dirall Response + elsif ($msg_type eq $msg_dirall) { + if (my $record = said $socket) { + $self->{record} .= $record; + my @response = _FromServer($self) ; + if (!@response) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path EMPTY") if $main::Debug{owfs}; + } else { + if ($response[2] > 66000) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path ERROR"); # if $main::Debug{owfs}; + $self->{failcnt}++; + if ($self->{failcnt} >= 5) { + $self->_lost( ); + } + $self->process_write_response( ); + } else { + # process response + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path response: $response[6]") if $main::Debug{owfs}; + $self->{failcnt} = 0; + $self->process_dir_response($response[6]); + } + shift @queue; + $popped = 1; +# } else { + # old msg_dir method -- many packets +# $self->{dirlist} = ''; +# $self->_ToServer($path,length($path)+1,$msg_dir,$default_block,0,$path) || return ; + } + } + } + + # Dir response + elsif ($msg_type eq $msg_dir) { + if (my $record = said $socket) { + $self->{record} .= $record; + my @response = _FromServer($self); + if (!@response) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path EMPTY") if $main::Debug{owfs}; + } else { + if ($response[2] > 66000) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path ERROR"); # if $main::Debug{owfs}; + $self->{failcnt}++; + if ($self->{failcnt} >= 5) { + $self->_lost( ); + } + $self->process_write_response( ); + } else { + $self->{failcnt} = 0;; + if ( $response[1] == 0 ) { # last null packet + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path response: $response[6]") if $main::Debug{owfs}; + $self->process_dir_response(substr($self->{dirlist},1)); + shift @queue; + $popped = 1; + } else { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path response: $response[6]") if $main::Debug{owfs}; + $self->{dirlist} .= ','.$response[6] ; + } + } + } + } + } + + # Handle Unknown response + else { + &main::print_log ( "Owfs_Item::_run_loop unknown msg_type: $msg_type") if $main::Debug{owfs}; + if (my $record = said $socket) { + $self->{record} .= $record; + my @response = _FromServer($self) ; + if (!@response) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path EMPTY") if $main::Debug{owfs}; + } else { + if ($response[2] > 66000) { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type path: $path ERROR"); # if $main::Debug{owfs}; + } else { + &main::print_log ( "Owfs_Item::_run_loop msg_type: $msg_type (UNKNOWN) path: $path") if $main::Debug{owfs}; + } + shift @queue; + $popped = 1; + } + } + } + if ($popped and scalar(@queue)) { + my $hashref = $queue[0]; + my $msg_type = $hashref->{msg_type}; + my $path = $hashref->{path}; + my $message = $hashref->{message}; + &main::print_log ( "Owfs_Item::run_loop path: $path message: $message sending socket....") if $main::Debug{owfs}; + start $socket unless active $socket; + $socket->set ( $message ); + } +} + +#======================================================================================= +# +# Owfs_Switch +# +# This package is a common base class for many OWFS Switch like devices which +# have PIO, Latch, and Sense. +# +#======================================================================================= + +=begin comment + +Usage: + + $sensor = new Owfs_Switch ( "", , , , ); + + - of the form family.address; identifies the one-wire device + - ASCII string identifier providing a useful name for device_id + - "0", "1", "2", "3", "4", "5", "6", "7" + - Identifies what is stored in 0: PIO (Relay) 1: Sense 2: Latch + - Optional (defaults to 2). Number of seconds between input samples. + + Examples: + + # RELAY + my $relay = new Owfs_Switch ( "20.DB2506000000", "Some Relay", "0", 0 ); + $relay->set_pio("1"); # Turn on Relay + $relay->set_pio("0"); # Turn off Relay + my $state = $state->state( ); # 0: Relay off 1: Relay on + + # LATCH + my $doorbell = new Owfs_Switch ( "20.DB2506000000", "Front Door Bell", "1", 1 ); + if (my $state = said $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } + + or + + if (my $state = state_now $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } + + or + + if (my $state = state_changed $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } + +=cut + +package Owfs_Switch; +use strict; + +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; + +@Owfs_Switch::ISA = ('Owfs_Item'); + +our (%latch_mask); +our (%latch_store); + +sub new { + my ($class, $device, $location, $channel, $interval, $mode) = @_; + my $self = new Owfs_Item ( $device, $location ); + bless $self,$class; + + $self->{channel} = undef; + if (defined $channel) { + $self->{channel} = $channel; + } + $self->{interval} = 1; + if (defined $interval && ($interval >= 1)) { + $self->{interval} = $interval; + } + $self->{mode} = PIO; + if (defined $mode) { + $self->{mode} = $mode; + } + @{$$self{states}} = ('on','off'); + $self->{pio} = undef; + $self->{latch} = 0; + $self->{sensed} = undef; + $self->{pass_triggered} = 0; + $self->restore_data('latch'); + + $latch_store{$device} = 0; + if (!exists $latch_mask{$device}) { + $latch_mask{$device} = 0; + } + if (defined $channel) { + $latch_mask{$device} |= (1 << $channel); + } + + $self->{loop_timer} = new Timer; + $self->{loop_timer}->set($self->{interval}, sub {Owfs_Switch::run_loop($self);}); + + &::Reload_pre_add_hook(\&Owfs_Switch::reload_hook, 1); + + return $self; +} + +sub set_interval { + my ($self,$interval) = @_; + $self->{interval} = $interval if defined $interval; +} + +sub get_interval { + my ($self) = @_; + return $self->{interval}; +} + +sub set { + my ($self,$value) = @_; + my $mode = $self->{mode}; + my $debug = $self->{debug} || $main::Debug{owfs}; + &main::print_log ("Owfs_Switch::set mode: $mode value: $value") if $debug; + if ($mode eq PIO) { + my $channel = $self->{channel}; + my $pio = "PIO"; + if (defined $channel) { + $pio .= ".$channel"; + } + my $state = $self->convert_state($value); + $self->SUPER::set ($pio, $state); + } +} + +sub get { + my ($self) = @_; + return $self->state( ); +} + +sub set_pio { + my ($self,$value) = @_; + $self->set($value); +} + +sub get_pio { + my ($self) = @_; + return unless $self->get_present( ); + return $self->{pio}; +} + +sub get_latch { + my ($self) = @_; + my $device = $self->{device}; + my $channel = $self->{channel}; + $channel = 0 if (!defined $channel); + return unless $self->get_present( ); + return $self->convert_state($self->{latch}); +} + +sub get_sensed { + my ($self) = @_; + return unless $self->get_present( ); + return $self->{sensed}; +} + +sub set_debug { + my ($self,$debug) = @_; + $self->{debug} = $debug; +} + +# This is a helper method to convert states to 'on' and 'off' +sub convert_state { + my ($self, $value) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $channel = $self->{channel}; + my $state = $value; + $state = ON if ($value eq 1); + $state = OFF if ($value eq 0); + $state = ON if ($value eq 'yes'); + $state = OFF if ($value eq 'no'); + if (($state ne ON) && ($state ne OFF)) { + &main::print_log ( "Owfs_Item::convert_state Unknown state device: $device location: $location channel: $channel value: $value state: $state"); + } + return $state; +} + +# This method is called whenever the object has been discovered. Useful for initialization. +sub discovered { + my ($self) = @_; + my $channel = $self->{channel}; + my $mode = $self->{mode}; + if ($mode ne PIO) { + my $pio = "PIO"; + if (defined $channel) { + $pio .= ".$channel"; + } + $self->SUPER::set( $pio, OFF ); + } +} + +sub process_read_response { + my ($self, $response) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $channel = $self->{channel}; + my $pio = "PIO"; + my $debug = $self->{debug} || $main::Debug{owfs}; + if (defined $channel) { + $pio .= ".$channel"; + } + my $sensed = "sensed"; + if (defined $channel) { + $sensed .= ".$channel"; + } + my $latchstr = "latch"; + if (defined $channel) { + $latchstr .= ".$channel"; + } + my $mode = $self->{mode}; + my $token = $self->{token}; + &main::print_log ("Owfs_Switch::process_read_response device: $device location: $location channel: $channel mode: $mode token: $token response: $response") if $debug; + if (defined $response) { + if ($self->{token} =~ /PIO/) { + if ($mode == PIO) { + if ($response ne $self->state( )) { + my $state = $self->convert_state($response); + $self->SUPER::process_read_response($state); + } + } + $self->{pio} = $response; + &main::print_log ("Owfs_Switch::process_read_response $device $location $channel pio: $response") if $debug; + $self->{token} = undef; + $self->{value} = undef; + } elsif ($self->{token} =~ /sensed/) { + if ($mode == SENSE) { + if ($response ne $self->state( )) { + my $state = $self->convert_state($response); + $self->SUPER::process_read_response($state); + } + } + $self->{sensed} = $response; + &main::print_log ("Owfs_Switch::process_read_response $device $location $channel sensed: $response") if $debug; + $self->{token} = undef; + $self->{value} = undef; + } elsif ($self->{token} =~ /latch/) { + $latch_store{$device} |= ($latch_mask{$device} & $response); + my $ls = $latch_store{$device}; + my $lm = $latch_mask{$device}; + my $chanidx = $channel; + $chanidx = 0 if (!defined $channel); + my $latch = ($latch_store{$device} >> $chanidx) & 1; + if ($mode == LATCH) { + if ($latch ne $self->{latch}) { + my $state = $self->convert_state($latch); + $self->SUPER::process_read_response($state); + $self->{pass_triggered} = $main::Loop_Count; + $latch_store{$device} &= ~(1 << $chanidx); + } + } + $self->{latch} = $latch; + &main::print_log ("Owfs_Switch::process_read_response device: $device location: $location channel: $channel latch: $latch ls: $ls lm: $lm chanidx: $chanidx") if $debug; + if ($response != 0) { + $self->SUPER::set ($latchstr, 1); + } else { + $self->{token} = undef; + $self->{value} = undef; + } + } else { + $self->{token} = undef; + $self->{value} = undef; + } + } else { + &main::print_log ("Owfs_Switch::process_read_response $device $location $channel ERROR"); # if $debug; + $self->{token} = undef; + $self->{value} = undef; + } +} + +sub process_write_response { + my ($self, $response) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $channel = $self->{channel}; + my $mode = $self->{mode}; + my $token = $self->{token}; + my $debug = $self->{debug} || $main::Debug{owfs}; + &main::print_log ("Owfs_Switch::process_write_response $device $location $channel mode: $mode token: $token response: $response") if $debug; + if (defined $response) { + if (($mode eq PIO) && ($self->{token} =~ /PIO/)) { + $self->SUPER::process_write_response($response); + } + #if ($self->{token} =~ /latch/) { + # $self->{latch} = 0; + #} + } + $self->{token} = undef; + $self->{value} = undef; +} + +sub reload_hook { +} + +sub run_loop { + my ($self) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $channel = $self->{channel}; + my $pio = "PIO"; + if (defined $channel) { + $pio .= ".$channel"; + } + my $mode = $self->{mode}; + my $present = $self->{present}; + my $token = $self->{token}; + my $debug = $self->{debug} || $main::Debug{owfs}; + &main::print_log ("Owfs_Switch::run_loop $device $location $channel mode: $mode present: $present token: $token") if $debug; + if (!defined $self->{token} && $self->{present}) { + if ($mode eq PIO) { + $self->SUPER::get ($pio); + } elsif ($mode eq SENSE) { + $self->SUPER::get ("sensed.$channel"); + } elsif ($mode eq LATCH) { + $self->SUPER::get ("latch.BYTE"); + } + } + # reschedule the timer for next pass + $self->{loop_timer}->set($self->{interval}, sub {Owfs_Switch::run_loop($self);}); } #======================================================================================= @@ -230,37 +1095,58 @@ Usage: Example: $ds18S20 = new Owfs_DS18S20 ( "10.DB2506000000", "Living Room", 2 ); - + my $temperature = get_temperature $ds18S20; -=cut + or; -use strict; + if (my $temperature = said $sensor) { + ... + } + + or; + + if (my $temperature = state_now $sensor) { + ... + } + + if (my $temperature = state_changed $sensor) { + ... + } + + or; + + my $temperature = $sensor->state( ); + +=cut package Owfs_DS18S20; +use strict; @Owfs_DS18S20::ISA = ('Owfs_Item'); -my @clients = (); -my $index = 0; -my $timer = undef; +our @clients = (); +our $index = 0; +our $timer = undef; sub new { - my ($class, $ds18S20, $location, $interval) = @_; - my $self = new Owfs_Item ( $ds18S20, $location, $interval ); + my ($class, $device, $location, $interval) = @_; + my $self = new Owfs_Item ( $device, $location ); bless $self,$class; $self->{interval} = 10; if (defined $interval && ($interval > 1)) { $self->{interval} = $interval; } - $self->{present} = 0; $self->{temperature} = undef; if (!defined $timer) { &::Reload_pre_add_hook(\&Owfs_DS18S20::reload_hook, 1); $index = 0; $timer = new Timer; + } + + if ($timer->inactive( )) { $timer->set($self->{interval}, sub {&Owfs_DS18S20::run_loop}); } @@ -273,11 +1159,6 @@ sub new { return $self; } -sub get_present { - my ($self) = @_; - return $self->{present}; -} - sub set_interval { my ($self,$interval) = @_; $self->{interval} = $interval if defined $interval; @@ -288,48 +1169,86 @@ sub get_interval { return $self->{interval}; } +sub set { + my ($self) = @_; +} + +sub get { + my ($self) = @_; + return $self->state( ); +} + sub get_temperature { - my $self = shift; - return ($self->{temperature}); + my ($self) = @_; + return $self->state( ); +} + +sub process_read_response { + my ($self, $temperature) = @_; + my $device = $self->{device}; + my $location = $self->{device}; + if (defined $temperature) { + $temperature = $self->_chomp_plus($temperature); + if ($temperature =~ /^[-]?\d+(?:[.]\d+)?$/) { + # convert to fahrenheit + $temperature = (($temperature*9)/5)+32; + if ($temperature ne $self->state( )) { + $self->SUPER::process_read_response( $temperature ); + } + $self->{temperature} = $temperature; + if ($main::Debug{owfs}) { + &main::print_log ("Owfs_DS18S20::process_read_response $device $location temperature: $temperature") if $main::Debug{owfs}; + } + } + } else { + &main::print_log ("Owfs_DS18S20::process_read_response $device $location temperature: ERROR"); # if $main::Debug{owfs}; + } + $self->{token} = undef; + $self->{value} = undef; +} + +# This method is called when the response for a write request to owserver returns. +sub process_write_response { + my ($self, $response) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $token = $self->{token}; + my $value = $self->{value}; + &main::print_log ("Owfs_DS18S20::process_write_response $device $location response: $response token: $token value: $value") if $main::Debug{owfs}; + $self->{token} = undef; + $self->{value} = undef; } sub reload_hook { @clients = (); - my $num = @clients; - &main::print_log( "Owfs_DS18S20::reload_hook $num") if $main::Debug{owfs}; + &main::print_log( "Owfs_DS18S20::reload_hook") if $main::Debug{owfs}; $timer->set(10, sub {&Owfs_DS18S20::run_loop}); } sub run_loop { - # exit if we don't have any clients. - return unless @clients; - - # issue simultaneous to start a conversion - if ($index == 0) { - my $self = $clients[0]; - &main::print_log ( "Owfs_DS18S20:: $index simultaneous") if $main::Debug{owfs}; - $self->set_root ( "simultaneous/temperature", "1" ); - } else { - my $self = $clients[$index-1]; - $self->{present} = $self->get("present"); - my $temperature = $self->get("temperature"); - $self->{temperature} = $temperature; - if ($main::Debug{owfs}) { - my $device = $self->{device}; - my $location = $self->{location}; - &main::print_log ("Owfs_DS18S20 $index $device $location temperature: $temperature") if $main::Debug{owfs}; - } - } - - # udpate the index - $index += 1; - if ($index > @clients) { - $index = 0; - } - - # reschedule the timer for next pass - $timer->set($clients[0]->get_interval( ), sub {&Owfs_DS18S20::run_loop}); + # exit if we don't have any clients. + return unless scalar(@clients); + + # issue simultaneous to start a conversion + if ($index == 0) { + my $self = $clients[0]; + &main::print_log ( "Owfs_DS18S20::run_loop index: $index simultaneous") if $main::Debug{owfs}; + $self->_set_root ( "/simultaneous/temperature", 1); + } else { + my $self = $clients[$index-1]; + if (!defined $self->{token} && $self->{present}) { + $self->SUPER::get("temperature"); + } + } + + # udpate the index + $index += 1; + if ($index > @clients) { + $index = 0; + } + # reschedule the timer for next pass + $timer->set($clients[0]->get_interval( ), sub {&Owfs_DS18S20::run_loop}); } #======================================================================================= @@ -344,52 +1263,66 @@ sub run_loop { Usage: - $sensor = new Owfs_DS2405 ( "", ); + $sensor = new Owfs_DS2405 ( "", , ); - of the form family.address; identifies the one-wire device - ASCII string identifier providing a useful name for device_id + - Optional (defaults to 2). Number of seconds between reads of sensed. Examples: - my $relay = new Owfs_DS2405 ( "20.DB2506000000", "Some Relay", "0" ); - - // Turn on relay + my $relay = new Owfs_DS2405_pio ( "20.DB2506000000", "Some Relay" ); + + # Turn on relay $relay->set_pio("1"); - // Turn off relay - $realy->set_pio("0"); + # Turn off relay + $relay->set_pio("0"); - // Detect input transition - my $doorbell = new Owfs_DS2405 ( "20.DB2506000000", "Front Door Bell", "1", 1 ); - if ($doorbell->get_latch( )) { - print_log ("notice,,, someone is at the front door"); - speak (rooms=>"all", text=> "notice,,, someone is at the front door"); -} + # Detect input transition + my $doorbell = new Owfs_DS2405_sense ( "20.DB2506000000", "Front Door Bell", 1 ); + if ($doorbell->state_now( )) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } =cut +package Owfs_DS2405; use strict; -package Owfs_DS2405; +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; -@Owfs_DS2405::ISA = ('Owfs_Item'); +@Owfs_DS2405::ISA = ('Owfs_DS2405_pio'); sub new { - my ($class, $ds2405, $location ) = @_; - my $self = new Owfs_Item ( $ds2405, $location ); + my ($class, $device, $location, $interval) = @_; + my $self = new Owfs_DS2405_pio ( $device, $location, $interval ); bless $self,$class; return $self; } -sub set_pio { - my ($self,$value) = @_; - $self->set ("PIO", $value); +@Owfs_DS2405_pio::ISA = ('Owfs_Switch'); + +sub new { + my ($class, $device, $location, $interval) = @_; + my $self = new Owfs_Switch ( $device, $location, undef, $interval, PIO); + bless $self,$class; + return $self; } -sub get_pio { - my ($self) = @_; - my $channel = $self->{channel}; - return ($self->get ("PIO")); +@Owfs_DS2405_sense::ISA = ('Owfs_Switch'); + +sub new { + my ($class, $device, $location, $interval) = @_; + my $self = new Owfs_Switch ( $device, $location, undef, $interval, SENSE ); + bless $self,$class; + return $self; } #======================================================================================= @@ -409,126 +1342,122 @@ Usage: - of the form family.address; identifies the one-wire device - ASCII string identifier providing a useful name for device_id - "0", "1", "2", "3", "4", "5", "6", "7" - - Optional (defaults to 10). Number of seconds between input samples. + - Optional (defaults to 2). Number of seconds between input samples. Examples: - my $relay = new Owfs_DS2408 ( "20.DB2506000000", "Some Relay", "0" ); - - // Turn on relay - $relay->set_pio("1"); + # RELAY + my $relay = new Owfs_DS2408_pio ( "20.DB2506000000", "Some Relay", "0", 1 ); + $relay->set_pio("1"); # Turn on Relay + $relay->set_pio("0"); # Turn off Relay + my $state = $state->state( ); # 0: Relay off 1: Relay on - // Turn off relay - $realy->set_pio("0"); + # LATCH + my $doorbell = new Owfs_DS2408_latch ( "20.DB2506000000", "Front Door Bell", "1", 1 ); + if (my $state = said $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } - // Detect input transition - my $doorbell = new Owfs_DS2408 ( "20.DB2506000000", "Front Door Bell", "1", 1 ); - if ($doorbell->get_latch( )) { - print_log ("notice,,, someone is at the front door"); - speak (rooms=>"all", text=> "notice,,, someone is at the front door"); -} + or + + if (my $state = state_now $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } + + or + + if (my $state = state_changed $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } =cut +package Owfs_DS2408; use strict; -package Owfs_DS2408; +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; -@Owfs_DS2408::ISA = ('Owfs_Item'); +@Owfs_DS2408::ISA = ('Owfs_DS2408_pio'); sub new { - my ($class, $ds2408, $location, $channel, $interval) = @_; - my $self = new Owfs_Item ( $ds2408, $location ); - bless $self,$class; - - $self->{interval} = 10; - if (defined $interval && ($interval >= 1)) { - $self->{interval} = $interval; - } - $self->{present} = 0; - $self->{latch} = 0; - $self->{pass_triggered} = 0; - $self->{sensed} = undef; - $self->{channel} = $channel; + my ($class, $device, $location, $channel, $interval) = @_; + my $self = new Owfs_DS2408_pio ( $device, $location, $channel, $interval ); + #bless $self,$class; + return $self; +} - $self->restore_data('latch'); +package Owfs_DS2408_pio; +use strict; - &::Reload_pre_add_hook(\&Owfs_DS2408::reload_hook, 1); +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; - $self->{timer} = new Timer; - $self->{timer}->set($self->{interval}, sub {&Owfs_DS2408::run_loop($self)}); +@Owfs_DS2408_pio::ISA = ('Owfs_Switch'); +sub new { + my ($class, $device, $location, $channel, $interval) = @_; + if (($channel < 0) || ($channel > 7)) { + &main::print_log ("Owfs_DS2408::new ERROR channel ($channel) out of range!"); + } + my $self = new Owfs_Switch ( $device, $location, $channel, $interval, PIO ); + #bless $self,$class; return $self; } -sub get_present { - my ($self) = @_; - return $self->{present}; -} - -sub set_interval { - my ($self,$interval) = @_; - $self->{interval} = $interval if defined $interval; -} - -sub get_interval { - my ($self) = @_; - return $self->{interval}; -} +package Owfs_DS2408_sense; +use strict; -sub set_pio { - my ($self,$value) = @_; - my $channel = $self->{channel}; - $self->set ("PIO.$channel", $value); -} +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; -sub get_pio { - my ($self) = @_; - my $channel = $self->{channel}; - return ($self->get ("PIO.$channel")); -} +@Owfs_DS2408_sense::ISA = ('Owfs_Switch'); -sub get_latch { - my ($self) = @_; - my $latch = $self->{latch}; - if ($latch) { - $self->{latch} = 0; - $self->{pass_triggered} = 0; +sub new { + my ($class, $device, $location, $channel, $interval) = @_; + if (($channel < 0) || ($channel > 7)) { + &main::print_log ("Owfs_DS2408::new ERROR channel ($channel) out of range!"); } - return ($latch); + my $self = new Owfs_Switch ( $device, $location, $channel, $interval, SENSE ); + #bless $self,$class; + return $self; } -sub get_sensed { - my $self = shift; - return ($self->{sensed} eq 1 ? 1 : 0); -} +package Owfs_DS2408_latch; +use strict; -sub reload_hook { -} +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; -sub run_loop { - my $self = shift; - my $channel = $self->{channel}; - my $latch = $self->get ("latch.$channel"); - $self->{present} = $self->get("present"); - $self->{sensed} = $self->get ("sensed.$channel"); - if ($latch) { - $self->{pass_triggered} = $main::Loop_Count; - $self->{latch} = $latch; - $self->set("latch.$channel", "0"); - } elsif ($self->{pass_triggered} && $self->{pass_triggered} < $main::Loop_Count) { - $self->{latch} = 0; - $self->{pass_triggered} = 0; - } - - if ($main::Debug{owfs}) { - my $device = $self->{device}; - my $location = $self->{location}; - &main::print_log ("Owfs_DS2408 $index $device $location $channel latch: $latch"); - } +@Owfs_DS2408_latch::ISA = ('Owfs_Switch'); - # reschedule the timer for next pass - $self->{timer}->set($self->get_interval( ), sub {&Owfs_DS2408::run_loop($self)}); +sub new { + my ($class, $device, $location, $channel, $interval) = @_; + if (($channel < 0) || ($channel > 7)) { + &main::print_log ("Owfs_DS2408::new ERROR channel ($channel) out of range!"); + } + my $self = new Owfs_Switch ( $device, $location, $channel, $interval, LATCH ); + #bless $self,$class; + return $self; } #======================================================================================= @@ -552,99 +1481,100 @@ Usage: Examples: - my $switch = new Owfs_DS2413 ( "20.DB2506000000", "Some Switch", "A" ); + # RELAY + my $relay = new Owfs_DS2413 ( "20.DB2506000000", "Some Relay", "0", 0 ); + $relay->set( 1 ); # Turn on Relay + $relay->set( 0 ); # Turn off Relay + my $state = $state->state( ); # 0: Relay off 1: Relay on - // Turn on switch - $switch->set_pio("1"); + # SENSE + my $doorbell = new Owfs_DS2413_sense ( "20.DB2506000000", "Front Door Bell", "1", 1 ); + if (my $state = said $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } - // Turn off switch - $switch->set_pio("0"); + or - // Detect input transition - my $doorbell = new Owfs_DS2413 ( "20.DB2506000000", "Front Door Bell", "A", 1 ); - if ($doorbell->get_latch( )) { - print_log ("notice,,, someone is at the front door"); - speak (rooms=>"all", text=> "notice,,, someone is at the front door"); -} + if (my $state = state_now $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } -=cut + or -use strict; + if (my $state = state_changed $doorbell) { + print_log ("notice,,, someone is at the front door"); + speak (rooms=>"all", text=> "notice,,, someone is at the front door"); + } -package Owfs_DS2413; + or -@Owfs_DS2413::ISA = ('Owfs_Item'); + my $state = $doorbell->state( ) -sub new { - my ($class, $ds2413, $location, $channel, $interval) = @_; - my $self = new Owfs_Item ( $ds2413, $location ); - bless $self,$class; +=cut - $self->{interval} = 10; - if (defined $interval && ($interval >= 1)) { - $self->{interval} = $interval; - } - $self->{present} = 0; - $self->{sensed} = undef; - $self->{channel} = $channel; +package Owfs_DS2413; +use strict; - &::Reload_pre_add_hook(\&Owfs_DS2413::reload_hook, 1); +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; - $self->{timer} = new Timer; - $self->{timer}->set($self->{interval}, sub {&Owfs_DS2413::run_loop($self)}); +@Owfs_DS2413::ISA = ('Owfs_DS2413_pio'); +sub new { + my ($class, $device, $location, $channel, $interval) = @_; + my $self = new Owfs_DS2413_pio ( $device, $location, $channel, $interval ); + bless $self,$class; return $self; } -sub get_present { - my ($self) = @_; - return $self->{present}; -} +package Owfs_DS2413_pio; +use strict; -sub set_interval { - my ($self,$interval) = @_; - $self->{interval} = $interval if defined $interval; -} +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; -sub get_interval { - my ($self) = @_; - return $self->{interval}; -} +@Owfs_DS2413_pio::ISA = ('Owfs_Switch'); -sub set_pio { - my ($self,$value) = @_; - my $channel = $self->{channel}; - $self->set ("PIO.$channel", $value); +sub new { + my ($class, $device, $location, $channel, $interval) = @_; + if (($channel < 0) || ($channel > 1)) { + &main::print_log ("Owfs_DS2413::new ERROR channel ($channel) out of range!"); + } + my $self = new Owfs_Switch ( $device, $location, $channel, $interval, PIO ); + bless $self,$class; + return $self; } -sub get_pio { - my ($self) = @_; - my $channel = $self->{channel}; - return ($self->get ("PIO.$channel")); -} +package Owfs_DS2413_sense; +use strict; -sub get_sensed { - my $self = shift; - return ($self->{sensed} eq 1 ? 1 : 0); -} +use constant; +use constant ON => 'on'; +use constant OFF => 'off'; +use constant PIO => 0; +use constant SENSE => 1; +use constant LATCH => 2; -sub reload_hook { -} +@Owfs_DS2413_sense::ISA = ('Owfs_Switch'); -sub run_loop { - my $self = shift; - my $channel = $self->{channel}; - $self->{present} = $self->get("present"); - $self->{sensed} = $self->get ("sensed.$channel"); - - if ($main::Debug{owfs}) { - my $device = $self->{device}; - my $location = $self->{location}; - &main::print_log ("Owfs_DS2413 $index $device $location $channel"); +sub new { + my ($class, $device, $location, $channel, $interval) = @_; + if (($channel < 0) || ($channel > 1)) { + &main::print_log ("Owfs_DS2413::new ERROR channel ($channel) out of range!"); } - - # reschedule the timer for next pass - $self->{timer}->set($self->get_interval( ), sub {&Owfs_DS2413::run_loop($self)}); + my $self = new Owfs_Switch ( $device, $location, $channel, $interval, SENSE ); + bless $self,$class; + return $self; } #======================================================================================= @@ -669,38 +1599,55 @@ Usage: Example: $ds2450 = new Owfs_DS2450 ( "20.DB2506000000", "Furnace Sensor", "A" ); - - my $voltage = $ds2450->get_voltage( ); -=cut + if (my $voltage = said $ds2450) { + ... + } -use strict; + or; + + if (my $voltage = state_now $ds2450) { + ... + } + + if (my $voltage = state_changed $ds2450) { + ... + } + + or; + + my $voltage = $ds2450->state( ); + +=cut package Owfs_DS2450; +use strict; @Owfs_DS2450::ISA = ('Owfs_Item'); -my @clients = (); -my $index = 0; -my $timer = undef; +our @clients = (); +our $index = 0; +our $timer = undef; sub new { - my ($class, $ds2450, $location, $channel, $interval) = @_; - my $self = new Owfs_Item ( $ds2450, $location ); + my ($class, $device, $location, $channel, $interval) = @_; + my $self = new Owfs_Item ( $device, $location ); bless $self,$class; + $self->{channel} = $channel; $self->{interval} = 10; if (defined $interval && ($interval > 1)) { $self->{interval} = $interval if defined $interval; } - $self->{present} = 0; $self->{voltage} = undef; - $self->{channel} = $channel; if (!defined $timer) { &::Reload_pre_add_hook(\&Owfs_DS2450::reload_hook, 1); + @clients = ( ); $index = 0; $timer = new Timer; + } + if ($timer->inactive( )) { $timer->set($self->{interval}, sub {&Owfs_DS2450::run_loop}); } @@ -710,19 +1657,9 @@ sub new { $clients[0]->set_interval($self->{interval}); } - $self->set ( "set_alarm/voltlow.$channel", "1.0" ); - $self->set ( "set_alarm/low.$channel", "1" ); - $self->set ( "power", "1" ); - $self->set ( "PIO.$channel", "1" ); - return $self; } -sub get_present { - my ($self) = @_; - return $self->{present}; -} - sub set_interval { my ($self,$interval) = @_; $self->{interval} = $interval if defined $interval; @@ -733,129 +1670,107 @@ sub get_interval { return $self->{interval}; } +sub set { + my ($self) = @_; +} + +sub get { + my ($self) = @_; + return $self->state( ); +} + sub get_voltage { - my $self = shift; - return ($self->{voltage}); + my ($self) = @_; + return unless $self->get_present( ); + return $self->state( ); +} + +# This method is called when the read request is returned from owserver. +sub process_read_response { + my ($self, $voltage) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $channel = $self->{channel}; + if (defined $voltage) { + $voltage = $self->_chomp_plus($voltage); + if ($voltage ne $self->state( )) { + $self->SUPER::process_read_response($voltage); + } + $self->{voltage} = $voltage; + &main::print_log ("Owfs_DS2450::process_read_response $device $location $channel voltage: $voltage") if $main::Debug{owfs}; + } else { + &main::print_log ("Owfs_DS2450::process_read_response $device $location $channel ERROR"); # if $main::Debug{owfs}; + } + $self->{token} = undef; + $self->{value} = undef; +} + +# This method is called when the response for a write request to owserver returns. +sub process_write_response { + my ($self, $response) = @_; + my $device = $self->{device}; + my $location = $self->{location}; + my $token = $self->{token}; + my $value = $self->{value}; + &main::print_log ("Owfs_DS2450::process_write_response $device $location response: $response token: $token value: $value") if $main::Debug{owfs}; + $self->{token} = undef; + $self->{value} = undef; +} + +# This method is called whenever the object has been discovered. Useful for initialization. +sub discovered { + my ($self) = @_; + my $channel = $self->{channel}; + $self->SUPER::set ( "set_alarm/voltlow.$channel", "1.0" ); + $self->SUPER::set ( "set_alarm/low.$channel", "1" ); + $self->SUPER::set ( "power", "1" ); + $self->SUPER::set ( "PIO.$channel", 1 ); } sub reload_hook { @clients = (); - my $num = @clients; - &main::print_log( "Owfs_DS2450::reload_hook $num") if $main::Debug{owfs}; + &main::print_log( "Owfs_DS2450::reload_hook") if $main::Debug{owfs}; $timer->set(10, sub {&Owfs_DS2450::run_loop}); } +# This method runs using a timer, with an interval of interval timer. Each +# pass of the timer will result in one A/D measurement reading. All of the DS2450 +# devices share this same timer loop. The first iteration of the loop will execute +# a simultaneous voltage reading, to cause all A/D device to start a conversion at +# the same time. The remaing passes are used to pick up the results from the +# simultaneous converstion. sub run_loop { - # exit if we don't have any clients. - return unless @clients; - + # exit if no clients + return unless scalar(@clients); + # issue simultaneous to start a conversion if ($index == 0) { - my $self = $clients[0]; - my $channel = $self->{channel}; - &main::print_log ( "Owfs_DS2450:: $index simultaneous: $channel index: $index") if $main::Debug{owfs}; - $self->set_root ( "simultaneous/voltage", "1" ); + my $self = $clients[0]; + &main::print_log ( "Owfs_DS2450::run_loop $index simultaneous") if $main::Debug{owfs}; + $self->_set_root ( "/simultaneous/voltage", 1 ); } else { - my $self = $clients[$index-1]; - my $channel = $self->{channel}; - my $voltage = $self->get ("volt.$channel"); - $self->{present} = $self->get("present"); - $self->{voltage} = $voltage; - if ($main::Debug{owfs}) { - my $device = $self->{device}; - my $location = $self->{location}; - &main::print_log ("Owfs_DS2450 $index $device $location $channel volt: $voltage"); - } - } - + my $self = $clients[$index-1]; + my $channel = $self->{channel}; + my $device = $self->{device}; + my $location = $self->{location}; + my $token = $self->{token}; + my $present = $self->{present}; + &main::print_log ( "Owfs_DS2450::run_loop $index $device $location channel: $channel present: $present token: $token") if $main::Debug{owfs}; + if (!defined $self->{token} && $self->{present}) { + $self->SUPER::get("volt.$channel"); + } + } + # udpate the index $index += 1; if ($index > @clients) { - $index = 0; + $index = 0; } - + # reschedule the timer for next pass $timer->set($clients[0]->get_interval( ), sub {&Owfs_DS2450::run_loop}); + } 1; - -__END__ - -Got this from the tini@ibutton.com list on 3/00: - -Field Index: ------------- -(1) Family code in hex -(2) Number of regular memory pages -(3) Length of regular memory page in bytes -(4) Number of status memory pages -(5) Length of status memory page in bytes -(6) Max communication speed (0 regular, 1 Overdrive) -(7) Memory type (see below) -(8) Part number in iButton package -(9) Part number in non-iButton package -(10) Brief descriptions - -(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) -------------------------------------------------------- -01, 0, 0, 0, 0, 1, 0, DS1990A,DS2401,Unique Serial Number -02, 0, 0, 0, 0, 0, 0, DS1991,DS1205, MultiKey iButton -04, 16, 32, 0, 0, 0, 1, DS1994,DS2404,4K-bit NVRAM with Clock -05, 0, 0, 0, 0, 0, 0, DS2405,,Single Addressable Switch -06, 16, 32, 0, 0, 0, 1, DS1993,DS2403,4K-bit NVRAM -08, 4, 32, 0, 0, 0, 1, DS1992,DS2402,1K-bit NVRAM -09, 4, 32, 1, 8, 1, 2, DS1982,DS2502,1K-bit EPROM -0A, 64, 32, 0, 0, 1, 1, DS1995,DS2416,16K-bit NVRAM -0B, 64, 32, 40, 8, 1, 3, DS1985,DS2505,16K-bit EPROM -0C, 256, 32, 0, 0, 1, 1, DS1996,DS2464,64K-bit NVRAM -0F, 256, 32, 64, 8, 1, 3, DS1986,DS2506,64K-bit EPROM -10, 0, 0, 0, 0, 0, 0, DS1920,DS1820,Temperature iButton with -Trips -11, 2, 32, 1, 8, 0, 2, DS1981,DS2501,512-bit EPROM -12, 4, 32, 1, 8, 0, 4, DS2407,,Dual Addressable Switch -13, 16, 32, 34, 8, 0, 3, DS1983,DS2503,4K-bit EPROM -14, 1, 32, 0, 0, 0, 5, DS1971,DS2430A,256-bit EEPROM, plus -64-bit -OTP -15, 0, 0, 0, 0, 1, 0, DS87C900,,Lock Processor -16, 0, 0, 0, 0, 0, 0, DS1954,,Crypto iButton -18, 4, 32, 0, 0, 1, 6, DS1963S,4K-bit Transaction iButton with -SHA -1A, 16, 32, 0, 0, 1, 6, DS1963,,4K-bit Transaction iButton -1C, 4, 32, 0, 0, 1, 6, DS2422,,1K-bit EconoRAM with Counter -Input -1D, 16, 32, 0, 0, 1, 6, DS2423,,4K-bit EconoRAM with Counter -Input -1F, 0, 32, 0, 0, 0, 0, DS2409,,One-Wire Net Coupler -20, 3, 8, 0, 0, 1, 9, DS2450,,Quad A-D Converter -21, 16, 32, 0, 0, 1, 8, DS1921,,Temperature Recorder iButton -23, 16, 32, 0, 0, 1, 7, DS1973,DS2433,4K-bit EEPROM -40, 16, 32, 0, 0, 0, 1, DS1608,,Battery Pack Clock - - -Memory Types: --------------- -0 NOMEM - no user storage space or with - non-standard structure. -1 NVRAM - non-volatile rewritable RAM. -2 EPROM1- EPROM (OTP). - Contains an onboard 8-bit CRC data check. -3 EPROM2 - EPROM (OTP). TMEX Bitmap starting on status page 8 - Contains an onboard 16-bit CRC. -4 EPROM3 - EPROM (OTP). TMEX Bitmap in upper nibble of byte 0 of status -memory - Contains an onboard 16-bit CRC data check. -5 EEPROM1 - EEPROM, one address byte -6 MNVRAM - non-volatile rewritable RAM with read-only non rolling-over page - write cycle counters associated with last 1/4 of pages - (3 minimum) -7 EEPROM2 - EEPROM. On board CRC16 for Write/Read memory. - Copy Scratchpad returns an authentication byte (alternating -1/0). -8 NVRAM2 - non-volatile RAM. Contains an onboard 16-bit CRC. -9 NVRAM3 - non-volatile RAM with bit accessible memory. Contains an onboard - - 16-bit CRC. ----------------------------------------------------------------------------- From 4451c90e82c3703983485b20d54b46d7302b3276 Mon Sep 17 00:00:00 2001 From: Jim Duda Date: Sat, 25 May 2013 11:52:33 -0400 Subject: [PATCH 18/49] Correct a bug involving tracking the state of a latch. Update to all use of config_params{owfs_temp_uom} to control our unit of measure for temperature. --- lib/Owfs_Item.pm | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/Owfs_Item.pm b/lib/Owfs_Item.pm index e7506e22d..3a1471913 100644 --- a/lib/Owfs_Item.pm +++ b/lib/Owfs_Item.pm @@ -69,10 +69,6 @@ Example Usage: =cut # TODO -# document -# test raw Owfs_Item -# test others -# celcius/fahrenheit # maintain inventory # dump inventory # inventory of all items, not just those requested @@ -833,8 +829,6 @@ sub new { $self->{pio} = undef; $self->{latch} = 0; $self->{sensed} = undef; - $self->{pass_triggered} = 0; - $self->restore_data('latch'); $latch_store{$device} = 0; if (!exists $latch_mask{$device}) { @@ -992,20 +986,20 @@ sub process_read_response { } elsif ($self->{token} =~ /latch/) { $latch_store{$device} |= ($latch_mask{$device} & $response); my $ls = $latch_store{$device}; - my $lm = $latch_mask{$device}; + my $lm = sprintf ("%x", $latch_mask{$device}); my $chanidx = $channel; $chanidx = 0 if (!defined $channel); my $latch = ($latch_store{$device} >> $chanidx) & 1; + my $slatch = $self->{latch}; + &main::print_log ("Owfs_Switch::process_read_response device: $device location: $location channel: $channel latch: $latch slatch: $slatch ls: $ls lm: $lm chanidx: $chanidx") if $debug; if ($mode == LATCH) { if ($latch ne $self->{latch}) { my $state = $self->convert_state($latch); $self->SUPER::process_read_response($state); - $self->{pass_triggered} = $main::Loop_Count; - $latch_store{$device} &= ~(1 << $chanidx); + $self->{latch} = $latch; } } - $self->{latch} = $latch; - &main::print_log ("Owfs_Switch::process_read_response device: $device location: $location channel: $channel latch: $latch ls: $ls lm: $lm chanidx: $chanidx") if $debug; + $latch_store{$device} &= ~(1 << $chanidx); if ($response != 0) { $self->SUPER::set ($latchstr, 1); } else { @@ -1084,6 +1078,16 @@ sub run_loop { =begin comment + By default, the temperature unit of measure will be Celcius. Use the owfs_uom_temp + config_parm to control the desired temperature uom + + $main::config_parms{owfs_uom_temp} + + C Celcius + F Fahrenheit + K Kelvin + R Rankine + Usage: $sensor = new Owfs_DS18S20 ( "", , ); @@ -1190,8 +1194,6 @@ sub process_read_response { if (defined $temperature) { $temperature = $self->_chomp_plus($temperature); if ($temperature =~ /^[-]?\d+(?:[.]\d+)?$/) { - # convert to fahrenheit - $temperature = (($temperature*9)/5)+32; if ($temperature ne $self->state( )) { $self->SUPER::process_read_response( $temperature ); } From 0b9ea004affda7e873a37dae43cdad6f2e7af75f Mon Sep 17 00:00:00 2001 From: Jim Duda Date: Sat, 25 May 2013 12:34:17 -0400 Subject: [PATCH 19/49] Restore files to original master. --- lib/PocketSphinx.pm | 1 - lib/Weather_Common.pm | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/PocketSphinx.pm b/lib/PocketSphinx.pm index c0beab069..6bedacccb 100644 --- a/lib/PocketSphinx.pm +++ b/lib/PocketSphinx.pm @@ -198,7 +198,6 @@ sub reset_language_files { my ($self) = @_; $PocketSphinx_state = "reset"; $self->{disabled} = 0; - $self->{crash_cnt} = 0; } #============================================================================================ diff --git a/lib/Weather_Common.pm b/lib/Weather_Common.pm index e240dcebf..5dcc5119c 100644 --- a/lib/Weather_Common.pm +++ b/lib/Weather_Common.pm @@ -293,10 +293,7 @@ sub convert_humidity_to_dewpoint { return unless defined $humidity and defined $temp_celsius; # http://en.wikipedia.org/wiki/Dew_point - my $gamma = ( (17.271 * $temp_celsius) / (237.7 + $temp_celsius) ); - if ($humidity != 0) { - $gamma += log($humidity/100); - } + my $gamma = ( (17.271 * $temp_celsius) / (237.7 + $temp_celsius) ) + log($humidity/100); my $dew_point = (237.7 * $gamma) / (17.271 - $gamma); # old calculations From 43f3030477d4d20c4f99d1d8da3b0ab01c5b94e7 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 31 May 2013 18:57:01 -0700 Subject: [PATCH 20/49] Insteon_RemoteLinc: Cleanup Documentation --- lib/Insteon/Controller.pm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index cb87d19f8..bc005176a 100755 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -113,7 +113,7 @@ to the device. If the device is not responding to the battery level requests, consider increasing this value. However, keep in mind that a longer awake time will result in more battery usage. -The factory setting is 4 seconds, 10 seconds seems to work with MisterHouse +The factory setting is 4 seconds, 10 seconds seems to work well with MisterHouse without causing adverse battery drain. =cut @@ -278,11 +278,11 @@ as its state. This is helpful if you want to be able to view the battery level through a web page. Battery level tracking is likely only available on RemoteLinc 2 devices. -This objects state will be updated based on interval defined for C +This object's state will be updated based on interval defined for C in the parent B object. -Once created, you can tie_events directly to this object rather than using the -battery_low_event code in the parent B object. +Once created, you can tie_events directly to this object, for example to alert +you when the battery is low. =head2 INHERITS From c7b08a8fe3c88571a042e860f701140f38f1bae0 Mon Sep 17 00:00:00 2001 From: Jim Duda Date: Sat, 1 Jun 2013 22:22:11 -0400 Subject: [PATCH 21/49] Oops, the last commit had git merge stuff. This is the proper changes. --- lib/Owfs_Item.pm | 513 ++++++----------------------------------------- 1 file changed, 66 insertions(+), 447 deletions(-) diff --git a/lib/Owfs_Item.pm b/lib/Owfs_Item.pm index 245336ae9..3a1471913 100644 --- a/lib/Owfs_Item.pm +++ b/lib/Owfs_Item.pm @@ -1,6 +1,5 @@ -=head1 B +=begin comment -<<<<<<< HEAD Owfs_Item.pm 03/10/2007 Created by Jim Duda (jim@duda.tzo.com) @@ -17,14 +16,10 @@ Requirements: http://www.owfs.org Setup: -======= -=head2 SYNOPSIS ->>>>>>> upstream/master In your code module, instantation the Owfs_Item class (or extension) to interface with some one-wire element. The one-wire device can be found using the OWFS html interface. -<<<<<<< HEAD configure mh.private.ini owfs_port = 4304 # defined port where the owfs server is listening @@ -32,8 +27,6 @@ owfs_port = 4304 # defined port where the owfs server is listening Example Usage: -======= ->>>>>>> upstream/master $item = new Owfs_Item ( "", ); - of the form family.address; identifies the one-wire device @@ -73,8 +66,8 @@ Example Usage: Extended devices will have different API routines and will typically not use the set/get methods. +=cut -<<<<<<< HEAD # TODO # maintain inventory # dump inventory @@ -88,95 +81,6 @@ Example Usage: # Owfs_Item should handle any Owfs device, and provides access to any individual field. # #======================================================================================= -======= -=head2 DESCRIPTION - -Use this module to interface with the OWFS (one-wire filesystem) software. -The OWFS software handles all the real-time processing of the one-wire itself, -offering a simple PERL API interface. - -Owfs_Item should handle any Owfs device, and provides access to any individual field. - -Requirements: - - Download and install OWFS (tested against release owfs-2.7p21) http://www.owfs.org - -Got this from the tini@ibutton.com list on 3/00: - - Field Index: - ------------ - (1) Family code in hex - (2) Number of regular memory pages - (3) Length of regular memory page in bytes - (4) Number of status memory pages - (5) Length of status memory page in bytes - (6) Max communication speed (0 regular, 1 Overdrive) - (7) Memory type (see below) - (8) Part number in iButton package - (9) Part number in non-iButton package - (10) Brief descriptions - - (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) - ------------------------------------------------------- - 01, 0, 0, 0, 0, 1, 0, DS1990A,DS2401,Unique Serial Number - 02, 0, 0, 0, 0, 0, 0, DS1991,DS1205, MultiKey iButton - 04, 16, 32, 0, 0, 0, 1, DS1994,DS2404,4K-bit NVRAM with Clock - 05, 0, 0, 0, 0, 0, 0, DS2405,,Single Addressable Switch - 06, 16, 32, 0, 0, 0, 1, DS1993,DS2403,4K-bit NVRAM - 08, 4, 32, 0, 0, 0, 1, DS1992,DS2402,1K-bit NVRAM - 09, 4, 32, 1, 8, 1, 2, DS1982,DS2502,1K-bit EPROM - 0A, 64, 32, 0, 0, 1, 1, DS1995,DS2416,16K-bit NVRAM - 0B, 64, 32, 40, 8, 1, 3, DS1985,DS2505,16K-bit EPROM - 0C, 256, 32, 0, 0, 1, 1, DS1996,DS2464,64K-bit NVRAM - 0F, 256, 32, 64, 8, 1, 3, DS1986,DS2506,64K-bit EPROM - 10, 0, 0, 0, 0, 0, 0, DS1920,DS1820,Temperature iButton with Trips - 11, 2, 32, 1, 8, 0, 2, DS1981,DS2501,512-bit EPROM - 12, 4, 32, 1, 8, 0, 4, DS2407,,Dual Addressable Switch - 13, 16, 32, 34, 8, 0, 3, DS1983,DS2503,4K-bit EPROM - 14, 1, 32, 0, 0, 0, 5, DS1971,DS2430A,256-bit EEPROM, plus 64-bit OTP - 15, 0, 0, 0, 0, 1, 0, DS87C900,,Lock Processor - 16, 0, 0, 0, 0, 0, 0, DS1954,,Crypto iButton - 18, 4, 32, 0, 0, 1, 6, DS1963S,4K-bit Transaction iButton with SHA - 1A, 16, 32, 0, 0, 1, 6, DS1963,,4K-bit Transaction iButton - 1C, 4, 32, 0, 0, 1, 6, DS2422,,1K-bit EconoRAM with Counter Input - 1D, 16, 32, 0, 0, 1, 6, DS2423,,4K-bit EconoRAM with Counter Input - 1F, 0, 32, 0, 0, 0, 0, DS2409,,One-Wire Net Coupler - 20, 3, 8, 0, 0, 1, 9, DS2450,,Quad A-D Converter - 21, 16, 32, 0, 0, 1, 8, DS1921,,Temperature Recorder iButton - 23, 16, 32, 0, 0, 1, 7, DS1973,DS2433,4K-bit EEPROM - 40, 16, 32, 0, 0, 0, 1, DS1608,,Battery Pack Clock - - Memory Types: - -------------- - 0 NOMEM - no user storage space or with - non-standard structure. - 1 NVRAM - non-volatile rewritable RAM. - 2 EPROM1- EPROM (OTP). - Contains an onboard 8-bit CRC data check. - 3 EPROM2 - EPROM (OTP). TMEX Bitmap starting on status page 8 - Contains an onboard 16-bit CRC. - 4 EPROM3 - EPROM (OTP). TMEX Bitmap in upper nibble of byte 0 of status memory - Contains an onboard 16-bit CRC data check. - 5 EEPROM1 - EEPROM, one address byte - 6 MNVRAM - non-volatile rewritable RAM with read-only non rolling-over page - write cycle counters associated with last 1/4 of pages (3 minimum) - 7 EEPROM2 - EEPROM. On board CRC16 for Write/Read memory. - Copy Scratchpad returns an authentication byte (alternating 1/0). - 8 NVRAM2 - non-volatile RAM. Contains an onboard 16-bit CRC. - 9 NVRAM3 - non-volatile RAM with bit accessible memory. Contains an onboard 16-bit CRC. - -=head2 INHERITS - -B - -=head2 METHODS - -=over - -=item B - -=cut ->>>>>>> upstream/master use Timer; use Socket_Item; @@ -1164,11 +1068,16 @@ sub run_loop { $self->{loop_timer}->set($self->{interval}, sub {Owfs_Switch::run_loop($self);}); } -=back +#======================================================================================= +# +# Owfs_DS18S20 +# +# This package specifically handles the DS18S20 Thermometer +# +#======================================================================================= -=head2 INI PARAMETERS +=begin comment -<<<<<<< HEAD By default, the temperature unit of measure will be Celcius. Use the owfs_uom_temp config_parm to control the desired temperature uom @@ -1180,69 +1089,18 @@ sub run_loop { R Rankine Usage: -======= - owfs_port = 3030 # defined port where the owfs server is listening - # (owserver defaults to 4304) ->>>>>>> upstream/master -=head2 AUTHOR + $sensor = new Owfs_DS18S20 ( "", , ); -03/10/2007 Created by Jim Duda (jim@duda.tzo.com) + - of the form family.address; identifies the one-wire device + - ASCII string identifier providing a useful name for device_id + - Optional (defaults to 10). Number of seconds between measurements. -=head2 SEE ALSO + Example: -<<<<<<< HEAD $ds18S20 = new Owfs_DS18S20 ( "10.DB2506000000", "Living Room", 2 ); my $temperature = get_temperature $ds18S20; -======= -NONE - -=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 - - - - - - -=head1 B - -=head2 SYNOPSIS - - $sensor = new Owfs_DS18S20 ( "", , ); - - - of the form family.address; identifies the one-wire device - - ASCII string identifier providing a useful name for device_id - - Optional (defaults to 10). Number of seconds between measurements. - -Example: - - $ds18S20 = new Owfs_DS18S20 ( "10.DB2506000000", "Living Room", 2 ); - - my $temperature = get_temperature $ds18S20; - -=head2 DESCRIPTION - -This package specifically handles the DS18S20 Thermometer - -=head2 INHERITS - -B - -=head2 METHODS - -=over - -=item B ->>>>>>> upstream/master or; @@ -1395,27 +1253,26 @@ sub run_loop { $timer->set($clients[0]->get_interval( ), sub {&Owfs_DS18S20::run_loop}); } -=back +#======================================================================================= +# +# Owfs_DS2405 +# +# This package specifically handles the DS2405 Relay / IO controller. +# +#======================================================================================= -=head2 INI PARAMETERS +=begin comment -NONE +Usage: -<<<<<<< HEAD $sensor = new Owfs_DS2405 ( "", , ); - of the form family.address; identifies the one-wire device - ASCII string identifier providing a useful name for device_id - Optional (defaults to 2). Number of seconds between reads of sensed. -======= -=head2 AUTHOR - -03/10/2007 Created by Jim Duda (jim@duda.tzo.com) ->>>>>>> upstream/master -=head2 SEE ALSO + Examples: -<<<<<<< HEAD my $relay = new Owfs_DS2405_pio ( "20.DB2506000000", "Some Relay" ); # Turn on relay @@ -1430,64 +1287,6 @@ NONE print_log ("notice,,, someone is at the front door"); speak (rooms=>"all", text=> "notice,,, someone is at the front door"); } -======= -NONE - -=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 - - - - - - -=head1 B - -=head2 SYNOPSIS - - $sensor = new Owfs_DS2405 ( "", ); - - - of the form family.address; identifies the one-wire device - - ASCII string identifier providing a useful name for device_id - -Examples: - - my $relay = new Owfs_DS2405 ( "20.DB2506000000", "Some Relay", "0" ); - - // Turn on relay - $relay->set_pio("1"); - - // Turn off relay - $realy->set_pio("0"); - - // Detect input transition - my $doorbell = new Owfs_DS2405 ( "20.DB2506000000", "Front Door Bell", "1", 1 ); - if ($doorbell->get_latch( )) { - print_log ("notice,,, someone is at the front door"); - speak (rooms=>"all", text=> "notice,,, someone is at the front door"); - } - -=head2 DESCRIPTION - -This package specifically handles the DS2405 Relay / IO controller. - -=head2 INHERITS - -B - -=head2 METHODS - -=over - -=item B ->>>>>>> upstream/master =cut @@ -1528,26 +1327,27 @@ sub new { return $self; } -=back +#======================================================================================= +# +# Owfs_DS2408 +# +# This package specifically handles the DS2408 Relay / IO controller. +# +#======================================================================================= -=head2 INI PARAMETERS +=begin comment -NONE +Usage: -=head2 AUTHOR + $sensor = new Owfs_DS2408 ( "", , , ); -<<<<<<< HEAD - of the form family.address; identifies the one-wire device - ASCII string identifier providing a useful name for device_id - "0", "1", "2", "3", "4", "5", "6", "7" - Optional (defaults to 2). Number of seconds between input samples. -======= -03/10/2007 Created by Jim Duda (jim@duda.tzo.com) ->>>>>>> upstream/master -=head2 SEE ALSO + Examples: -<<<<<<< HEAD # RELAY my $relay = new Owfs_DS2408_pio ( "20.DB2506000000", "Some Relay", "0", 1 ); $relay->set_pio("1"); # Turn on Relay @@ -1574,67 +1374,6 @@ NONE print_log ("notice,,, someone is at the front door"); speak (rooms=>"all", text=> "notice,,, someone is at the front door"); } -======= -NONE - -=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 - - - - - - -=head1 B - -=head2 SYNOPSIS - - $sensor = new Owfs_DS2408 ( "", , , ); - - - of the form family.address; identifies the one-wire device - - ASCII string identifier providing a useful name for device_id - - "0", "1", "2", "3", "4", "5", "6", "7" - - Optional (defaults to 10). Number of seconds between input samples. - -Examples: - - my $relay = new Owfs_DS2408 ( "20.DB2506000000", "Some Relay", "0" ); - - // Turn on relay - $relay->set_pio("1"); - - // Turn off relay - $realy->set_pio("0"); - - // Detect input transition - my $doorbell = new Owfs_DS2408 ( "20.DB2506000000", "Front Door Bell", "1", 1 ); - if ($doorbell->get_latch( )) { - print_log ("notice,,, someone is at the front door"); - speak (rooms=>"all", text=> "notice,,, someone is at the front door"); - } - - -=head2 DESCRIPTION - -This package specifically handles the DS2408 Relay / IO controller. - -=head2 INHERITS - -B - -=head2 METHODS - -=over - -=item B ->>>>>>> upstream/master =cut @@ -1723,19 +1462,27 @@ sub new { return $self; } -=back +#======================================================================================= +# +# Owfs_DS2413 +# +# This package specifically handles the DS2413 Dual Channel Addressable Switch. +# +#======================================================================================= -=head2 INI PARAMETERS +=begin comment -NONE +Usage: -=head2 AUTHOR + $sensor = new Owfs_DS2413 ( "", , , ); -03/10/2007 Created by Jim Duda (jim@duda.tzo.com) + - of the form family.address; identifies the one-wire device + - ASCII string identifier providing a useful name for device_id + - Channel identifier, "A" or "B" + - Optional (defaults to 10). Number of seconds between input samples. -=head2 SEE ALSO + Examples: -<<<<<<< HEAD # RELAY my $relay = new Owfs_DS2413 ( "20.DB2506000000", "Some Relay", "0", 0 ); $relay->set( 1 ); # Turn on Relay @@ -1755,66 +1502,6 @@ NONE print_log ("notice,,, someone is at the front door"); speak (rooms=>"all", text=> "notice,,, someone is at the front door"); } -======= -NONE - -=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 - - - - - - -=head1 B - -=head2 SYNOPSIS - - $sensor = new Owfs_DS2413 ( "", , , ); - - - of the form family.address; identifies the one-wire device - - ASCII string identifier providing a useful name for device_id - - Channel identifier, "A" or "B" - - Optional (defaults to 10). Number of seconds between input samples. - -Examples: - - my $switch = new Owfs_DS2413 ( "20.DB2506000000", "Some Switch", "A" ); - - // Turn on switch - $switch->set_pio("1"); - - // Turn off switch - $switch->set_pio("0"); - - // Detect input transition - my $doorbell = new Owfs_DS2413 ( "20.DB2506000000", "Front Door Bell", "A", 1 ); - if ($doorbell->get_latch( )) { - print_log ("notice,,, someone is at the front door"); - speak (rooms=>"all", text=> "notice,,, someone is at the front door"); - } - -=head2 DESCRIPTION - -This package specifically handles the DS2413 Dual Channel Addressable Switch. - -=head2 INHERITS - -B - -=head2 METHODS - -=over - -=item B ->>>>>>> upstream/master or @@ -1892,69 +1579,28 @@ sub new { return $self; } -=back - -=head2 INI PARAMETERS - -NONE - -=head2 AUTHOR - -03/10/2007 Created by Jim Duda (jim@duda.tzo.com) - -=head2 SEE ALSO - -NONE - -=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 - - +#======================================================================================= +# +# Owfs_DS2450 +# +# This package specifically handles the DS2450 A/D Converter. +# +#======================================================================================= +=begin comment +Usage: + $sensor = new Owfs_DS2450 ( "", , , ); -=head1 B + - of the form family.address; identifies the one-wire device + - ASCII string identifier providing a useful name for device_id + - "A", "B", "C", or "D" + - Optional (defaults to 10). Number of seconds between measurements. -=head2 SYNOPSIS + Example: -<<<<<<< HEAD $ds2450 = new Owfs_DS2450 ( "20.DB2506000000", "Furnace Sensor", "A" ); -======= - $sensor = new Owfs_DS2450 ( "", , , ); - - - of the form family.address; identifies the one-wire device - - ASCII string identifier providing a useful name for device_id - - "A", "B", "C", or "D" - - Optional (defaults to 10). Number of seconds between measurements. - -Example: - - $ds2450 = new Owfs_DS2450 ( "20.DB2506000000", "Furnace Sensor", "A" ); - - my $voltage = $ds2450->get_voltage( ); - -=head2 DESCRIPTION - -This package specifically handles the DS2450 A/D Converter. - -=head2 INHERITS - -B - -=head2 METHODS - -=over - -=item B ->>>>>>> upstream/master if (my $voltage = said $ds2450) { ... @@ -2130,30 +1776,3 @@ sub run_loop { } 1; -<<<<<<< HEAD -======= - -=back - -=head2 INI PARAMETERS - -NONE - -=head2 AUTHOR - -03/10/2007 Created by Jim Duda (jim@duda.tzo.com) - -=head2 SEE ALSO - -NONE - -=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 ->>>>>>> upstream/master From 0574d43ecd657d98919b86ea5bbe724a19e6ba78 Mon Sep 17 00:00:00 2001 From: Eloy Paris Date: Mon, 3 Jun 2013 11:54:03 -0400 Subject: [PATCH 22/49] Fix issue 210 - Return HTML page instead of HTML markup. - Use MH Version number instead of SVN $Id$ tag in the "About" page. - Set the pod2html cache directory to a place it will most likely be able to write to. --- web/bin/ListManager.pl | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/web/bin/ListManager.pl b/web/bin/ListManager.pl index b2088b6c7..51961b2df 100644 --- a/web/bin/ListManager.pl +++ b/web/bin/ListManager.pl @@ -20,8 +20,6 @@ my @Category; # array containing category name, in file order # this allow to get printed list in store aisle. my $AtShopStatus = ""; -my $Version = '$Revision$'; -$Version =~ s/\$//g; my $NumColumns; my $ColumnsWidth; @@ -490,8 +488,7 @@ $html .= qq[]; $html .= qq[]; -return $html; - +return &html_page('', $html); #}}} # ============== Subroutine ================ @@ -501,8 +498,8 @@ sub DisplayAbout { $html .= qq [

ListManager

-

$Version

-

Managing $PrettyListName

+

Version '$Version'

+

Managing list '$PrettyListName'




Gaetan Lord
@@ -1301,7 +1298,7 @@ =head1 Credits and contact information # ======================== POD END ================================== ]; - open DOC, "echo \"$POD\" | pod2html 2>/dev/null|"; + open DOC, "echo \"$POD\" | pod2html --cachedir=$config_parms{data_dir}/cache --flush 2>/dev/null |"; my $content = 0; while () { $content = 1 if / Date: Thu, 6 Jun 2013 19:05:13 -0700 Subject: [PATCH 23/49] Insteon: Add Initial Support for Linking i2cs Devices in MH No longer do you have to manually link i2cs devices. Added: enter_linking_mode() Places the object into linking mode as if you had held down the set button on the device. To create a link wherein the PLM is the controller, first run the PLM voice command "initiate link as controller". Then run this command. Finally, run the voice command "scan link table" on this device. This will eventually be merged into a simpler one-step method, however that will require some additional coding. --- lib/Insteon/BaseInsteon.pm | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index a0d50044c..186910b99 100644 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -1050,6 +1050,33 @@ sub unlink_to_interface } } +=item C + +BETA -- Can be used to create the initial link with i2cs devices. i1 devices +will not respond to this command. In the future, this will be incorporated into a +one-step process -- BETA + +Places the object into linking mode as if you had held down the set button on +the device. To create a link wherein the PLM is the controller, first run the +PLM voice command "initiate link as controller". Then run this command. Finally, +run the voice command "scan link table" on this device. + +The group argument is optional and not needed for group 01. + +Returns: nothing + +=cut + +sub enter_linking_mode +{ + my ($self,$p_group) = @_; + my $group = $p_group; + $group = '01' unless $group; + my $extra = sprintf("%02x", $group); + $extra .= '0' x (30 - length $extra); + my $message = new Insteon::InsteonMessage('insteon_ext_send', $self, 'linking_mode', $extra); + $self->_send_cmd($message); +} sub _aldb { From 58051a790e42142c60ec59c8509d9017ec4c98ac Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 6 Jun 2013 19:39:01 -0700 Subject: [PATCH 24/49] Insteon: Dont Just Decode the First Message Typo in the Debug4 printout was causing the first message to be reprinted multiple times if multiple messages were received in one pass. --- lib/Insteon_PLM.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index db50f4a0e..79b2d0704 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -598,7 +598,7 @@ sub _parse_data { { #ignore blanks.. the split does odd things next if $parsed_data eq ''; - &::print_log( "[Insteon_PLM] DEBUG4:\n".Insteon::MessageDecoder::plm_decode($data)) if $main::Debug{insteon} >= 4; + &::print_log( "[Insteon_PLM] DEBUG4:\n".Insteon::MessageDecoder::plm_decode($parsed_data)) if $main::Debug{insteon} >= 4; if ($previous_parsed_data eq $parsed_data){ # guard against repeats ::print_log("[Insteon_PLM] DEBUG3: Dropped duplicate message: $parsed_data") if $main::Debug{insteon} >= 3; From ad4b4b7c2adf5a592f9a3cd61e433c3d45f36099 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 6 Jun 2013 19:53:55 -0700 Subject: [PATCH 25/49] Insteon: Timeout After Receipt of AllLink Broadcast to Avoid Collision with Cleanup Previously MH ignored AllLink broadcast messages, so this wasn't an issue. Timeout is the number of linked devices that cleanup messages have to be sent to multiplied by the maximum hop length for a direct message and an ACK to be sent and received. --- lib/Insteon/BaseInsteon.pm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index a0d50044c..046e248f6 100644 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -719,6 +719,16 @@ sub _process_message } else { $self->set($p_state, $self); $$self{_pending_cleanup} = 1; + #Wait to avoid clobbering incomming subsequent cleanup messages + my @links = $self->find_members('Insteon::BaseDevice'); + #Timeout is the number of linked devices multiplied by + #the maximum hop length for a direct message and an ACK + #PLM is the +1 + my $timeout = (scalar(@links)+1) * 300; + ::print_log("[Insteon::BaseObject] DEBUG3 Delaying any outgoing messages ". + "by $timeout milliseconds to avoid collision with subsequent cleanup ". + "messages from " . $self->get_object_name) if ($main::Debug{insteon} >= 3); + $self->interface->_set_timeout('xmit', $timeout); } } elsif ($msg{type} eq 'cleanup') From e2f20e46fa9c4f33e20e364674ff17b9c44b8721 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 6 Jun 2013 20:13:31 -0700 Subject: [PATCH 26/49] Insteon: Set Cmd2 to 00 in All Link Send Commands Per the spec, Cmd2 should be 00, was getting set to FF when on command was sent. --- lib/Insteon/BaseInsteon.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index a0d50044c..84cfc665e 100644 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -406,7 +406,10 @@ sub derive_message return undef; } - if ($p_extra) + if ($self->isa("Insteon::InterfaceController")) + { + $message->extra('00') #All PLM Scenes are Cmd2=00; + } elsif ($p_extra) { $message->extra($p_extra); } elsif ($subcommand) { From 0142eb3c20b6478a4c1ec54504f8f0c37a43d072 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 7 Jun 2013 17:39:00 -0700 Subject: [PATCH 27/49] Insteon: Catch Status Requests in Unique _process_message Routines Controller and Security both have unique _process_message routines that catch messages unique to them. Before processing a message, these routines need to check to see if the incoming message is in response to a status request. Otherwise eventually the ALDB version number will match one of these unique message types, and MH gets confused. --- lib/Insteon/Controller.pm | 11 +++++++++-- lib/Insteon/Security.pm | 9 ++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index bc005176a..2484a2973 100644 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -197,13 +197,20 @@ sub _process_message { if ($root->_is_battery_time_expired){ #Queue an get_extended_info request if ($$root{queue_timer}->active){ - $$root{queue_timer}-restart(); + $$root{queue_timer}->restart(); } else { $$root{queue_timer}->set(3, '$root->get_extended_info(1)'); } } - if ($msg{command} eq "extended_set_get" && $msg{is_ack}){ + 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::RemoteLinc] Extended Set/Get ACK Received for " . $self->get_object_name) if $main::Debug{insteon}; diff --git a/lib/Insteon/Security.pm b/lib/Insteon/Security.pm index 2becf30bd..e60e89118 100644 --- a/lib/Insteon/Security.pm +++ b/lib/Insteon/Security.pm @@ -375,7 +375,14 @@ sub _process_message { my $no_retry = 1; $root->get_extended_info($no_retry); } - if ($msg{command} eq "extended_set_get" && $msg{is_ack}){ + 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::MotionSensor] Extended Set/Get ACK Received for " . $self->get_object_name) if $main::Debug{insteon}; From 77cb7e6051c374b94af3c5af1c0d9a4480b0e9e7 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Tue, 11 Jun 2013 19:51:10 -0700 Subject: [PATCH 28/49] Update_Docs: Initial Work to Allow Subdirectory Scanning The changes are not as widespread as it appears, but a large percentage of the code had to be indented Doesn't fully work yet. --- bin/update_docs | 274 ++++++++++++++++++++++++++---------------------- 1 file changed, 149 insertions(+), 125 deletions(-) diff --git a/bin/update_docs b/bin/update_docs index ce8f957d1..201c81744 100755 --- a/bin/update_docs +++ b/bin/update_docs @@ -80,130 +80,154 @@ $outdir = '../docs' unless $outdir and -d $outdir; -w $outdir || die "directory $outdir isn't writeable"; mkdir "$outdir/lib" unless -d "$outdir/lib"; -# make list of module and script files in lib so we can extract pod doc later -my %libfiles; -opendir LIB, $libdir || die "can't open $libdir directory: $!"; - -foreach ( readdir LIB ) { - $libfiles{$_}{exists} = 1 if /\.p[lm]$/i; -} +my ( $ipod, $mpod ); +## Get list of possible directories +my %libsubdirs; +opendir LIB, $libdir || die "can't open $libdir directory: $!"; + foreach ( readdir LIB ) { + $libsubdirs{$_}{exists} = 1 if (-d "$libdir/$_" && !($_ =~ /^site/i) + && !($_ =~ /^\./)); + } closedir LIB; -# make list of lib html files so we can delete obsolete ones -my %htmlfiles; -opendir OUT, "$outdir/lib" || die "can't open $outdir/lib directory: $!"; - -foreach ( readdir OUT ) { - $htmlfiles{$_}{exists} = 1 if /\.html$/i; -} - -closedir OUT; - -# convert the pod doc in each changed pl or pm file into html -my $changes = 0; -foreach my $lib ( keys %libfiles ) { - my $libfile = "$libdir/$lib"; - my $htmlfile = "$outdir/lib/$lib"; - $htmlfile =~ s/\.p[lm]$/.html/i; - $libfiles{$lib}{html} = $htmlfile; - - my $mdate = ( stat($libfile) )[9]; - my $hdate = ( stat($htmlfile) )[9]; - - #print "mdate $mdate hdate $hdate $libfile\n"; - if ( !-e $htmlfile or $mdate > $hdate ) { - print "converting $libfile to $htmlfile\n"; - $changes++; - pod2html( - "--title=$lib", "--infile=$libfile", - "--outfile=$htmlfile", "--header", - "--htmlroot=/docs", "--htmldir=$outdir/..", - "--podroot=$docdir", "--podpath=.", - "--css=/lib/pod.css", - ); - } -} - -# check for deleted lib files -foreach ( keys %htmlfiles ) { - my $htmlfile = "$outdir/lib/$_"; - my $pm = $_; - my $pl = $_; - $pm =~ s/\.html$/.pm/i; - $pl =~ s/\.html$/.pl/i; - my $check; #Don't invent keys that dont exist - $check = $pm if( exists( $libfiles{$pm})); - $check = $pl if( exists( $libfiles{$pl})); - if ( !$check or !$libfiles{$check}{exists}) { - $changes++; - print "deleting $htmlfile\n"; - unlink $htmlfile; - } -} - -# write out items and modules lists if any pm files changed -my ( $ipod, $mpod ); -if ($changes) { - my %packages; - foreach my $pm ( keys %libfiles ) { - next unless $pm =~ /.+\.pm$/i; - my $html = $pm; - $html =~ s/\.pm$/.html/i; - my $noext = $pm; - $noext =~ s/\.pm$//i; - my $modfile = "$libdir/$pm"; - my $htmlfile = "$outdir/lib/$html"; - - my $fh; - unless( open( $fh, $modfile) ) { - print "Can't open $modfile, skipping: $!\n"; - next; +## Start foreach loop + +foreach my $libsubdir ( keys %libsubdirs ) { + + ## make outdir if doesn't exist + ## Set libdir and outdir to correct settings + $libdir = "../lib/$libsubdir"; + my $htmldir = "$outdir/lib/$libsubdir"; + mkdir "$htmldir" unless -d "$htmldir"; + +print "[krk] - $libdir - $htmldir"; + + # make list of module and script files in lib so we can extract pod doc later + my %libfiles; + opendir LIB, $libdir || die "can't open $libdir directory: $!"; + + foreach ( readdir LIB ) { + $libfiles{$_}{exists} = 1 if /\.p[lm]$/i; } - my $current_p; - while ( my $l = <$fh> ) { - if ( $l =~ /^package ([^;]+);/ ) { - $current_p = $1; - - #print "found package $current_p in $pm\n"; - $packages{$current_p}{pm} = $pm; - $packages{$current_p}{html} = $html; - $packages{$current_p}{noext} = $noext; - } - elsif ( $l =~ /^sub new / ) { - - #print "found 'new' method in package $current_p in $pm\n"; - $packages{$current_p}{isitem} = 1 if $current_p; - } - elsif ( $l =~ /^=head/ ) { - - #print "found pod directive in package $current_p in $pm\n"; - $packages{$current_p}{haspod} = 1 if $current_p; - } - } - print "didn't find any packages in $pm\n" unless $current_p; - close $fh; - } - - foreach ( sort keys %packages ) { - - #print "package: $_\n"; - s/\//::/g; - my $pod = "=item $_\n\n"; - if ( $packages{$_}{haspod} ) { - $pod .= "L<$_|lib::" . $packages{$_}{noext} . "/$_>\n\n"; - } - else { - $pod .= "package $_ in $packages{$_}{pm} isn't documented yet\n\n"; - } - if ( $packages{$_}{isitem} ) { - $ipod .= $pod; - } - else { - $mpod .= $pod; - } - } -} + + closedir LIB; + + # make list of lib html files so we can delete obsolete ones + my %htmlfiles; + opendir OUT, $htmldir || die "can't open $htmldir directory: $!"; + + foreach ( readdir OUT ) { + $htmlfiles{$_}{exists} = 1 if /\.html$/i; + } + + closedir OUT; + + # convert the pod doc in each changed pl or pm file into html + my $changes = 0; + foreach my $lib ( keys %libfiles ) { + my $libfile = "$libdir/$lib"; + my $htmlfile = "$htmldir/$lib"; + $htmlfile =~ s/\.p[lm]$/.html/i; + $libfiles{$lib}{html} = $htmlfile; + + my $mdate = ( stat($libfile) )[9]; + my $hdate = ( stat($htmlfile) )[9]; + + #print "mdate $mdate hdate $hdate $libfile\n"; + if ( !-e $htmlfile or $mdate > $hdate ) { + print "converting $libfile to $htmlfile\n"; + $changes++; + pod2html( + "--title=$lib", "--infile=$libfile", + "--outfile=$htmlfile", "--header", + "--htmlroot=/docs", "--htmldir=$htmldir/..", + "--podroot=$docdir", "--podpath=.", + "--css=/lib/pod.css", + ); + } + } + + # check for deleted lib files + foreach ( keys %htmlfiles ) { + my $htmlfile = "$htmldir/$_"; + my $pm = $_; + my $pl = $_; + $pm =~ s/\.html$/.pm/i; + $pl =~ s/\.html$/.pl/i; + my $check; #Don't invent keys that dont exist + $check = $pm if( exists( $libfiles{$pm})); + $check = $pl if( exists( $libfiles{$pl})); + if ( !$check or !$libfiles{$check}{exists}) { + $changes++; + print "deleting $htmlfile\n"; + unlink $htmlfile; + } + } + + # write out items and modules lists if any pm files changed + if ($changes) { + my %packages; + foreach my $pm ( keys %libfiles ) { + next unless $pm =~ /.+\.pm$/i; + my $html = $pm; + $html =~ s/\.pm$/.html/i; + my $noext = $pm; + $noext =~ s/\.pm$//i; + my $modfile = "$libdir/$pm"; + my $htmlfile = "$htmldir/$html"; + + my $fh; + unless( open( $fh, $modfile) ) { + print "Can't open $modfile, skipping: $!\n"; + next; + } + my $current_p; + while ( my $l = <$fh> ) { + if ( $l =~ /^package ([^;]+);/ ) { + $current_p = $1; + + #print "found package $current_p in $pm\n"; + $packages{$current_p}{pm} = $pm; + $packages{$current_p}{html} = $html; + $packages{$current_p}{noext} = $noext; + } + elsif ( $l =~ /^sub new / ) { + + #print "found 'new' method in package $current_p in $pm\n"; + $packages{$current_p}{isitem} = 1 if $current_p; + } + elsif ( $l =~ /^=head/ ) { + + #print "found pod directive in package $current_p in $pm\n"; + $packages{$current_p}{haspod} = 1 if $current_p; + } + } + print "didn't find any packages in $pm\n" unless $current_p; + close $fh; + } + + foreach ( sort keys %packages ) { + + #print "package: $_\n"; + s/\//::/g; + my $pod = "=item $_\n\n"; + if ( $packages{$_}{haspod} ) { + $pod .= "L<$_|lib::" . $packages{$_}{noext} . "/$_>\n\n"; + } + else { + $pod .= "package $_ in $packages{$_}{pm} isn't documented yet\n\n"; + } + if ( $packages{$_}{isitem} ) { + $ipod .= $pod; + } + else { + $mpod .= $pod; + } + } + } + +}##Stop loop here? if ($ipod) { print "writing $outdir/items.pod file\n"; @@ -243,11 +267,11 @@ else { s/\.pod$/.html/i; print("deleting $docdir/$_\n"), unlink "$docdir/$_" if -e "$docdir/$_"; } - foreach ( keys %libfiles ) { - s/\.p[lm]$/.html/i; - print("deleting $docdir/lib/$_\n"), unlink "$docdir/lib/$_" - if -e "$docdir/lib/$_"; - } +# foreach ( keys %libfiles ) { +# s/\.p[lm]$/.html/i; +# print("deleting $docdir/lib/$_\n"), unlink "$docdir/lib/$_" +# if -e "$docdir/lib/$_"; +# } print("deleting $docdir/lib/\n"), rmdir "$docdir/lib" if -d "$docdir/lib"; print("deleting $docdir/modules.pod\n"), unlink "$docdir/modules.pod" if -w "$docdir/modules.pod"; From 0d1f2770854ca1578387364a9c40a87cd7475048 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 17:25:00 -0700 Subject: [PATCH 29/49] Update_Docs: Print SubDir Files in Items and Modules List --- bin/update_docs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/bin/update_docs b/bin/update_docs index 201c81744..83c2a2df7 100755 --- a/bin/update_docs +++ b/bin/update_docs @@ -87,22 +87,15 @@ my %libsubdirs; opendir LIB, $libdir || die "can't open $libdir directory: $!"; foreach ( readdir LIB ) { $libsubdirs{$_}{exists} = 1 if (-d "$libdir/$_" && !($_ =~ /^site/i) - && !($_ =~ /^\./)); + && !($_ =~ /^\.\./)); } closedir LIB; -## Start foreach loop - foreach my $libsubdir ( keys %libsubdirs ) { - - ## make outdir if doesn't exist - ## Set libdir and outdir to correct settings $libdir = "../lib/$libsubdir"; my $htmldir = "$outdir/lib/$libsubdir"; mkdir "$htmldir" unless -d "$htmldir"; - -print "[krk] - $libdir - $htmldir"; - + # make list of module and script files in lib so we can extract pod doc later my %libfiles; opendir LIB, $libdir || die "can't open $libdir directory: $!"; @@ -211,9 +204,10 @@ print "[krk] - $libdir - $htmldir"; #print "package: $_\n"; s/\//::/g; + my $class = ($libsubdir eq ".") ? '' : $libsubdir . "::"; my $pod = "=item $_\n\n"; if ( $packages{$_}{haspod} ) { - $pod .= "L<$_|lib::" . $packages{$_}{noext} . "/$_>\n\n"; + $pod .= "L<$_|lib::" . $class . $packages{$_}{noext} . "/$_>\n\n"; } else { $pod .= "package $_ in $packages{$_}{pm} isn't documented yet\n\n"; @@ -225,9 +219,8 @@ print "[krk] - $libdir - $htmldir"; $mpod .= $pod; } } - } - -}##Stop loop here? + } +} if ($ipod) { print "writing $outdir/items.pod file\n"; From 5f9c7dc2806046397b7c78ca138abb35d7de3e2b Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 17:30:00 -0700 Subject: [PATCH 30/49] Update_Docs: Move Package Sorting Outside of Directory Loop This allows for sorting of the entire list, not just parts of it --- bin/update_docs | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/bin/update_docs b/bin/update_docs index 83c2a2df7..c5957c2ee 100755 --- a/bin/update_docs +++ b/bin/update_docs @@ -80,7 +80,9 @@ $outdir = '../docs' unless $outdir and -d $outdir; -w $outdir || die "directory $outdir isn't writeable"; mkdir "$outdir/lib" unless -d "$outdir/lib"; -my ( $ipod, $mpod ); +#Define variables used in creating module and item lists +my ($ipod, $mpod, %packages); +my $changes = 0; ## Get list of possible directories my %libsubdirs; @@ -117,7 +119,6 @@ foreach my $libsubdir ( keys %libsubdirs ) { closedir OUT; # convert the pod doc in each changed pl or pm file into html - my $changes = 0; foreach my $lib ( keys %libfiles ) { my $libfile = "$libdir/$lib"; my $htmlfile = "$htmldir/$lib"; @@ -160,7 +161,6 @@ foreach my $libsubdir ( keys %libsubdirs ) { # write out items and modules lists if any pm files changed if ($changes) { - my %packages; foreach my $pm ( keys %libfiles ) { next unless $pm =~ /.+\.pm$/i; my $html = $pm; @@ -184,6 +184,7 @@ foreach my $libsubdir ( keys %libsubdirs ) { $packages{$current_p}{pm} = $pm; $packages{$current_p}{html} = $html; $packages{$current_p}{noext} = $noext; + $packages{$current_p}{class} = ($libsubdir eq ".") ? '' : $libsubdir . "::"; } elsif ( $l =~ /^sub new / ) { @@ -199,29 +200,30 @@ foreach my $libsubdir ( keys %libsubdirs ) { print "didn't find any packages in $pm\n" unless $current_p; close $fh; } - - foreach ( sort keys %packages ) { - - #print "package: $_\n"; - s/\//::/g; - my $class = ($libsubdir eq ".") ? '' : $libsubdir . "::"; - my $pod = "=item $_\n\n"; - if ( $packages{$_}{haspod} ) { - $pod .= "L<$_|lib::" . $class . $packages{$_}{noext} . "/$_>\n\n"; - } - else { - $pod .= "package $_ in $packages{$_}{pm} isn't documented yet\n\n"; - } - if ( $packages{$_}{isitem} ) { - $ipod .= $pod; - } - else { - $mpod .= $pod; - } - } } } +#Sort Packages and Place into Module or Item List +if ($changes) { + foreach ( sort keys %packages ) { + s/\//::/g; + my $pod = "=item $_\n\n"; + if ( $packages{$_}{haspod} ) { + $pod .= "L<$_|lib::" . $packages{$_}{class} . $packages{$_}{noext} . "/$_>\n\n"; + } + else { + $pod .= "package $_ in $packages{$_}{pm} isn't documented yet\n\n"; + } + if ( $packages{$_}{isitem} ) { + $ipod .= $pod; + } + else { + $mpod .= $pod; + } + } +} + +#Create Item List POD if ($ipod) { print "writing $outdir/items.pod file\n"; open TAR, "> $outdir/items.pod"; @@ -229,6 +231,7 @@ if ($ipod) { close TAR; } +#Create Module List POD if ($mpod) { print "writing $outdir/modules.pod file\n"; open TAR, "> $outdir/modules.pod"; From 9eccb18280c91b2a0d98d439c5a55a1d7692f90b Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 17:30:00 -0700 Subject: [PATCH 31/49] Update_Docs: Fix Regex Error Used to Distinguish Items from Modules "sub new" should be followed by a whitespace character, but no necessarily a space --- bin/update_docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/update_docs b/bin/update_docs index c5957c2ee..98ad03e26 100755 --- a/bin/update_docs +++ b/bin/update_docs @@ -186,7 +186,7 @@ foreach my $libsubdir ( keys %libsubdirs ) { $packages{$current_p}{noext} = $noext; $packages{$current_p}{class} = ($libsubdir eq ".") ? '' : $libsubdir . "::"; } - elsif ( $l =~ /^sub new / ) { + elsif ( $l =~ /^sub new\s/ ) { #print "found 'new' method in package $current_p in $pm\n"; $packages{$current_p}{isitem} = 1 if $current_p; From 3305afd3f0694451c2cc5d8f50985e4ebfe6b538 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 17:35:00 -0700 Subject: [PATCH 32/49] Update_Docs: Disable code which deleted files in the distro dir; Cleanup internal comments Script previously would delete extra files in the /doc dir even when users had followed the suggested install procedure and used an alternative docs dir. The distribution directory structure should not be modified if users are installing things the way we suggest. --- bin/update_docs | 82 ++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/bin/update_docs b/bin/update_docs index 98ad03e26..d32375122 100755 --- a/bin/update_docs +++ b/bin/update_docs @@ -13,10 +13,10 @@ recommended that documentation be created along side the code it relates to. =over -=item html_alias_docs +=item html_alias2_docs This script will write its output to the directory specified in -C, otherwise it will write to C<../docs>. +C, otherwise it will write to C<../docs>. =back @@ -80,11 +80,11 @@ $outdir = '../docs' unless $outdir and -d $outdir; -w $outdir || die "directory $outdir isn't writeable"; mkdir "$outdir/lib" unless -d "$outdir/lib"; -#Define variables used in creating module and item lists +# Define variables used in creating module and item lists my ($ipod, $mpod, %packages); my $changes = 0; -## Get list of possible directories +# Generate the list of directories to scan for pm or pl files my %libsubdirs; opendir LIB, $libdir || die "can't open $libdir directory: $!"; foreach ( readdir LIB ) { @@ -100,22 +100,18 @@ foreach my $libsubdir ( keys %libsubdirs ) { # make list of module and script files in lib so we can extract pod doc later my %libfiles; - opendir LIB, $libdir || die "can't open $libdir directory: $!"; - + opendir LIB, $libdir || die "can't open $libdir directory: $!"; foreach ( readdir LIB ) { $libfiles{$_}{exists} = 1 if /\.p[lm]$/i; - } - + } closedir LIB; # make list of lib html files so we can delete obsolete ones my %htmlfiles; opendir OUT, $htmldir || die "can't open $htmldir directory: $!"; - foreach ( readdir OUT ) { $htmlfiles{$_}{exists} = 1 if /\.html$/i; - } - + } closedir OUT; # convert the pod doc in each changed pl or pm file into html @@ -128,7 +124,7 @@ foreach my $libsubdir ( keys %libsubdirs ) { my $mdate = ( stat($libfile) )[9]; my $hdate = ( stat($htmlfile) )[9]; - #print "mdate $mdate hdate $hdate $libfile\n"; + # If the HTML file older or doesn't exist make a new one if ( !-e $htmlfile or $mdate > $hdate ) { print "converting $libfile to $htmlfile\n"; $changes++; @@ -142,7 +138,7 @@ foreach my $libsubdir ( keys %libsubdirs ) { } } - # check for deleted lib files + # Delete HTML files if the pm or pl file has been deleted foreach ( keys %htmlfiles ) { my $htmlfile = "$htmldir/$_"; my $pm = $_; @@ -179,21 +175,15 @@ foreach my $libsubdir ( keys %libsubdirs ) { while ( my $l = <$fh> ) { if ( $l =~ /^package ([^;]+);/ ) { $current_p = $1; - - #print "found package $current_p in $pm\n"; $packages{$current_p}{pm} = $pm; $packages{$current_p}{html} = $html; $packages{$current_p}{noext} = $noext; $packages{$current_p}{class} = ($libsubdir eq ".") ? '' : $libsubdir . "::"; } elsif ( $l =~ /^sub new\s/ ) { - - #print "found 'new' method in package $current_p in $pm\n"; $packages{$current_p}{isitem} = 1 if $current_p; } elsif ( $l =~ /^=head/ ) { - - #print "found pod directive in package $current_p in $pm\n"; $packages{$current_p}{haspod} = 1 if $current_p; } } @@ -203,7 +193,7 @@ foreach my $libsubdir ( keys %libsubdirs ) { } } -#Sort Packages and Place into Module or Item List +# Sort Packages and Place into Module or Item List if ($changes) { foreach ( sort keys %packages ) { s/\//::/g; @@ -223,7 +213,7 @@ if ($changes) { } } -#Create Item List POD +# Create Item List POD if ($ipod) { print "writing $outdir/items.pod file\n"; open TAR, "> $outdir/items.pod"; @@ -231,7 +221,7 @@ if ($ipod) { close TAR; } -#Create Module List POD +# Create Module List POD if ($mpod) { print "writing $outdir/modules.pod file\n"; open TAR, "> $outdir/modules.pod"; @@ -239,43 +229,47 @@ if ($mpod) { close TAR; } -# make list of pod files so we can convert them to html +# make list of distributed pod files that need to be converted to html my %podfiles; opendir POD, $docdir || die "can't open $docdir directory: $!"; - foreach ( readdir POD ) { $podfiles{$_}{exists} = 1 if /\.pod$/i; } - $podfiles{'items.pod'}{exists} = 1 if -f "$outdir/items.pod"; $podfiles{'modules.pod'}{exists} = 1 if -f "$outdir/modules.pod"; closedir POD; -# delete html files from docs dir if out dir is diff and pod ex +# delete html files from docs dir if out dir is diff and pod exists my $docsi = ( stat($docdir) )[1]; my $outi = ( stat($outdir) )[1]; if ( $docsi eq $outi ) { - print "you should set the html_alias_docs directory to a place outside" - . " the mh distribution\n"; + print "you should set the html_alias2_docs directory to a place outside" + . " the mh distribution\n directory. Otherwise, everytime this script is" + . " run, you will alter\n your distribution files."; } else { - foreach ( keys %podfiles ) { - s/\.pod$/.html/i; - print("deleting $docdir/$_\n"), unlink "$docdir/$_" if -e "$docdir/$_"; - } -# foreach ( keys %libfiles ) { -# s/\.p[lm]$/.html/i; -# print("deleting $docdir/lib/$_\n"), unlink "$docdir/lib/$_" -# if -e "$docdir/lib/$_"; -# } - print("deleting $docdir/lib/\n"), rmdir "$docdir/lib" if -d "$docdir/lib"; - print("deleting $docdir/modules.pod\n"), unlink "$docdir/modules.pod" - if -w "$docdir/modules.pod"; - print("deleting $docdir/items.pod\n"), unlink "$docdir/items.pod" - if -w "$docdir/items.pod"; + # the following would delete files from the distribution docs dir + # When MisterHouse is installed in the recommended fashion, this deletes a + # number of files from the distribution directory structure. I am disabling + # for the moment, as I don't think we should be altering the distribution + # directory structure + #foreach ( keys %podfiles ) { + # s/\.pod$/.html/i; + # print("deleting $docdir/$_\n"), unlink "$docdir/$_" if -e "$docdir/$_"; + #} + #foreach ( keys %libfiles ) { + # s/\.p[lm]$/.html/i; + # print("deleting $docdir/lib/$_\n"), unlink "$docdir/lib/$_" + # if -e "$docdir/lib/$_"; + #} + #print("deleting $docdir/lib/\n"), rmdir "$docdir/lib" if -d "$docdir/lib"; + #print("deleting $docdir/modules.pod\n"), unlink "$docdir/modules.pod" + # if -w "$docdir/modules.pod"; + #print("deleting $docdir/items.pod\n"), unlink "$docdir/items.pod" + # if -w "$docdir/items.pod"; } -# convert any modified pod files to html +# convert any modified distributed pod files to html foreach my $doc ( keys %podfiles ) { my $podfile = "$docdir/$doc"; my $ind = ""; @@ -290,11 +284,9 @@ foreach my $doc ( keys %podfiles ) { $pdate = ( stat($podfile) )[9] if -f $podfile; $hdate = ( stat($htmlfile) )[9] if -f $htmlfile; - #print "pdate $pdate hdate $hdate : $doc\n"; if ( !-e "$outdir/$doc.html" or $pdate > $hdate ) { print "pod2html $podfile > $htmlfile\n"; - #`pod2html --htmlroot $outdir $docdir/$doc.pod > $outdir/$doc.html`; pod2html( "--infile=$podfile", "--outfile=$htmlfile", "--noheader", From 7c4482a57a48589abb19e7be84e7123344cead03 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 17:55:00 -0700 Subject: [PATCH 33/49] Insteon: Add Documentation to AllLinkDatabase File --- lib/Insteon/AllLinkDatabase.pm | 428 +++++++++++++++++++++++++++++++-- 1 file changed, 411 insertions(+), 17 deletions(-) diff --git a/lib/Insteon/AllLinkDatabase.pm b/lib/Insteon/AllLinkDatabase.pm index 52cdea2c0..2600b5157 100644 --- a/lib/Insteon/AllLinkDatabase.pm +++ b/lib/Insteon/AllLinkDatabase.pm @@ -1,27 +1,34 @@ -=begin comment -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +package Insteon::AllLinkDatabase; -File: - AllLinkDatabase.pm +=head1 B -Description: - Generic class implementation of an insteon device's all link database. +=head2 SYNOPSIS -Author(s): - Gregg Liming / gregg@limings.net +Base class used for storing AllLink Database structures within MisterHouse. -License: - This free software is licensed under the terms of the GNU public license. +=head2 DESCRIPTION +Generally this object should be interacted with through the insteon objects and +not by directly calling any of the following methods. -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -=cut +=head2 INHERITS +None -package Insteon::AllLinkDatabase; +=head2 METHODS + +=over + +=cut use strict; +=item C + +Instantiate a new object. + +=cut + sub new { my ($class, $device) = @_; @@ -39,6 +46,16 @@ sub _send_cmd $$self{device}->_send_cmd($msg); } +=item C + +Used to track the ALDB version type. + +If provided, saves version to memory. + +Returns the saved version type. + +=cut + sub aldb_version { my ($self, $aldb_version) = @_; @@ -46,17 +63,33 @@ sub aldb_version return $$self{aldb_version}; } +=item C + +Used to track the health of MisterHouse's copy of a device's ALDB. + +If provided, saves status to memory. + +Returns the saved health status. + +=cut + sub health { - # out-of-sync - # unknown - # empty - # good my ($self, $health) = @_; $$self{health} = $health if defined $health; return $$self{health}; } +=item C + +Used to track the time, in unix time seconds, of the last ALDB scan. + +If provided, saves the time to memory. + +Returns the time of the last ALDB scan. + +=cut + sub scandatetime { my ($self, $scandatetime) = @_; @@ -64,6 +97,19 @@ sub scandatetime return $$self{scandatetime}; } +=item C + +Used to track the ALDB Delta. The ALDB Delta starts at 00 and iterates ++1 for each change to a device's ALDB. The ALDB Delta will be reset to 00 +whenever power is lost to the device or if the device is factory reset. + +If provided, saves the hex value to memory. (This should likely only be done by +C) + +Returns the current ALDB Delta. + +=cut + sub aldb_delta { my ($self, $p_aldb_delta) = @_; @@ -71,6 +117,21 @@ sub aldb_delta return $$self{aldb_delta}; } +=item C + +Interacts with the device's ALDB Delta. + +If called with "check", MisterHouse will query the device to obtain the current +ALDB Delta. If the ALDB Delta matches the version stored in C +MisterHouse will eval the code stored in C<$self->{_aldb_unchanged_callback}>. +If the ALDB Delta does not match, MisterHouse will eval the code stored in +C<$self->{_aldb_changed_callback}>. + +If called with "set" will cause MisterHouse to query the device for its ALDB +Delta and will store it with C. + +=cut + sub query_aldb_delta { my ($self, $action) = @_; @@ -107,6 +168,12 @@ sub query_aldb_delta } } +=item C + +This is called by mh on exit to save the cached ALDB of a device to persistant data. + +=cut + sub restore_string { my ($self) = @_; @@ -158,6 +225,12 @@ sub restore_string return $restore_string; } +=item C + +Used to reload MisterHouse's cached version of a device's ALDB on restart. + +=cut + sub restore_aldb { my ($self,$aldb) = @_; @@ -203,6 +276,12 @@ sub restore_aldb } } +=item C + +Scans a device's link table and caches a copy. + +=cut + sub scan_link_table { my ($self,$success_callback,$failure_callback) = @_; @@ -218,6 +297,12 @@ sub scan_link_table } } +=item C + +Deletes a specific link from a device. Generally called by C. + +=cut + sub delete_link { my ($self, $parms_text) = @_; @@ -316,6 +401,14 @@ sub delete_link } } +=item C + +Reviews the cached version of all of the ALDBs and based on this review removes +links from this device which are not present in the mht file, not defined in the +code, or links which are only half-links.. + +=cut + sub delete_orphan_links { my ($self, $audit_mode) = @_; @@ -768,6 +861,12 @@ sub _process_delete_queue { } } +=item C + +Adds address to the duplicate link hash. Called as part of C. + +=cut + sub add_duplicate_link_address { my ($self, $address) = @_; @@ -779,6 +878,12 @@ sub add_duplicate_link_address } +=item C + +Removes address from the duplicate link hash. Called as part of C. + +=cut + sub delete_duplicate_link_address { my ($self, $address) = @_; @@ -800,6 +905,13 @@ sub delete_duplicate_link_address } } +=item C + +Adds address to the empty link hash. Called as part of C +or C. + +=cut + sub add_empty_address { my ($self, $address) = @_; @@ -829,6 +941,14 @@ sub add_empty_address } +=item C + +Returns the highest empty link address, or if no empty addresses exist, returns +the highest unused address. Called as part of C or +C.. + +=cut + sub get_first_empty_address { my ($self) = @_; @@ -866,6 +986,13 @@ sub get_first_empty_address return $first_address; } +=item C + +Adds the link to the device's ALDB. Generally called from the "sync links" or +"link to interface" voice commands. + +=cut + sub add_link { my ($self, $parms_text) = @_; @@ -992,6 +1119,13 @@ sub add_link } } +=item C + +Updates the on_level and/or ramp_rate associated with a link to match the defined +value in MisterHouse. Generally called from the "sync links" voice command. + +=cut + sub update_link { my ($self, %link_parms) = @_; @@ -1063,6 +1197,14 @@ sub update_link } } +=item C + +Prints a human readable form of MisterHouse's cached version of a device's ALDB +to the print log. Called as part of the "scan links" voice command +or in response to the "log links" voice command. + +=cut + sub log_alllink_table { my ($self) = @_; @@ -1191,6 +1333,13 @@ sub log_alllink_table } } +=item C + +Checks and returns true if a link with the passed details exists on the device +or false if it does not. Generally called as part of C. + +=cut + sub has_link { my ($self, $insteon_object, $group, $is_controller, $subaddress) = @_; @@ -1212,12 +1361,57 @@ sub has_link return (defined $$self{aldb}{$key}); } +=back + +=head2 INI PARAMETERS + +None + +=head2 AUTHOR + +=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 + package Insteon::ALDB_i1; +=head1 B + +=head2 SYNOPSIS + +Unique class for storing a cahced copy of a verion i1 device's ALDB. + +=head2 DESCRIPTION + +Generally this object should be interacted with through the insteon objects and +not by directly calling any of the following methods. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + use strict; @Insteon::ALDB_i1::ISA = ('Insteon::AllLinkDatabase'); +=item C + +Instantiate a new object. + +=cut + sub new { my ($class,$device) = @_; @@ -1717,6 +1911,12 @@ sub _on_peek } } +=item C + +Used to update the local on level and ramp rate of a device. Called by +C. + +=cut sub update_local_properties { @@ -1731,6 +1931,12 @@ sub update_local_properties } } +=item C + +Used to update the flags of a device. Called by C. + +=cut + sub update_flags { my ($self, $flags, $aldb_check) = @_; @@ -1746,6 +1952,14 @@ sub update_flags } } +=item C + +Gets and returns the details of a link. Called by C. + +NOTE - This routine may be obsolete, its parent routine is not called by any code. + +=cut + sub get_link_record { my ($self,$link_key) = @_; @@ -1823,14 +2037,57 @@ sub _peek } } +=back + +=head2 INI PARAMETERS + +None +=head2 AUTHOR + +=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 package Insteon::ALDB_i2; +=head1 B + +=head2 SYNOPSIS + +Unique class for storing a cahced copy of a verion i2 device's ALDB. + +=head2 DESCRIPTION + +Generally this object should be interacted with through the insteon objects and +not by directly calling any of the following methods. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + use strict; @Insteon::ALDB_i2::ISA = ('Insteon::AllLinkDatabase'); +=item C + +Instantiate a new object. + +=cut + sub new { my ($class,$device) = @_; @@ -1841,6 +2098,11 @@ sub new return $self; } +=item C + +Called as part of any process to read or write to a device's ALDB. + +=cut sub on_read_write_aldb { @@ -2199,6 +2461,12 @@ sub _write_delete } } +=item C + +Called as part of "scan link table" voice command. + +=cut + sub send_read_aldb { my ($self, $address) = @_; @@ -2214,13 +2482,57 @@ sub send_read_aldb $self->_send_cmd($message); } +=back + +=head2 INI PARAMETERS + +None + +=head2 AUTHOR + +=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 package Insteon::ALDB_PLM; +=head1 B + +=head2 SYNOPSIS + +Unique class for storing a cahced copy of a the PLM's link database. + +=head2 DESCRIPTION + +Generally this object should be interacted with through the insteon objects and +not by directly calling any of the following methods. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + use strict; @Insteon::ALDB_PLM::ISA = ('Insteon::AllLinkDatabase'); +=item C + +Instantiate a new object. + +=cut + sub new { my ($class,$device) = @_; @@ -2230,6 +2542,12 @@ sub new return $self; } +=item C + +This is called by mh on exit to save the cached ALDB of a device to persistant data. + +=cut + sub restore_string { my ($self) = @_; @@ -2262,6 +2580,12 @@ sub restore_string return $restore_string; } +=item C + +Used to reload MisterHouse's cached version of a device's ALDB on restart. + +=cut + sub restore_linktable { my ($self, $links) = @_; @@ -2288,6 +2612,14 @@ sub restore_linktable } } +=item C + +Prints a human readable form of MisterHouse's cached version of a device's ALDB +to the print log. Called as part of the "scan links" voice command +or in response to the "log links" voice command. + +=cut + sub log_alllink_table { my ($self) = @_; @@ -2319,6 +2651,12 @@ sub log_alllink_table } } +=item C + +Parses the alllink message sent from the PLM. + +=cut + sub parse_alllink { my ($self, $data) = @_; @@ -2338,6 +2676,12 @@ sub parse_alllink } } +=item C + +Sends the request for the first alllink entry on the PLM. + +=cut + sub get_first_alllink { my ($self) = @_; @@ -2346,12 +2690,26 @@ sub get_first_alllink $$self{device}->queue_message(new Insteon::InsteonMessage('all_link_first_rec', $$self{device})); } +=item C + +Sends the request for the next alllink entry on the PLM. + +=cut + sub get_next_alllink { my ($self) = @_; $$self{device}->queue_message(new Insteon::InsteonMessage('all_link_next_rec', $$self{device})); } +=item C + +Reviews the cached version of all of the ALDBs and based on this review removes +links from this device which are not present in the mht file, not defined in the +code, or links which are only half-links.. + +=cut + sub delete_orphan_links { my ($self, $audit_mode) = @_; @@ -2548,6 +2906,12 @@ sub _process_delete_queue { } +=item C + +Deletes a specific link from a device. Generally called by C. + +=cut + sub delete_link { # linkkey is concat of: deviceid, group, is_controller @@ -2602,6 +2966,13 @@ sub delete_link return $num_deleted; } +=item C + +Adds the link to the device's ALDB. Generally called from the "sync links" or +"link to interface" voice commands. + +=cut + sub add_link { my ($self, $parms_text) = @_; @@ -2681,6 +3052,13 @@ sub add_link } } +=item C + +Checks and returns true if a link with the passed details exists on the device +or false if it does not. Generally called as part of C. + +=cut + sub has_link { my ($self, $insteon_object, $group, $is_controller, $subaddress) = @_; @@ -2689,7 +3067,23 @@ sub has_link return (defined $$self{aldb}{$key}) ? 1 : 0; } +=back + +=head2 INI PARAMETERS +None + +=head2 AUTHOR + +=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; From d14d893c3f1d4cce116e8057bc1d239c3e282980 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 18:07:00 -0700 Subject: [PATCH 34/49] Insteon: Add Documentation to BaseInsteon.pm; Fix a few things in AllLinkDatabase.pm --- lib/Insteon/AllLinkDatabase.pm | 10 +- lib/Insteon/BaseInsteon.pm | 780 +++++++++++++++++++++++++++++++-- 2 files changed, 753 insertions(+), 37 deletions(-) diff --git a/lib/Insteon/AllLinkDatabase.pm b/lib/Insteon/AllLinkDatabase.pm index 2600b5157..1abea6289 100644 --- a/lib/Insteon/AllLinkDatabase.pm +++ b/lib/Insteon/AllLinkDatabase.pm @@ -4,7 +4,7 @@ package Insteon::AllLinkDatabase; =head2 SYNOPSIS -Base class used for storing AllLink Database structures within MisterHouse. +Generic class implementation of an insteon device's all link database. =head2 DESCRIPTION @@ -1369,6 +1369,8 @@ None =head2 AUTHOR +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + =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. @@ -2045,6 +2047,8 @@ None =head2 AUTHOR +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + =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. @@ -2490,6 +2494,8 @@ None =head2 AUTHOR +Michael Stovenour + =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. @@ -3075,6 +3081,8 @@ None =head2 AUTHOR +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + =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. diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index f2680b43c..f00415695 100644 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -1,29 +1,26 @@ -=begin comment -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +=head1 B -File: - BaseInsteon.pm +=head2 SYNOPSIS -Description: - Generic class implementation of an Insteon Device. +Usage -Author(s): - Gregg Liming / gregg@limings.net +In user code: -License: - This free software is licensed under the terms of the GNU public license. + $ip_patio_light = new Insteon_Device($myPLM,"33.44.55"); + $ip_patio_light->set("ON"); -Usage: +=head2 DESCRIPTION - $ip_patio_light = new Insteon_Device($myPLM,"33.44.55"); +Generic class implementation of an Insteon Device. - $ip_patio_light->set("ON"); +=head2 INHERITS -Special Thanks to: - Brian Warren for significant testing and patches - Bruce Winter - MH +B + +=head2 METHODS + +=over -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ =cut package Insteon::BaseObject; @@ -46,6 +43,13 @@ our %nack_messages = ( ff => 'sender_id_not_in_responder_aldb', ); +=item C + +Takes the various states available to insteon devices and returns a derived +state of either ON or OFF. + +=cut + sub derive_link_state { my ($p_state) = @_; @@ -64,6 +68,12 @@ sub derive_link_state return $link_state; } +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -107,6 +117,13 @@ sub new return $self; } +=item C + +A former holdover from when MisterHouse used to ping devices to get their device +category. May not be needed anymore. + +=cut + sub initialize { my ($self) = @_; @@ -121,6 +138,14 @@ sub initialize # unless $self->group eq '01' and defined $self->devcat; } +=item C + +Used to store and return the associated interface of a device. + +If provided, stores interface as the device's interface. + +=cut + sub interface { my ($self,$p_interface) = @_; @@ -134,6 +159,16 @@ sub interface return $$self{interface}; } +=item C + +Used to store and return the associated device_id of a device. + +If provided, stores id as the device's id. + +Returns device id without any delimiters. + +=cut + sub device_id { my ($self,$p_device_id) = @_; @@ -146,6 +181,14 @@ sub device_id return $$self{device_id}; } +=item C + +Used to store and return the associated group of a device. + +If provided, stores group as the device's group. + +=cut + sub group { my ($self, $p_group) = @_; @@ -153,6 +196,20 @@ sub group return $$self{m_group}; } +=item C + +Used to track the number of hops needed to reach a device. Will store the past +20 hop counts for the device. Hop counts are added based on the number of hops +needed for an incomming message to arrive. Additionally, any time a message is +resent, a hop count equal to the prior default_hop_count + 1 is added. + +If provided, stores hop as a new hop count for the device. If more than 20 hop +counts have been stored, will drop the oldest hop count until only 20 exist. + +Returns the highest hop count of the past 20 hop counts + +=cut + sub default_hop_count { my ($self, $hop_count) = @_; @@ -171,6 +228,14 @@ sub default_hop_count return $$self{default_hop_count}; } +=item C + +Used to store and return the associated engine version of a device. + +If provided, stores the engine version of the device. + +=cut + sub engine_version { my ($self, $p_engine_version) = @_; @@ -178,6 +243,12 @@ sub engine_version return $$self{engine_version}; } +=item C + +Returns 1 if object is the same as $self, otherwise returns 0. + +=cut + sub equals { my ($self, $compare_object) = @_; @@ -192,6 +263,14 @@ sub equals return 0; } +=item C + +Used to set the device's state. If called by device or a device linked to device, +calls C. If called by something +else, will send the command to the device. + +=cut + sub set { my ($self,$p_state,$p_setby,$p_response) = @_; @@ -263,6 +342,12 @@ sub set } } +=item C + +If ack is true, calls C. If ack is false, clears awaiting_ack flag. + +=cut + sub is_acknowledged { my ($self, $p_ack) = @_; @@ -286,6 +371,16 @@ sub is_acknowledged return $$self{is_acknowledged}; } +=item C + +Updates the device's state in MisterHouse. Triggers state_now, state_changed, and +state_final variables to update accordingly. Which causes tie_events to occur. + +If state was set to the same state within the last 1 second, then this is ignored. +This prevents the accidental calling of state_now if duplicate messages are received. + +=cut + sub set_receive { my ($self, $p_state, $p_setby, $p_response) = @_; @@ -302,6 +397,16 @@ sub set_receive } } +=item C + +NOTE - This routine appears to be nearly identical, if not identical to the +C routine, it is not clear why this routine is +needed here. + +See full description of this routine in C + +=cut + sub set_with_timer { my ($self, $state, $time, $return_state, $additional_return_states) = @_; return if &main::check_for_tied_filters($self, $state); @@ -346,6 +451,12 @@ sub _send_cmd $self->_process_command_stack(); } +=item C + +Generates and returns a basic on/off message from a command. + +=cut + sub derive_message { my ($self, $p_command, $p_extra) = @_; @@ -427,18 +538,39 @@ sub derive_message return $message; } +=item C + +Takes msg, a text based msg type, and returns the corresponding text version of +the hexadecimal message type. + +=cut + sub message_type_code { my ($self, $msg) = @_; return $$self{message_types}->{$msg}; } +=item C + +Takes msg, a text based msg type, and returns the corresponding message type as +a hex. + +=cut + sub message_type_hex { my ($self, $msg) = @_; return unpack( 'H*', pack( 'c', $self->message_type_code($msg))); } +=item C + +Takes cmd, text based hexadecimal code, and returns the text based description +of the message code. + +=cut + sub message_type { my ($self, $cmd1) = @_; @@ -838,7 +970,13 @@ sub _is_valid_state } } -# Provide human readable nack message. +=item C + +Takes msg, text based hexadecimal code, and returns the text based description +of the NACK code. + +=cut + sub get_nack_msg_for { my ($self,$msg) = @_; return $nack_messages{ $msg }; @@ -864,14 +1002,59 @@ sub failure_reason return $$self{failure_reason}; } +=back + +=head2 INI PARAMETERS + +Insteon_PLM_max_queue_time - Was previously used to set the maximum amount of time +a message could remain in the queue. This parameter is no longer used in the code +but it still appears in the initialization. It may be removed at a future date. + +=head2 AUTHOR + +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + +=head2 NOTES + +Special thanks to: + Brian Warren for significant testing and patches + Bruce Winter - MH + +=head2 SEE ALSO + +=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 + #################################### ### ##################### -### BaseObject ##################### +### BaseDevice ##################### ### ##################### #################################### -package Insteon::BaseDevice; +=head1 B +=head2 DESCRIPTION + +Generic class implementation of a Base Insteon Device. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + +package Insteon::BaseDevice; @Insteon::BaseDevice::ISA = ('Insteon::BaseObject'); @@ -927,6 +1110,11 @@ my %operating_flags = ( 'one_minute_warn_enabled' => '0b' ); +=item C + +Instantiates a new object. + +=cut sub new { @@ -959,6 +1147,13 @@ sub new return $self; } +=item C + +A former holdover from when MisterHouse used to ping devices to get their device +category. May not be needed anymore. + +=cut + sub initialize { my ($self) = @_; @@ -971,6 +1166,14 @@ sub initialize $$self{ping_timerTime} = 300; } +=item C + +Used to store and return the associated ramp rate of a device. + +If provided, stores rate as the device's ramp rate in MisterHouse. + +=cut + sub rate { my ($self,$p_rate) = @_; @@ -978,6 +1181,13 @@ sub rate return $$self{rate}; } +=item C + +Updates the device's level if it can level, then calls +C. + +=cut + sub set_receive { my ($self, $p_state, $p_setby, $p_response) = @_; @@ -985,12 +1195,24 @@ sub set_receive $self->SUPER::set_receive($p_state, $p_setby, $p_response); } +=item C + +Returns true if the device is a controller. + +=cut + sub is_controller { my ($self) = @_; return $$self{is_controller}; } +=item C + +Stores and returns whether a device is a responder. + +=cut + sub is_responder { my ($self,$is_responder) = @_; @@ -1012,6 +1234,22 @@ sub is_responder } } +=item C + +If a controller link from the device to the interface does not exist, this will +create that link on the device. + +Next, if a responder link from the device to the interface does not exist on the +interface, this will create that link on the interface. + +The group is the group on the device that is the controller, such as a button on +a keypad link. It will default to 01. + +Data3 is optional and is used to set the Data3 value in the controller link on +the device. + +=cut + sub link_to_interface { my ($self,$p_group, $p_data3) = @_; @@ -1035,6 +1273,18 @@ sub link_to_interface } } +=item C + +Will delete the contoller link from the device to the interface if such a link exists. + +Next, will delete the responder link from the device to the interface on the +interface, if such a link exists. + +The group is the group on the device that is the controller, such as a button on +a keypad link. It will default to 01. + +=cut + sub unlink_to_interface { my ($self,$p_group) = @_; @@ -1088,6 +1338,11 @@ sub _aldb return $$root_obj{aldb}; } +=item C + +Sets the defined flag on the device. + +=cut sub set_operating_flag { my ($self, $flag) = @_; @@ -1118,6 +1373,12 @@ sub set_operating_flag { } } +=item C + +Requests the device's operating flag and prints it to the log. + +=cut + sub get_operating_flag { my ($self) = @_; @@ -1135,6 +1396,13 @@ sub get_operating_flag { } } +=item C + +Appears to set and or return the "writable" state. Does not appear to be used +in the Insteon code, but may be necessary for supporting other classes? + +=cut + sub writable { my ($self, $p_write) = @_; if (defined $p_write) @@ -1151,17 +1419,36 @@ sub writable { return $$self{m_write}; } +=item C + +Returns the is_locally_set variable. Doesn't appear to be used in Insteon code. +Likely was used to test whether setby was equal to the device itself. May not +always be properly updated since it appears unused. + +=cut + sub is_locally_set { my ($self) = @_; return $$self{m_is_locally_set}; } +=item C + +Returns true if the object is the base object, generally group 01, on the device. + +=cut sub is_root { my ($self) = @_; return (($self->group eq '01') and !($self->isa('Insteon::InterfaceController'))) ? 1 : 0; } +=item C + +Returns the root object of a device. + +=cut + sub get_root { my ($self) = @_; if ($self->is_root) @@ -1179,6 +1466,13 @@ sub get_root { } } +=item C + +If a device has an ALDB, passes link_details onto one of the has_link() routines +within C. Generally called as part of C. + +=cut + sub has_link { my ($self, $insteon_object, $group, $is_controller, $subaddress) = @_; @@ -1194,6 +1488,14 @@ sub has_link } +=item C + +If a device has an ALDB, passes link_details onto one of the add_link() routines +within C. Generally called from the "sync links" or +"link to interface" voice commands. + +=cut + sub add_link { my ($self, $parms_text) = @_; @@ -1215,6 +1517,14 @@ sub add_link } +=item C + +If a device has an ALDB, passes link_details onto one of the update_link() routines +within C. Generally called from the "sync links" +voice command. + +=cut + sub update_link { my ($self, $parms_text) = @_; @@ -1235,6 +1545,13 @@ sub update_link } } +=item C + +If a device has an ALDB, passes link_details onto one of the delete_link() routines +within C. Generally called by C. + +=cut + sub delete_link { my ($self, $parms_text) = @_; @@ -1255,6 +1572,12 @@ sub delete_link } } +=item C + +Scans a device's link table and caches a copy. + +=cut + sub scan_link_table { my ($self, $success_callback, $failure_callback) = @_; @@ -1266,6 +1589,15 @@ sub scan_link_table } +=item C + +Prints a human readable description of various settings and attributes associated +with a device including: + +Hop Count, Engine Version, ALDB Type, ALDB Health, and Last ALDB Scan Time + +=cut + sub log_aldb_status { my ($self) = @_; @@ -1280,7 +1612,16 @@ sub log_aldb_status } } -### WARN: Testing using the following does not produce results as expected. Use at your own risk. [GL] +=item C + +In theory, would have the same effect as manually tapping the set button on the +device repeat times. + +WARN: Testing using the following does not produce results as expected. Use at +your own risk. [GL] + +=cut + sub remote_set_button_tap { my ($self,$p_number_taps) = @_; @@ -1291,6 +1632,13 @@ sub remote_set_button_tap # $self->_send_cmd('command' => 'remote_set_button_tap', 'extra' => $taps); } +=item C + +Requests the current status of the device and calls C on the response. +This will trigger tied_events. + +=cut + sub request_status { my ($self, $requestor) = @_; @@ -1347,6 +1695,12 @@ sub _get_engine_version_failure } } +=item C + +Sends a ping command to the device. + +=cut + sub ping { my ($self) = @_; @@ -1355,6 +1709,12 @@ sub ping # $self->_send_cmd('command' => 'ping'); } +=item C + +Used to set the led staatus of SwitchLinc companion leds. + +=cut + sub set_led_status { my ($self, $status_mask) = @_; @@ -1364,6 +1724,12 @@ sub set_led_status # $self->_send_cmd('command' => 'set_led_status', 'extra' => $status_mask); } +=item C + +This is called by mh on exit to save the cached ALDB of a device to persistant data. + +=cut + sub restore_string { my ($self) = @_; @@ -1386,6 +1752,12 @@ sub restore_string return $restore_string; } +=item C + +Used to reload the persistent states of variables on restart. + +=cut + sub restore_states { my ($self, $states) = @_; @@ -1395,6 +1767,12 @@ sub restore_states } } +=item C + +Used to reload the aldb of a device on restart. + +=cut + sub restore_aldb { my ($self,$aldb) = @_; @@ -1404,6 +1782,12 @@ sub restore_aldb } } +=item C + +NOT USED - Sets and returns the device category of a device. No longer used. + +=cut + sub devcat { my ($self, $devcat) = @_; @@ -1418,6 +1802,12 @@ sub devcat return $$self{devcat}; } +=item C + +Sets and returns the available states for a device. + +=cut + sub states { my ($self, $states) = @_; @@ -1434,6 +1824,12 @@ sub states } +=item C + +Sets and returns the local onlevel for the device in MH only. Level is a +percentage from 0%-100% + +=cut sub local_onlevel { @@ -1446,6 +1842,14 @@ sub local_onlevel return $$self{_onlevel}; } +=item C + +Sets and returns the local ramp rate for the device in MH only. Rate is a time +between .1 and 540 seconds. Only 32 rate steps exist, to MH will pick a time +equal to of the closest below this time. + +=cut + sub local_ramprate { my ($self, $p_ramprate) = @_; @@ -1456,6 +1860,17 @@ sub local_ramprate } +=item C + +Reviews the cached version of all of the ALDBs and based on this review removes +links from this device which are not present in the mht file, not defined in the +code, or links which are only half-links. + +If audit_mode is true, prints the actions that would be taken to the log, but +does nothing. + +=cut + sub delete_orphan_links { my ($self, $audit_mode) = @_; @@ -1467,12 +1882,28 @@ sub _process_delete_queue { $self->_aldb->_process_delete_queue() if $self->_aldb; } +=item C + +Prints a human readable form of MisterHouse's cached version of a device's ALDB +to the print log. Called as part of the "scan links" voice command +or in response to the "log links" voice command. + +=cut + sub log_alllink_table { my ($self) = @_; $self->_aldb->log_alllink_table if $self->_aldb; } +=item C + +Pushes the values set in C and C to the device. +The device will only reread these values when it is power-cycled. This can be +done by pulling the air-gap for 4 seconds or unplugging the device. + +=cut + sub update_local_properties { my ($self) = @_; @@ -1486,6 +1917,23 @@ sub update_local_properties } } +=item C + +Can be used to set the button layout and light level on a keypadlinc. Flag +options include: + + '0a' - 8 button; backlighting dim + '06' - 8 button; backlighting off + '02' - 8 button; backlighting normal + + '08' - 6 button; backlighting dim + '04' - 6 button; backlighting off + '00' - 6 button; backlighting normal + +Note: This routine will likely be moved to C at some point. + +=cut + sub update_flags { my ($self, $flags) = @_; @@ -1519,24 +1967,28 @@ sub engine_version return $engine_version; } -sub check_aldb_version -{ - #Because of the way MH saves / restores states "after" object creation - #the aldb must be initially created before the engine_version is restored. - #It is therefore impossible to know the device is i2 before creating - #the aldb object. The solution is to keep the existing logic which assumes - #the device is peek/poke capable (i1 or i2) and then delete/recreate the - #aldb object if it is later determined to be an i2 device. +=item C + +Because of the way MH saves / restores states "after" object creation +the aldb must be initially created before the engine_version is restored. +It is therefore impossible to know the device is i2 before creating +the aldb object. The solution is to keep the existing logic which assumes +the device is peek/poke capable (i1 or i2) and then delete/recreate the +aldb object if it is later determined to be an i2 device. + +There is a use case where a device is initially I2 but the user replaces +the device with an I1 device, reusing the same object name. In this case +the object state restore will build an I2 aldb object. The user must +manually initiate the 'get engine version' voice command or stop/start +MH so the initial poll will detect the change. - #There is a use case where a device is initially I2 but the user replaces - #the device with an I1 device, reusing the same object name. In this case - #the object state restore will build an I2 aldb object. The user must - #manually initiate the 'get engine version' voice command or stop/start - #MH so the initial poll will detect the change. +This is called anytime the engine_version is queried (initial startup poll) and +in the Reload_post_hooks once object_states_restore completes - #This is called anytime the engine_version is queried (initial startup poll) and - #in the Reload_post_hooks once object_states_restore completes +=cut +sub check_aldb_version +{ my ($self) = @_; my $engine_version = $self->SUPER::engine_version(); @@ -1572,6 +2024,21 @@ sub check_aldb_version } } +=back + +=head2 AUTHOR + +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + +=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 #################################### ### ################# @@ -1579,12 +2046,34 @@ sub check_aldb_version ### ################# #################################### +=head1 B + +=head2 DESCRIPTION + +Generic class implementation of an Insteon Controller. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + package Insteon::BaseController; use strict; @Insteon::BaseController::ISA = ('Generic_Item'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface,$p_devcat) = @_; @@ -1597,6 +2086,13 @@ sub new return $self; } +=item C + +Adds object as a responder to the device. If on_level and ramp_rate are specified +they will be used, otherwise 100% .1s will be used. + +=cut + sub add { my ($self, $obj, $on_level, $ramp_rate) = @_; @@ -1632,6 +2128,17 @@ sub add } } +=item C + +Causes MisterHouse to review the list of objects that should be linked to device +and to check to make sure these links are complete. If any link is not complete +MisterHouse will add the link. + +If audit_mode is true, MisterHouse will print the actions it would have taken to +the log, but will not take any actions. + +=cut + sub sync_links { my ($self, $audit_mode, $callback, $failure_callback) = @_; @@ -1895,6 +2402,16 @@ sub _process_sync_queue { } } +=item C + +Returns -1 if setby was set by this object. + +Returns -1 if setby a tied_filter. + +Otherwise calls C and returns 0. + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -1913,6 +2430,14 @@ sub set return 0; } +=item C + +Checks each linked member of device. If the linked member is a C, +then sets that item to state. If the linked member is a C +then call C for the member. + +=cut + sub set_linked_devices { my ($self, $link_state) = @_; @@ -1970,6 +2495,16 @@ sub set_linked_devices } +=item C + +NOTE - This routine appears to be nearly identical, if not identical to the +C routine, it is not clear why this routine is +needed here. + +See full description of this routine in C + +=cut + sub set_with_timer { my ($self, $state, $time, $return_state, $additional_return_states) = @_; return if &main::check_for_tied_filters($self, $state); @@ -1990,6 +2525,12 @@ sub set_with_timer { $$self{set_timer}->set($time, $action); } +=item C + +This appears to be a depricated routine that is no longer used. At a cursory +glance, it may throw an error if called. + +=cut sub update_members { @@ -2023,6 +2564,14 @@ sub update_members } } +=item C + +Places the interface in linking mode as the controller. To complete the process +press the set button on the responder device until it beeps. Alternatively, +you may be able to complete the process with +C. + +=cut sub initiate_linking_as_controller { @@ -2041,6 +2590,12 @@ sub initiate_linking_as_controller $self->interface()->initiate_linking_as_controller($p_group); } +=item C + +Generates and returns a basic on/off message from a command. + +=cut + sub derive_message { my ($self, $p_state, $p_extra) = @_; @@ -2051,6 +2606,15 @@ sub derive_message } } +=item C + +Returns a list of objects that are members of device. If type is specified, only +members of that type are returned. Type is a package name, for example: + + $member->find_members('Insteon::BaseDevice'); + +=cut + sub find_members { my ($self,$p_type) = @_; @@ -2071,6 +2635,12 @@ sub find_members } +=item C + +Returns true if object is a member of device, else returns false. + +=cut + sub has_member { my ($self, $compare_object) = @_; @@ -2085,12 +2655,43 @@ sub has_member return 0; } +=back + +=head2 AUTHOR + +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + +=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 + #################################### ### ##################### ### DeviceController ############### ### ############### #################################### +=head1 B + +=head2 DESCRIPTION + +Generic class implementation of an Device Controller. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut package Insteon::DeviceController; @@ -2098,6 +2699,12 @@ use strict; @Insteon::DeviceController::ISA = ('Insteon::BaseController'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface,$p_devcat) = @_; @@ -2108,6 +2715,14 @@ sub new return $self; } +=item C + +If C returns a true value returns that. + +Else, calls C and returns 0 + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -2122,6 +2737,12 @@ sub set return 0; } +=item C + +Requests the current status of the device and calls C on the response. +This will trigger tied_events. + +=cut sub request_status { @@ -2148,6 +2769,22 @@ sub request_status } } +=item C + +If a controller link from the device to the interface does not exist, this will +create that link on the device. + +Next, if a responder link from the device to the interface does not exist on the +interface, this will create that link on the interface. + +The group is the group on the device that is the controller, such as a button on +a keypad link. It will default to 01. + +Data3 is optional and is used to set the Data3 value in the controller link on +the device. + +=cut + sub link_to_interface { my ($self, $p_group, $p_data3) = @_; @@ -2177,6 +2814,18 @@ sub link_to_interface } } +=item C + +Will delete the contoller link from the device to the interface if such a link exists. + +Next, will delete the responder link from the device to the interface on the +interface, if such a link exists. + +The group is the group on the device that is the controller, such as a button on +a keypad link. It will default to 01. + +=cut + sub unlink_to_interface { my ($self,$p_group) = @_; @@ -2196,7 +2845,21 @@ sub unlink_to_interface } } +=back + +=head2 AUTHOR + +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour +=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 #################################### ### ############ @@ -2204,6 +2867,21 @@ sub unlink_to_interface ### ############ #################################### +=head1 B + +=head2 DESCRIPTION + +Generic class implementation of an Interface Controller. These are the PLM Scenes. + +=head2 INHERITS + +B, B + +=head2 METHODS + +=over + +=cut package Insteon::InterfaceController; @@ -2211,6 +2889,12 @@ use strict; @Insteon::InterfaceController::ISA = ('Insteon::BaseController','Insteon::BaseObject'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -2221,6 +2905,14 @@ sub new return $self; } +=item C + +If C returns a true value returns that. + +Else, calls C and returns 0 + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -2238,4 +2930,20 @@ sub is_root return 0; } +=back + +=head2 AUTHOR + +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + +=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; From 3ecfe5158493b22a0349dbf5d6f77bb21dc099b2 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 18:45:13 -0700 Subject: [PATCH 35/49] Format Docs: Make Head3 Larger, Add Head4 Style It looked silly to have heading 3 smaller than the body text. Heading4 is not often used, but it should be defined to avoid the default setting in browsers. --- web/lib/pod.css | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/web/lib/pod.css b/web/lib/pod.css index 71ba2c74f..7f32e3b0f 100644 --- a/web/lib/pod.css +++ b/web/lib/pod.css @@ -103,8 +103,16 @@ h2 { } h3 { - font: 0.8em "ITC Garamond", Garamond, Georgia, "Times New Roman", Times, serif; + font: 1.0em "ITC Garamond", Garamond, Georgia, "Times New Roman", Times, serif; + color: #36497d; + margin-top: 9px; + margin-bottom: 3px; +} + +h4 { + font: 1.0em "ITC Garamond", Garamond, Georgia, "Times New Roman", Times, serif; color: #36497d; + margin-left: 30px; margin-top: 9px; margin-bottom: 3px; } From 75e18e5d7dad919f56ad8650ac9af389f1d38984 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 19:33:28 -0700 Subject: [PATCH 36/49] Insteon_Docs: Add Documentation to BaseInterface.pm --- lib/Insteon/BaseInterface.pm | 276 ++++++++++++++++++++++++++++++++--- 1 file changed, 253 insertions(+), 23 deletions(-) diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 1e8f03e47..161259d32 100644 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -1,3 +1,18 @@ +=head1 B + +=head2 SYNOPSIS + +Provides support for the Insteon Interface. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut package Insteon::BaseInterface; @@ -5,12 +20,32 @@ use strict; use Insteon::Message; @Insteon::BaseInterface::ISA = ('Class::Singleton'); +=item C + +Locates the active_interface from the main Insteon class and calls +C on it. Called once per loop to get data from the PLM. + +=cut + sub check_for_data { my $interface = &Insteon::active_interface(); $interface->check_for_data(); } +=item C + +Called on startup or reload. Will always request and print the plm_info, which +contains the PLM revision number, to the log on startup. + +If Insteon_PLM_scan_at_startup is set to 1 in the ini file, this routine will poll +all insteon devices and request their current state. Useful for making sure that +no devices changed their state while MisterHouse was off. Will also call +C on each device to ensure that +the proper ALDB object is created for them. + +=cut + sub poll_all { my $scan_at_startup = $main::config_parms{Insteon_PLM_scan_at_startup}; @@ -45,6 +80,12 @@ sub poll_all } } +=item C + +Instantiate a new object. + +=cut + sub new { my ($class) = @_; @@ -59,6 +100,12 @@ sub new return $self; } +=item C + +Returns 1 if object is the same as $self, otherwise returns 0. + +=cut + sub equals { my ($self, $compare_object) = @_; @@ -77,6 +124,12 @@ sub equals } } +=item C<_is_duplicate(cmd)> + +Returns true if cmd already exists in the command stack. + +=cut + sub _is_duplicate { my ($self, $cmd) = @_; @@ -94,6 +147,13 @@ sub _is_duplicate return $duplicate_detected; } +=item C + +If a device has an ALDB, passes link_details onto one of the has_link() routines +within C. Generally called as part of C. + +=cut + sub has_link { my ($self, $insteon_object, $group, $is_controller, $subaddress) = @_; @@ -104,6 +164,14 @@ sub has_link return 0; } +=item C + +If a device has an ALDB, passes link_details onto one of the add_link() routines +within C. Generally called from the "sync links" or +"link to interface" voice commands. + +=cut + sub add_link { my ($self, $parms_text) = @_; @@ -123,6 +191,13 @@ sub add_link } } +=item C + +If a device has an ALDB, passes link_details onto one of the delete_link() routines +within C. Generally called by C. + +=cut + sub delete_link { my ($self, $parms_text) = @_; @@ -142,6 +217,12 @@ sub delete_link } } +=item C + +Optionally stores, and returns the message currently being processed by the interface. + +=cut + sub active_message { my ($self, $message) = @_; @@ -152,6 +233,13 @@ sub active_message return $$self{active_message}; } +=item C + +Clears the message currently being processed by the interface, and sets the +transmit in progress flag to false. + +=cut + sub clear_active_message { my ($self) = @_; @@ -159,12 +247,25 @@ sub clear_active_message $self->transmit_in_progress(0); } +=item C + +Sets the transmit in progress flag to false. + +=cut + sub retry_active_message { my ($self) = @_; $self->transmit_in_progress(0); } +=item C + +Sets the transmit in progress flag to xmit_flag, returns true if xmit_flag +true or xmit timout has not elapsed. + +=cut + sub transmit_in_progress { my ($self, $xmit_flag) = @_; @@ -177,6 +278,15 @@ sub transmit_in_progress return $$self{xmit_in_progress} || ($self->_check_timeout('xmit')==0); } +=item C + +If no msg is passed, returns the queue length. + +Msg is optionally a message, if sent is added to the message queue. +C is then called. + +=cut + sub queue_message { my ($self, $message) = @_; @@ -206,6 +316,17 @@ sub queue_message $self->process_queue(); } +=item C + +If C is true returns queue size. + +If there is a pending message, will leave it as active_message. If retries are +exceeded, will log an error, clear the message, and call the message failure_callback. + +Else, will pull a message from the queue and place it as the active_message. + +=cut + sub process_queue { my ($self) = @_; @@ -278,12 +399,28 @@ sub process_queue return $command_queue_size; } +=item C + +Used to store and return the associated device_id of a device. + +If provided, stores id as the device's id. + +Returns device id without any delimiters. + +=cut + sub device_id { my ($self, $p_deviceid) = @_; $$self{deviceid} = $p_deviceid if defined $p_deviceid; return $$self{deviceid}; } +=item C + +This is called by mh on exit to save the cached ALDB of a device to persistant data. + +=cut + sub restore_string { my ($self) = @_; @@ -292,6 +429,12 @@ sub restore_string return $restore_string; } +=item C + +Used to reload the link table of a device on restart. + +=cut + sub restore_linktable { my ($self,$aldb) = @_; @@ -300,6 +443,13 @@ sub restore_linktable } } +=item C + +Prints a human readable form of MisterHouse's cached version of a device's ALDB +to the print log. Called as part of the "scan links" voice command +or in response to the "log links" voice command. + +=cut sub log_alllink_table { @@ -307,15 +457,33 @@ sub log_alllink_table $self->_aldb->log_alllink_table if $self->_aldb; } +=item C + +Reviews the cached version of all of the ALDBs and based on this review removes +links from this device which are not present in the mht file, not defined in the +code, or links which are only half-links. + +If audit_mode is true, prints the actions that would be taken to the log, but +does nothing. + +=cut + sub delete_orphan_links { my ($self, $audit_mode) = @_; return $self->_aldb->delete_orphan_links($audit_mode) if $self->_aldb; } - ###################### - ### EVENT HANDLERS ### ###################### +### EVENT HANDLERS ### +###################### + +=item C + +Called to process the plm_info request sent by the C command. +Prints output to log. + +=cut sub on_interface_info_received { @@ -326,6 +494,13 @@ sub on_interface_info_received $self->clear_active_message(); } +=item C + +Called to process standard length insteon messages. The routine is rather complex +some messsages are processed right here. The majority are passed off to the +C<_is_info_request()> and C<_process_message()> routines for each device. + +=cut sub on_standard_insteon_received { @@ -479,6 +654,14 @@ sub on_standard_insteon_received } } +=item C + +Called to process extended length insteon messages. The majority of messages are +passed off to the C<_process_message()> routines for each device. + +=cut + + sub on_extended_insteon_received { my ($self, $message_data) = @_; @@ -529,9 +712,17 @@ sub on_extended_insteon_received } - ################################# - ### INTERNAL METHODS/FUNCTION ### ################################# +### INTERNAL METHODS/FUNCTION ### +################################# + +=item C<_set_timeout(timeout_name, timeout_millis)> + +Sets an internal variable, timeout_name, the current time plus the number of +milliseconds specified by timeout_millis. + +=cut + sub _set_timeout { @@ -541,11 +732,17 @@ sub _set_timeout $$self{"_timeout_$timeout_name"} = $tickcount; } -# -# return -1 if timeout_name does not match an existing timer -# return 0 if timer has not expired -# return 1 if timer has expired -# +=item C<_check_timeout(timeout_name)> + +Checks to see if the current number of milliseconds has exceeded the number of +milliseconds defined in timeout_name, which was set by C<_set_timeout()>. + +return -1 if timeout_name does not match an existing timer +return 0 if timer has not expired +return 1 if timer has expired + +=cut + sub _check_timeout { my ($self, $timeout_name) = @_; @@ -556,32 +753,49 @@ sub _check_timeout return ($current_tickcount > $$self{"_timeout_$timeout_name"}) ? 1 : 0; } +=item C<_check_timeout(timeout_name)> + +Erases timeout_name, which was set by C<_set_timeout()>. + +=cut sub _clear_timeout { my ($self, $timeout_name) = @_; $$self{"_timeout_$timeout_name"} = undef; } +=item C<_aldb()> + +Returns the ALDB object associated with the device. + +=cut + sub _aldb { my ($self) = @_; return $$self{aldb}; } -# This function attempts to identify erroneous duplicative incoming messages -# while still permitting identical messages to arrive in close proximity. For -# example, a valid identical message is the ACK of an extended aldb read which -# is always 2F00. -# -# Messages are deemed to be identical if, excluding the max_hops and hops_left -# bits, they are otherwise the same. Identical messages are deemed to be -# erroneous if they are received within a calculated message window, $delay. -# -# The message window is calculated depending on whether the PLM is sending an ACK. -# - -# Returns 1 if the received message is a duplicate message -# See discussion at: https://github.com/hollie/misterhouse/issues/169 +=item C<_is_duplicate_received()> + +This function attempts to identify erroneous duplicative incoming messages +while still permitting identical messages to arrive in close proximity. For +example, a valid identical message is the ACK of an extended aldb read which +is always 2F00. + +Messages are deemed to be identical if, excluding the max_hops and hops_left +bits, they are otherwise the same. Identical messages are deemed to be +erroneous if they are received within a calculated message window, $delay. + +The message window is calculated based on the amount of time that should have +elapsed before a subsequent identical message could have been received.. + +Returns 1 if the received message is an erroneous duplicate message + +See discussion at: https://github.com/hollie/misterhouse/issues/169 + +=cut + sub _is_duplicate_received { my ($self, $message_data, %msg) = @_; my $is_duplicate; @@ -638,4 +852,20 @@ sub _is_duplicate_received { return $is_duplicate; } +=back + +=head2 AUTHOR + +Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + +=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 From 55eb869e7bf1338d12058ddf78de3b3d1ac63bac Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 19:47:18 -0700 Subject: [PATCH 37/49] Insteon_Docs: Update Documentation for Controller.pm --- lib/Insteon/Controller.pm | 69 ++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 2484a2973..143645747 100644 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -62,6 +62,12 @@ my %message_types = ( extended_set_get => 0x2e ); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -76,6 +82,15 @@ sub new return $self; } +=item C + +Handles messages received from the device. Ignores attempts to set the same state +in less than 1 second. (This can likely be removed as the same process exists +now in BaseInsteon set_receive.) If this is not a duplicate message calls +C. + +=cut + sub set { my ($self,$p_state,$p_setby,$p_response) = @_; @@ -180,6 +195,12 @@ sub set_battery_timer { return; } +=item C<_is_battery_time_expired()> + +Returns true if the battery timer has expired, else returns false. + +=cut + sub _is_battery_time_expired { my ($self) = @_; my $root = $self->get_root(); @@ -190,6 +211,15 @@ sub _is_battery_time_expired { return 0; } +=item C<_process_message()> + +Checks for and handles unique RemoteLinc messages such as battery voltage messages. +All other messages are transferred to C. + +Also checks the battery timer and sends a battery request if needed. + +=cut + sub _process_message { my ($self,$p_setby,%msg) = @_; my $clear_message = 0; @@ -263,6 +293,22 @@ sub is_responder =back +=head2 AUTHOR + +Gregg Liming / gregg@limings.net, 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 + +=back + =head1 B =head2 SYNOPSIS @@ -306,6 +352,12 @@ use strict; @Insteon::RemoteLinc_Battery::ISA = ('Generic_Item'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $parent) = @_; my $self = new Generic_Item(); @@ -315,6 +367,13 @@ sub new { return $self; } +=item C + +Receives voltage messages from the parent object and sets the state of this +device accordingly. + +=cut + sub set_receive { my ($self, $p_state) = @_; $self->SUPER::set($p_state); @@ -322,17 +381,9 @@ sub set_receive { =back -=head2 INI PARAMETERS - -None. - =head2 AUTHOR -Bruce Winter, Gregg Limming, Kevin Robert Keegan - -=head2 SEE ALSO - - +Kevin Robert Keegan =head2 LICENSE From 2cc485eb88ab397cb488cf63a08f0f58b1cf3d01 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Jun 2013 20:05:50 -0700 Subject: [PATCH 38/49] Insteon Docs: Update IOLinc Documentation --- lib/Insteon/IOLinc.pm | 181 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 149 insertions(+), 32 deletions(-) diff --git a/lib/Insteon/IOLinc.pm b/lib/Insteon/IOLinc.pm index 11837ab72..1d2acd758 100755 --- a/lib/Insteon/IOLinc.pm +++ b/lib/Insteon/IOLinc.pm @@ -1,47 +1,48 @@ -=begin comment +=head1 B + +=head2 SYNOPSIS -INITIAL CONFIGURATION In user code: - use Insteon::IOLinc; - $io_device = new Insteon::IOLinc('12.34.56',$myPLM); + use Insteon::IOLinc; + $io_device = new Insteon::IOLinc('12.34.56',$myPLM); In items.mht: -INSTEON_IOLINC, 12.34.56, io_device, io_group - -Where commands sent to io_device control the relay, however commands received -from io_device represent the sensor state.. - -EXAMPLE USAGE + INSTEON_IOLINC, 12.34.56, io_device, io_group Turning on a relay: - $io_device->set('on'); + $io_device->set('on'); Turning off a relay: - $io_device->set('off'); + $io_device->set('off'); Requesting sensor status: - $io_device->request_sensor_status(); + $io_device->request_sensor_status(); + +Print the Current Device Settings to the log: + + $io_device->get_operating_flag(); + +=head2 DESCRIPTION + +Support for the Insteon IOLinc. The IOLinc is a strange device in that commands sent to it control one aspect of the device, but commands received from it are from another aspect of the device. -Print the Current Device Settings to the log: - $io_device->get_operating_flag(); - -LINKING +=head3 LINKING As a result of the IOLinc's oddities, when the IOLinc is set as a controller of another device, that other device will be controlled by the sensor state. However, when the IOLinc is set as a responder in a link, the relay of the IOLinc will change with the commands sent by the controller. -STATE REPORTED IN MisterHouse +=head3 STATE REPORTED IN MisterHouse MisterHouse objects are only designed to hold the state of a single aspect. As a result of the IOLinc's oddities, the $io_device defined using the examples above @@ -52,23 +53,20 @@ One more oddity is that using the "set" button on the side of the device to change the state of the relay, will cause MH to perceive this as a change in the state of the sensor, thus placing the sensor and relay objects out of sync. -SENSOR STATE CHILD OBJECT +=head3 SENSOR STATE CHILD OBJECT To create a device that directly tracks the state of the sensor, you can use -the following code to create a generic child object. The state of the child -object will reflect the state of the sensor and it will be automatically updated -as long as the IOLinc is linked to the PLM. Tie_events can be used on this -child object. However, if you want to directly link an obect to the sensor +C. The state of the child object will reflect the state +of the sensor and it will be automatically updated as long as the IOLinc is +linked to the + +However, if you want to directly link an obect to the sensor be sure to use the normal SCENE_MEMBER code in your mht file with the IOLinc defined as the controller. -User Code: - - $io_device_sensor = new Insteon::IOLinc_sensor($io_device); - -Where $io_device is the parent device defined above. +Instructions for this object are contained in C. -NOTES +=head2 NOTES This module works with the Insteon IOLinc device from Smarthome. The EZIO device uses a different set of commands and this code will offer only limited, if any @@ -77,10 +75,16 @@ support at all, for EZIO devices. The state that the relay is in when the device is linked to the PLM matters if you are using relay mode Momentary_A. -BUGS +=head2 BUGS The relay state will not be accurate if you are using a momentary mode. +=head2 INHERITS + +B, B + +=head2 METHODS + =over =cut @@ -121,6 +125,12 @@ my %message_types = ( extended_set_get => 0x2e ); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $p_deviceid, $p_interface) = @_; @@ -133,6 +143,16 @@ sub new return $self; } +=item C + +Handles setting and receiving states from the device. + +If the set command originates from the device, it represents the sensor state +and is processed accordingly. All other set commands are sent to the device +and control the relay state. + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -153,6 +173,16 @@ sub set return; } +=item C + +Works just like C but it requests the status of the sensor. +Will cause the sensor status to be printed to the log. + +As an alternative to calling the function repeatedly, you can define an +C object. + +=cut + sub request_sensor_status { my ($self, $requestor) = @_; @@ -162,6 +192,14 @@ sub request_sensor_status $self->_send_cmd($message); } +=item C<_is_info_request()> + +Checks to see if an incomming message contains the sensor state or the operating +flags for the device. If not the message is passed on to +C. + +=cut + sub _is_info_request { my ($self, $cmd, $ack_setby, %msg) = @_; @@ -202,6 +240,13 @@ sub _is_info_request return $is_info_request; } +=item C<_process_message()> + +Checks for and handles unique IOLinc messages such as the momentary time settings. +All other messages are transferred to C. + +=cut + sub _process_message { my ($self,$p_setby,%msg) = @_; my $clear_message = 0; @@ -403,11 +448,63 @@ sub set_relay_mode return; } +=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 + +=head1 B + +=head2 SYNOPSIS + +User Code: + + $io_device_sensor = new Insteon::IOLinc_sensor($io_device); + +Where $io_device is the parent device defined above. + +=head2 DESCRIPTION + +Creates a device that directly tracks the state of the IOLinc sensor. The state +of this object will reflect the state of the sensor and it will be automatically +updated as long as the IOLinc is linked to the PLM. + +Tie_events can be used on this child object. However, if you want to directly +link an obect to the sensor be sure to use the normal SCENE_MEMBER code in your +mht file with the main IOLinc device defined as the controller. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + package Insteon::IOLinc_sensor; use strict; @Insteon::IOLinc_sensor::ISA = ('Generic_Item'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $parent) = @_; my $self = new Generic_Item(); @@ -417,12 +514,32 @@ sub new { return $self; } +=item C + +Receives sensor state messages from the parent object and sets the state of this +device accordingly. + +=cut + sub set_receive { my ($self, $p_state, $p_setby, $p_respond) = @_; $self->SUPER::set($p_state, $p_setby, $p_respond); } - -1; =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 + +1; From 8f7a6a955b4e1fecaa32b732a3c7f4a08efa3c8f Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 17:00:06 -0700 Subject: [PATCH 39/49] Update Docs: Fix Pod2Html Commands so Links Are Created; Modify Example.pod The settings in pod2html were preventing proper links from being created. The new settings allow it to properly search the pod directories Updated Example.pod to suggest using a link to identify inherited objects. --- bin/update_docs | 4 ++-- lib/ExamplePOD.pm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/update_docs b/bin/update_docs index d32375122..2ca9526ce 100755 --- a/bin/update_docs +++ b/bin/update_docs @@ -131,8 +131,8 @@ foreach my $libsubdir ( keys %libsubdirs ) { pod2html( "--title=$lib", "--infile=$libfile", "--outfile=$htmlfile", "--header", - "--htmlroot=/docs", "--htmldir=$htmldir/..", - "--podroot=$docdir", "--podpath=.", + "--htmlroot=/docs/lib", "--htmldir=$htmldir/", + "--podroot=../lib", "--podpath=.", "--css=/lib/pod.css", ); } diff --git a/lib/ExamplePOD.pm b/lib/ExamplePOD.pm index 412504eb5..4a2950384 100644 --- a/lib/ExamplePOD.pm +++ b/lib/ExamplePOD.pm @@ -10,7 +10,7 @@ =head2 INHERITS -B<---Inherited Items---> +L<---Inherited Items---> =head2 METHODS From 48b08228228fe2d39666615bbf687d0c69da659a Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 17:33:00 -0700 Subject: [PATCH 40/49] Insteon Docs: Add Documentation to Irrigation; Fix Typo in IOLinc Documentation --- lib/Insteon/IOLinc.pm | 1 + lib/Insteon/Irrigation.pm | 174 ++++++++++++++++++++++++++++++-------- 2 files changed, 141 insertions(+), 34 deletions(-) diff --git a/lib/Insteon/IOLinc.pm b/lib/Insteon/IOLinc.pm index 1d2acd758..9418dce5d 100755 --- a/lib/Insteon/IOLinc.pm +++ b/lib/Insteon/IOLinc.pm @@ -86,6 +86,7 @@ B, B =head2 METHODS =over + =cut use strict; diff --git a/lib/Insteon/Irrigation.pm b/lib/Insteon/Irrigation.pm index 42464a0e9..b42df9c83 100755 --- a/lib/Insteon/Irrigation.pm +++ b/lib/Insteon/Irrigation.pm @@ -1,12 +1,7 @@ -=begin comment +=head1 B -AUTHORS -Gregg Liming -David Norwood -Evan P. Hall -Kevin R Keegan - Updated to new Insteon code +=head2 SYNOPSIS -INITIAL CONFIGURATION In user code: use Insteon::Irrigation; @@ -14,45 +9,48 @@ In user code: In items.mht: -INSTEON_IRRIGATION, 12.34.56, irrigation, Irrigation - -BUGS - - -EXAMPLE USAGE + INSTEON_IRRIGATION, 12.34.56, irrigation, Irrigation Creating the object: - use Insteon::Irrigation; - $irrigation = new Insteon::Irrigation('12.34.56', $myPLM); + + use Insteon::Irrigation; + $irrigation = new Insteon::Irrigation('12.34.56', $myPLM); Turning on a valve: - $v_valve_on = new Voice_Cmd "Turn on valve [1,2,3,4,5,6,7,8]"; - if (my $valve = state_now $v_valve_on) { - $valve--; - set_valve $irrigation "0$valve", "on"; - } + + $v_valve_on = new Voice_Cmd "Turn on valve [1,2,3,4,5,6,7,8]"; + if (my $valve = state_now $v_valve_on) { + $valve--; + set_valve $irrigation "0$valve", "on"; + } Turning off a valve: - $v_valve_off = new Voice_Cmd "Turn off valve [1,2,3,4,5,6,7,8]"; - if (my $valve = state_now $v_valve_off) { - $valve--; - set_valve $irrigation "0$valve", "off"; - } + + $v_valve_off = new Voice_Cmd "Turn off valve [1,2,3,4,5,6,7,8]"; + if (my $valve = state_now $v_valve_off) { + $valve--; + set_valve $irrigation "0$valve", "off"; + } Requesting valve status: - $v_valve_status = new Voice_Cmd "Request valve status"; - if (state_now $v_valve_status) { - poll_valve_status $irrigation; - } + + $v_valve_status = new Voice_Cmd "Request valve status"; + if (state_now $v_valve_status) { + poll_valve_status $irrigation; + } + +=head2 DESCRIPTION + +Provides basic support for the EzFlora (aka EzRain) sprinkler controller. -NOTES +=head2 INHERITS -This module works with the EzFlora (aka EzRain) sprinkler controller, documented -here http://www.simplehomenet.com/Downloads/EZRain%20Command%20Set.pdf +B, +=head2 METHODS + +=over -#TODO - - Should be able to intitialize programs. =cut use strict; @@ -75,6 +73,12 @@ our %message_types = ( # -------------------- START OF SUBROUTINES -------------------- # -------------------------------------------------------------- +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $p_deviceid, $p_interface) = @_; @@ -90,6 +94,13 @@ sub new { return $self; } +=item C + +Sends a message to the device requesting the valve status. The response from the +device is printed to the log and stores the result in memory. + +=cut + sub poll_valve_status { my ($self) = @_; my $subcmd = '02'; @@ -98,6 +109,13 @@ sub poll_valve_status { return; } +=item C + +Used to directly control valves. Valve_id is a two digit number 00-07, +valve_state may be on or off. + +=cut + sub set_valve { my ($self, $valve_id, $state) = @_; my $subcmd = $valve_id; @@ -117,6 +135,13 @@ sub set_valve { return; } +=item C + +Used to directly control programs. Program_id is a two digit number 00-03, +valve_state may be on or off. + +=cut + sub set_program { my ($self, $program_id, $state) = @_; my $subcmd = $program_id; @@ -136,31 +161,75 @@ sub set_program { return; } +=item C + +Returns the active valve number identified by the device in response to the last +C request. + +=cut + sub get_active_valve_id() { my ($self) = @_; return $$self{'active_valve_id'}; } +=item C + +Returns true if the active valve identified by the device in response to the last +C request is running. + +=cut + sub get_valve_is_running() { my ($self) = @_; return $$self{'valve_is_running'}; } +=item C + +Returns the active program number identified by the device in response to the last +C request. + +=cut + sub get_active_program_number() { my ($self) = @_; return $$self{'active_program_number'}; } +=item C + +Returns true if the active program identified by the device in response to the last +C request is running. + +=cut + sub get_program_is_running() { my ($self) = @_; return $$self{'program_is_running'}; } +=item C + +Returns true if valve 8 is set to be a pump. In this setup, valve 8 will also +turn on when any other valve is enabled. Generally used if you have some sort +of water pump that runs to provide water to your sprinklers. + +=cut + sub get_pump_enabled() { my ($self) = @_; return $$self{'pump_enabled'}; } +=item C + +Sends a request to the device asking for it to respond with the current timers. +It does not appear that there is code to interpret the response provided by the +device. + +=cut + sub get_timers() { my ($self) = @_; my $cmd = 'sprinkler_timers_request'; @@ -170,6 +239,13 @@ sub get_timers() { return; } +=item C<_is_info_request()> + +Used to intercept and handle unique EZFlora messages, all others are passed on +to C. + +=cut + sub _is_info_request { my ($self, $cmd, $ack_setby, %msg) = @_; my $is_info_request = 0; @@ -198,8 +274,38 @@ sub _is_info_request { } +=item C + +This does nothing and returns 0, it prevents a request_status message, which the +device does not support, from being sent to the device. + +=cut # Overload methods we don't use, but would otherwise cause Insteon traffic. sub request_status { return 0 } +=back + +=head2 AUTHOR + +Gregg Liming +David Norwood +Evan P. Hall +Kevin Robert Keegan + +=head2 SEE ALSO + +L, +L + +=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; \ No newline at end of file From ed773487257ad1f78213e8fac78872355f800a8a Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 17:48:39 -0700 Subject: [PATCH 41/49] Insteon Docs: Add documentation to lighting.pm --- lib/Insteon/Lighting.pm | 536 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 536 insertions(+) diff --git a/lib/Insteon/Lighting.pm b/lib/Insteon/Lighting.pm index 0896d6798..e742e76a1 100644 --- a/lib/Insteon/Lighting.pm +++ b/lib/Insteon/Lighting.pm @@ -1,3 +1,19 @@ +=head1 B + +=head2 DESCRIPTION + +A generic base class for all Insteon lighting objects. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + package Insteon::BaseLight; use strict; @@ -5,6 +21,12 @@ use Insteon::BaseInsteon; @Insteon::BaseLight::ISA = ('Insteon::BaseDevice'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -17,6 +39,12 @@ sub new return $self; } +=item C + +Takes the p_level, and stores it as a numeric level in memory. + +=cut + sub level { my ($self, $p_level) = @_; @@ -32,6 +60,38 @@ sub level } +=back + +=head2 AUTHOR + +Gregg Limming + +=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 + +=head1 B + +=head2 DESCRIPTION + +A generic base class for all dimmable Insteon lighting objects. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut + package Insteon::DimmableLight; use strict; @@ -80,6 +140,17 @@ my %ramp_h2n = ( '1f' => .1 ); +=item C + +Takes ramp_seconds in numeric seconds and returns the hexadecimal value of that +ramp rate or the next lowest value if the passed value doesn't exist. Possible +ramp rates are: + +540, 480, 420, 360, 300, 270, 240, 210, 180, 150, 120, 90, 60, 47, 43, 39, 34, +32, 30, 28, 26, 23.5, 21.5, 19, 8.5, 6.5, 4.5, 2, .5, .3, .2, and .1 + +=cut + sub convert_ramp { my ($ramp_in_seconds) = @_; @@ -92,6 +163,13 @@ sub convert_ramp } } +=item C + +Takes ramp_code as a hexadecimal representation of the device's ramp rate and +returns the equivalent ramp rate in decimal seconds. + +=cut + sub get_ramp_from_code { my ($ramp_code) = @_; @@ -102,6 +180,13 @@ sub get_ramp_from_code } } +=item C + +Takes on_level as an integer percentage and converts it to a hexadecimal +representation of that on_level that is used by a device. + +=cut + sub convert_level { my ($on_level) = @_; @@ -119,6 +204,12 @@ sub convert_level return $level; } +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -128,6 +219,14 @@ sub new return $self; } +=item C + +Takes the p_level, and stores it as a numeric level in memory. If the p_level +is ON and the device has a defined local_onlevel, the local_onlevel is stored +as the numeric level in memory. + +=cut + sub level { my ($self, $p_level) = @_; @@ -156,6 +255,48 @@ sub level } +=back + +=head2 AUTHOR + +Gregg Limming + +=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 + +=head1 B + +=head2 SYNOPSIS + +User code: + + use Insteon::ApplianceLinc; + $appliance_device = new Insteon::ApplianceLinc('12.34.56',$myPLM); + +In mht file: + + INSTEON_APPLIANCELINC, 12.34.56, appliance_device, appliance_group + +=head2 DESCRIPTION + +Provides support for the Insteon ApplianceLinc. + +=head2 INHERITS + +B + +=head2 METHODS + +=over + +=cut package Insteon::ApplianceLinc; @@ -164,6 +305,12 @@ use Insteon::BaseInsteon; @Insteon::ApplianceLinc::ISA = ('Insteon::BaseLight'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -173,6 +320,15 @@ sub new return $self; } +=item C + +Handles setting and receiving states from the device. + +NOTE - Maybe this should be moved to BaseLight, or something farther up the stack? +The only thing this routine does is convert p_state with derive_link_state. + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -182,6 +338,48 @@ sub set return $self->Insteon::BaseDevice::set($link_state, $p_setby, $p_respond); } +=back + +=head2 AUTHOR + +Gregg Limming + +=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 + +=head1 B + +=head2 SYNOPSIS + +User code: + + use Insteon::LampLinc; + $lamp_device = new Insteon::LampLinc('12.34.56',$myPLM); + +In mht file: + + INSTEON_LAMPLINC, 12.34.56, lamp_device, All_Lights + +=head2 DESCRIPTION + +Provides support for the Insteon LampLinc. + +=head2 INHERITS + +B, B + +=head2 METHODS + +=over + +=cut package Insteon::LampLinc; @@ -190,6 +388,11 @@ use Insteon::BaseInsteon; @Insteon::LampLinc::ISA = ('Insteon::DimmableLight','Insteon::DeviceController'); +=item C + +Instantiates a new object. + +=cut sub new { @@ -200,6 +403,49 @@ sub new return $self; } +=back + +=head2 AUTHOR + +Gregg Limming + +=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 + +=head1 B + +=head2 SYNOPSIS + +User code: + + use Insteon::SwitchLincRelay; + $light_device = new Insteon::SwitchLincRelay('12.34.56',$myPLM); + +In mht file: + + INSTEON_SWITCHLINCRELAY, 12.34.56, light_device, All_Lights + +=head2 DESCRIPTION + +Provides support for the Insteon SwitchLinc Relay. + +=head2 INHERITS + +B, B + +=head2 METHODS + +=over + +=cut + package Insteon::SwitchLincRelay; use strict; @@ -207,6 +453,11 @@ use Insteon::BaseInsteon; @Insteon::SwitchLincRelay::ISA = ('Insteon::BaseLight','Insteon::DeviceController'); +=item C + +Instantiates a new object. + +=cut sub new { @@ -217,6 +468,15 @@ sub new return $self; } +=item C + +Handles setting and receiving states from the device. + +NOTE - Maybe this should be moved to BaseLight, or something farther up the stack? +The only thing this routine does is convert p_state with derive_link_state. + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -226,6 +486,49 @@ sub set return $self->Insteon::DeviceController::set($link_state, $p_setby, $p_respond); } +=back + +=head2 AUTHOR + +Gregg Limming + +=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 + +=head1 B + +=head2 SYNOPSIS + +User code: + + use Insteon::SwitchLinc; + $light_device = new Insteon::SwitchLinc('12.34.56',$myPLM); + +In mht file: + + INSTEON_SWITCHLINC, 12.34.56, light_device, All_Lights + +=head2 DESCRIPTION + +Provides support for the Insteon SwitchLinc. + +=head2 INHERITS + +B, B + +=head2 METHODS + +=over + +=cut + package Insteon::SwitchLinc; use strict; @@ -233,6 +536,12 @@ use Insteon::BaseInsteon; @Insteon::SwitchLinc::ISA = ('Insteon::DimmableLight','Insteon::DeviceController'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -242,6 +551,16 @@ sub new return $self; } +=item C + +Handles setting and receiving states from the device. + +NOTE - This is just silly, the only thing this routine does is push the set +command to the C class. Simply reording the class +inheritance of this object would remove the need to do this. + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -249,6 +568,53 @@ sub set return $self->Insteon::DeviceController::set($p_state, $p_setby, $p_respond); } +=back + +=head2 AUTHOR + +Gregg Limming + +=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 + +=head1 B + +=head2 SYNOPSIS + +User code: + + use Insteon::KeyPadLincRelay; + $light_device = new Insteon::KeyPadLincRelay('12.34.56:01',$myPLM); + $button1_device = new Insteon::KeyPadLincRelay('12.34.56:02',$myPLM); + $button2_device = new Insteon::KeyPadLincRelay('12.34.56:03',$myPLM); + +In mht file: + + INSTEON_KEYPADLINCRELAY, 12.34.56:01, light_device, All_Lights + INSTEON_KEYPADLINCRELAY, 12.34.56:02, button1_device, All_Buttons + INSTEON_KEYPADLINCRELAY, 12.34.56:03, button2_device, All_Buttons + +=head2 DESCRIPTION + +Provides support for the Insteon KeypadLinc Relay. + +=head2 INHERITS + +B, B + +=head2 METHODS + +=over + +=cut + package Insteon::KeyPadLincRelay; use strict; @@ -256,6 +622,11 @@ use Insteon::BaseInsteon; @Insteon::KeyPadLincRelay::ISA = ('Insteon::BaseLight','Insteon::DeviceController'); +=item C + +Instantiates a new object. + +=cut sub new { @@ -266,6 +637,13 @@ sub new return $self; } +=item C + +Handles setting and receiving states from the device and specifically its +subordinate buttons. + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -301,6 +679,52 @@ sub set } +=back + +=head2 AUTHOR + +Gregg Limming + +=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 + +=head1 B + +=head2 SYNOPSIS + +User code: + + use Insteon::KeyPadLinc; + $light_device = new Insteon::KeyPadLinc('12.34.56:01',$myPLM); + $button1_device = new Insteon::KeyPadLinc('12.34.56:02',$myPLM); + $button2_device = new Insteon::KeyPadLinc('12.34.56:03',$myPLM); + +In mht file: + + INSTEON_KEYPADLINC, 12.34.56:01, light_device, All_Lights + INSTEON_KEYPADLINC, 12.34.56:02, button1_device, All_Buttons + INSTEON_KEYPADLINC, 12.34.56:03, button2_device, All_Buttons + +=head2 DESCRIPTION + +Provides support for the Insteon KeypadLinc. + +=head2 INHERITS + +B, B + +=head2 METHODS + +=over + +=cut package Insteon::KeyPadLinc; @@ -309,6 +733,11 @@ use Insteon::BaseInsteon; @Insteon::KeyPadLinc::ISA = ('Insteon::DimmableLight','Insteon::DeviceController'); +=item C + +Instantiates a new object. + +=cut sub new { @@ -319,6 +748,16 @@ sub new return $self; } +=item C + +Handles setting and receiving states from the device and specifically its +subordinate buttons. + +NOTE: This could be merged somehow with the set() function in +C + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -354,6 +793,51 @@ sub set } +=back + +=head2 AUTHOR + +Gregg Limming + +=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 + +=head1 B + +=head2 SYNOPSIS + +User code: + + use Insteon::FanLinc; + $light_device = new Insteon::FanLinc('12.34.56:01',$myPLM); + $fan_device = new Insteon::FanLinc('12.34.56:02',$myPLM); + +In mht file: + + INSTEON_FANLINC, 12.34.56:01, light_device, All_Lights + INSTEON_FANLINC, 12.34.56:02, fan_device, All_Fans + +=head2 DESCRIPTION + +Provides support for the Insteon FanLinc. + +=head2 INHERITS + +B, B + +=head2 METHODS + +=over + +=cut + package Insteon::FanLinc; use strict; @@ -361,6 +845,12 @@ use Insteon::BaseInsteon; @Insteon::FanLinc::ISA = ('Insteon::DimmableLight','Insteon::DeviceController'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -369,6 +859,13 @@ sub new return $self; } +=item C + +Handles setting and receiving states from the device and specifically its +fan object. + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -412,6 +909,14 @@ sub set } } +=item C + +Will request the status of the device. For the light device, the process is +handed off to the C routine. This routine +specifically handles the fan request. + +=cut + sub request_status { my ($self,$requestor) = @_; @@ -427,6 +932,14 @@ sub request_status } } +=item C<_is_info_request()> + +Handles incoming messages from the device which are unique to the FanLinc, +specifically this handles the C response for the Fan device, +all other responses are handed off to the C. + +=cut + sub _is_info_request { my ($self, $cmd, $ack_setby, %msg) = @_; @@ -448,6 +961,14 @@ sub _is_info_request return $is_info_request; } +=item C + +Handles command acknowledgement messages received from the device that are +unique to the FanLinc, specifically the acknowledgement of commands sent to the +fan device. All other instances are handed off to the C. + +=cut + sub is_acknowledged { my ($self, $p_ack) = @_; @@ -468,5 +989,20 @@ sub is_acknowledged } } +=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 1 \ No newline at end of file From 8013f7cffb5288aecd783641d4593f957547d849 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 18:49:12 -0700 Subject: [PATCH 42/49] Insteon Docs: Add Documenation to Message.pm --- lib/Insteon/Message.pm | 302 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 294 insertions(+), 8 deletions(-) diff --git a/lib/Insteon/Message.pm b/lib/Insteon/Message.pm index 238ed3138..4f0d0e283 100644 --- a/lib/Insteon/Message.pm +++ b/lib/Insteon/Message.pm @@ -1,8 +1,31 @@ +=head1 B + +=head2 DESCRIPTION + +Generic base class for L object messages, including +L. Primarily just +stores variables for the object. + +=head2 INHERITS + +Nothing + +=head2 METHODS + +=over + +=cut package Insteon::BaseMessage; use strict; +=item C + +Instantiates a new object. + +=cut + sub new { my ($class) = @_; @@ -15,6 +38,12 @@ sub new return $self; } +=item C + +Save and retrieve the interface data defined by C. + +=cut + sub interface_data { my ($self, $interface_data) = @_; @@ -25,6 +54,13 @@ sub interface_data return $$self{interface_data}; } +=item C + +Stores the time at which a message was added to the queue. Used for calculating +how long a message was delayed. + +=cut + sub queue_time { my ($self, $queue_time) = @_; @@ -35,6 +71,12 @@ sub queue_time return $$self{queue_time}; } +=item C + +Data will be evaluated each time the message is sent. + +=cut + sub callback { my ($self, $callback) = @_; @@ -45,6 +87,13 @@ sub callback return $$self{callback}; } +=item C + +Data will be evaluated if the maximum number of retry attempts has been made +and the message is not acknowledged. + +=cut + sub failure_callback { my ($self, $callback) = @_; @@ -55,6 +104,12 @@ sub failure_callback return $$self{failure_callback}; } +=item C + +Stores and retrieves the number of times Misterhouse has tried to send the message. + +=cut + sub send_attempts { my ($self, $send_attempts) = @_; @@ -65,6 +120,12 @@ sub send_attempts return $$self{send_attempts}; } +=item C + +Stores and retrieves what the source of this message was. + +=cut + sub setby { my ($self, $setby) = @_; @@ -75,6 +136,12 @@ sub setby return $$self{setby}; } +=item C + +Stores and retrieves respond variable. + +=cut + sub respond { my ($self, $respond) = @_; @@ -85,6 +152,17 @@ sub respond return $$self{respond}; } + +=item C + +Stores and retrieves no_hop_increase variable, if set to true, when the message +is retried, no additional hops will be added. Typically used where the failure +to deliver the last message attempt was not caused by a failure of the object +to receive the message such as when the PLM is too busy to even attempt sending +the message. + +=cut + sub no_hop_increase { my ($self, $no_hop_increase) = @_; @@ -95,6 +173,16 @@ sub no_hop_increase return $$self{no_hop_increase}; } +=item C + +Stores and retrieves the number of times MisterHouse should try to deliver this +message. If B is set in the ini parameters will default +to that value, otherwise defaults to 5. Some messages types have specific +retry counts, such as L +battery level requests which are only sent once. + +=cut + sub retry_count { my ($self, $retry_count) = @_; if ($retry_count) @@ -107,6 +195,18 @@ sub retry_count { return $result_retry; } +=item C + +Sends this message using the interface p_interface. If C is +greater than 0 then +L +is increase by one. Calls C +when the message is sent. + +Returns 1 if message sent or 0 if message retry count exceeds C. + +=cut + sub send { my ($self, $interface) = @_; @@ -155,6 +255,13 @@ sub send } +=item C + +Returns the number of seconds that elapsed between time set in C +and when this routine was called. + +=cut + sub seconds_delayed { my ($self) = @_; @@ -169,6 +276,13 @@ sub seconds_delayed return $delay_time; } +=item C + +Stores and returns the number of milliseconds, p_timeout, that MisterHouse +should wait before retrying this message again. + +=cut + sub send_timeout { my ($self, $timeout) = @_; @@ -176,17 +290,60 @@ sub send_timeout return $$self{send_timeout}; } +=item C + +Returns the hexadecimal representation of the message. + +=cut + sub to_string { my ($self) = @_; return $self->interface_data; } +=back + +=head2 AUTHOR + +Gregg Limming, 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 + +=head1 B + +=head2 DESCRIPTION + +Main class for all L messages. + +=head2 INHERITS + +L + +=head2 METHODS + +=over + + package Insteon::InsteonMessage; use strict; @Insteon::InsteonMessage::ISA = ('Insteon::BaseMessage'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $command_type, $setby, $command, $extra) = @_; @@ -202,6 +359,12 @@ sub new return $self; } +=item C + +Takes msg, a hexadecimal message, and returns a hash of the message details. + +=cut + sub command_to_hash { my ($p_state) = @_; @@ -282,6 +445,11 @@ sub command_to_hash return %msg; } +=item C + +Stores and retrieves the Cmd1 value for this message. + +=cut sub command { @@ -290,6 +458,12 @@ sub command return $$self{command}; } +=item C + +Stores and retrieves the Command Type value for this message. + +=cut + sub command_type { my ($self, $command_type) = @_; @@ -297,6 +471,13 @@ sub command_type return $$self{command_type}; } +=item C + +Stores and retrieves the extra value for this message. For standard messages +extra is Cmd2. For extended messages extra is Cmd2 + D1-D14. + +=cut + sub extra { my ($self, $extra) = @_; @@ -304,16 +485,33 @@ sub extra return $$self{extra}; } +=item C + +Calculates and returns the number of milliseconds that MisterHouse should wait +for this message to be delivered. The time is based on message type, command type, +and hop count. + + Peek Related Messages = 4000 + PLM Scene Commands = 3000 + Ext / Std + 0 Hop 2220 1400 + 1 Hop 2690 1700 + 2 Hop 3000 1900 + 3 Hop 3170 2000 + +These times were intially calculated by Gregg Limming and appear to have been +calculated based on experience. In reality each hop of a standard message +should take 50 ms and 108 for extended messages. Each time needs to be at least +doubled to compensate for the return hops as well. + +In reality, the PLM and even some Insteon devices appear to react much slower +than the spec defines. These settings generally appear to work without causing +errors or too much undue delay. + +=cut + sub send_timeout { -# hop timing in seconds; this method returns timeout in millisconds -# hops standard extended -# ---- -------- -------- -# 0 1.40 2.22 -# 1 1.70 2.69 -# 2 1.90 3.01 -# 3 2.00 3.17 - my ($self, $ignore) = @_; my $hop_count = (ref $self->setby and $self->setby->isa('Insteon::BaseObject')) ? $self->setby->default_hop_count : $self->send_attempts; @@ -366,6 +564,12 @@ sub send_timeout } } +=item C + +Returns text based human readable representation of the message. + +=cut + sub to_string { my ($self) = @_; @@ -394,6 +598,13 @@ sub to_string return $result; } +=item C + +Stores data as the hexadecimal message, or if data is not specified, then derives +the hexadecimal message and returns it. + +=cut + sub interface_data { my ($self, $interface_data) = @_; @@ -412,6 +623,13 @@ sub interface_data } } +=item C<_derive_interface_data()> + +Converts all of the attributes set for this message into a hexadecimal message +that can be sent to the PLM. Will add checksums and crcs when necessary. + +=cut + sub _derive_interface_data { @@ -547,6 +765,8 @@ The calculation if the crc value involves data bytes from command 1 to the data byte. This function will return two bytes, which are generally added to the data 13 & 14 bytes in an extended message. +To add a crc16 to a message set the $$message{add_crc16} flag to true. + =cut sub calculate_crc16 @@ -573,6 +793,37 @@ sub calculate_crc16 return uc(sprintf("%x", $crc)); } +=back + +=head2 AUTHOR + +Gregg Limming, Kevin Robert Keegan, Michael Stovenour + +=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 + +=head1 B + +=head2 DESCRIPTION + +Main class for all L X10 messages. + +=head2 INHERITS + +L + +=head2 METHODS + +=over + +=cut package Insteon::X10Message; use strict; @@ -709,6 +960,12 @@ my %mh_commands = ( '8' => 'hail_request' ); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $interface_data) = @_; @@ -721,6 +978,13 @@ sub new return $self; } +=item C + +Converts an X10 message from the interface into the generic humand readable X10 +message format. + +=cut + sub get_formatted_data { my ($self) = @_; @@ -753,6 +1017,12 @@ sub get_formatted_data return $msg; } +=item C + +Generates and returns the X10 hexadecimal message for sending to the PLM. + +=cut + sub generate_commands { my ($p_state, $p_setby) = @_; @@ -821,4 +1091,20 @@ sub generate_commands return @data; } +=back + +=head2 AUTHOR + +Gregg Limming + +=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; From 23bad9fc99746b6b4049ee043e90ae45f64f72ed Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 19:02:37 -0700 Subject: [PATCH 43/49] Insteon Docs: Update Documentation in Security.pm --- lib/Insteon/Security.pm | 106 +++++++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 11 deletions(-) diff --git a/lib/Insteon/Security.pm b/lib/Insteon/Security.pm index e60e89118..43dcec5ea 100644 --- a/lib/Insteon/Security.pm +++ b/lib/Insteon/Security.pm @@ -2,8 +2,6 @@ =head2 SYNOPSIS -Configuration: - In user code: use Insteon::MotionSensor; @@ -86,7 +84,7 @@ contains a specific light and voltage level, as opposed to the simple binary states provided by the GROUP method. To use this method, set the C routine. - + You can further create child objects that automatically track the state of the light and voltage levels. These objects allow you to display the state of the light and voltage levels on the MisterHouse webpage. The child objects are @@ -96,7 +94,8 @@ certain threshold. =head2 INHERITS -B, B +L, +B =head2 METHODS @@ -116,6 +115,12 @@ my %message_types = ( extended_set_get => 0x2e ); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class,$p_deviceid,$p_interface) = @_; @@ -130,6 +135,12 @@ sub new return $self; } +=item C + +Handles setting and receiving states from the device. + +=cut + sub set { my ($self, $p_state, $p_setby, $p_respond) = @_; @@ -356,6 +367,13 @@ sub enable_all_motion { return; } +=item C<_is_query_time_expired()> + +Returns true if the last battery level response received by MisterHouse is older +than C. + +=cut + sub _is_query_time_expired { my ($self) = @_; my $root = $self->get_root(); @@ -366,6 +384,14 @@ sub _is_query_time_expired { return 0; } +=item C<_process_message()> + +Processes unique messages sent to the device, notably battery level messages, and +settings messages but passes the rest of the messages off to +L. + +=cut + sub _process_message { my ($self,$p_setby,%msg) = @_; my $clear_message = 0; @@ -457,6 +483,12 @@ sub _process_message { return $clear_message; } +=item C + +Always returns 0. + +=cut + sub is_responder { return 0; @@ -464,6 +496,22 @@ sub is_responder =back +=head2 AUTHOR + +Kevin Robert Keegan, Gregg Limming + +=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 + +=back + =head1 B =head2 SYNOPSIS @@ -494,7 +542,7 @@ battery_low_event code in the parent B object. =head2 INHERITS -B +L =head2 METHODS @@ -507,6 +555,12 @@ use strict; @Insteon::MotionSensor_Battery::ISA = ('Generic_Item'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $parent) = @_; my $self = new Generic_Item(); @@ -516,6 +570,12 @@ sub new { return $self; } +=item C + +Handles state updates provided by the parent object. + +=cut + sub set_receive { my ($self, $p_state) = @_; $self->SUPER::set($p_state); @@ -523,6 +583,22 @@ sub set_receive { =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 + +=back + =head1 B =head2 SYNOPSIS @@ -554,7 +630,7 @@ B object. =head2 INHERITS -B +L =head2 METHODS @@ -567,6 +643,12 @@ use strict; @Insteon::MotionSensor_Light_Level::ISA = ('Generic_Item'); +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $parent) = @_; my $self = new Generic_Item(); @@ -576,6 +658,12 @@ sub new { return $self; } +=item C + +Handles state updates provided by the parent object. + +=cut + sub set_receive { my ($self, $p_state) = @_; $self->SUPER::set($p_state); @@ -589,11 +677,7 @@ None. =head2 AUTHOR -Bruce Winter, Gregg Limming, Kevin Robert Keegan - -=head2 SEE ALSO - - +Kevin Robert Keegan =head2 LICENSE From 05a430c6059ef6fc151166d10b22b3f95647f9dc Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 19:34:07 -0700 Subject: [PATCH 44/49] Insteon Docs: Add More Links to Connect the Documents Together --- lib/Insteon/AllLinkDatabase.pm | 12 ++++++------ lib/Insteon/BaseInsteon.pm | 21 +++++++++++---------- lib/Insteon/BaseInterface.pm | 10 +++++----- lib/Insteon/Controller.pm | 7 ++++--- lib/Insteon/IOLinc.pm | 11 ++++++----- lib/Insteon/Irrigation.pm | 5 +++-- lib/Insteon/Lighting.pm | 31 +++++++++++++++++++------------ lib/Insteon/Security.pm | 2 +- 8 files changed, 55 insertions(+), 44 deletions(-) diff --git a/lib/Insteon/AllLinkDatabase.pm b/lib/Insteon/AllLinkDatabase.pm index 1abea6289..5c7918641 100644 --- a/lib/Insteon/AllLinkDatabase.pm +++ b/lib/Insteon/AllLinkDatabase.pm @@ -1396,7 +1396,7 @@ not by directly calling any of the following methods. =head2 INHERITS -B +L =head2 METHODS @@ -1916,7 +1916,7 @@ sub _on_peek =item C Used to update the local on level and ramp rate of a device. Called by -C. +L. =cut @@ -1935,7 +1935,7 @@ sub update_local_properties =item C -Used to update the flags of a device. Called by C. +Used to update the flags of a device. Called by L. =cut @@ -1956,7 +1956,7 @@ sub update_flags =item C -Gets and returns the details of a link. Called by C. +Gets and returns the details of a link. Called by L. NOTE - This routine may be obsolete, its parent routine is not called by any code. @@ -2074,7 +2074,7 @@ not by directly calling any of the following methods. =head2 INHERITS -B +L =head2 METHODS @@ -2521,7 +2521,7 @@ not by directly calling any of the following methods. =head2 INHERITS -B +L =head2 METHODS diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index f00415695..81a1a4ca3 100644 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -15,7 +15,7 @@ Generic class implementation of an Insteon Device. =head2 INHERITS -B +L =head2 METHODS @@ -1046,7 +1046,7 @@ Generic class implementation of a Base Insteon Device. =head2 INHERITS -B +L =head2 METHODS @@ -1469,7 +1469,7 @@ sub get_root { =item C If a device has an ALDB, passes link_details onto one of the has_link() routines -within C. Generally called as part of C. +within L. Generally called as part of C. =cut @@ -1491,7 +1491,7 @@ sub has_link =item C If a device has an ALDB, passes link_details onto one of the add_link() routines -within C. Generally called from the "sync links" or +within L. Generally called from the "sync links" or "link to interface" voice commands. =cut @@ -1520,7 +1520,7 @@ sub add_link =item C If a device has an ALDB, passes link_details onto one of the update_link() routines -within C. Generally called from the "sync links" +within L. Generally called from the "sync links" voice command. =cut @@ -1548,7 +1548,7 @@ sub update_link =item C If a device has an ALDB, passes link_details onto one of the delete_link() routines -within C. Generally called by C. +within L. Generally called by C. =cut @@ -1930,7 +1930,7 @@ options include: '04' - 6 button; backlighting off '00' - 6 button; backlighting normal -Note: This routine will likely be moved to C at some point. +Note: This routine will likely be moved to L at some point. =cut @@ -2054,7 +2054,7 @@ Generic class implementation of an Insteon Controller. =head2 INHERITS -B +L =head2 METHODS @@ -2685,7 +2685,7 @@ Generic class implementation of an Device Controller. =head2 INHERITS -B +L =head2 METHODS @@ -2875,7 +2875,8 @@ Generic class implementation of an Interface Controller. These are the PLM Scen =head2 INHERITS -B, B +L, +L =head2 METHODS diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 161259d32..93d599e54 100644 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -6,7 +6,7 @@ Provides support for the Insteon Interface. =head2 INHERITS -B +L =head2 METHODS @@ -41,7 +41,7 @@ contains the PLM revision number, to the log on startup. If Insteon_PLM_scan_at_startup is set to 1 in the ini file, this routine will poll all insteon devices and request their current state. Useful for making sure that no devices changed their state while MisterHouse was off. Will also call -C on each device to ensure that +L on each device to ensure that the proper ALDB object is created for them. =cut @@ -150,7 +150,7 @@ sub _is_duplicate =item C If a device has an ALDB, passes link_details onto one of the has_link() routines -within C. Generally called as part of C. +within L. Generally called as part of C. =cut @@ -167,7 +167,7 @@ sub has_link =item C If a device has an ALDB, passes link_details onto one of the add_link() routines -within C. Generally called from the "sync links" or +within L. Generally called from the "sync links" or "link to interface" voice commands. =cut @@ -194,7 +194,7 @@ sub add_link =item C If a device has an ALDB, passes link_details onto one of the delete_link() routines -within C. Generally called by C. +within L. Generally called by C. =cut diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index 143645747..d5cf880e0 100644 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -40,7 +40,8 @@ must first be put into "awake mode." =head2 INHERITS -B, B +L, +L, =head2 METHODS @@ -214,7 +215,7 @@ sub _is_battery_time_expired { =item C<_process_message()> Checks for and handles unique RemoteLinc messages such as battery voltage messages. -All other messages are transferred to C. +All other messages are transferred to L. Also checks the battery timer and sends a battery request if needed. @@ -339,7 +340,7 @@ you when the battery is low. =head2 INHERITS -B +L =head2 METHODS diff --git a/lib/Insteon/IOLinc.pm b/lib/Insteon/IOLinc.pm index 9418dce5d..a6b5bc20d 100755 --- a/lib/Insteon/IOLinc.pm +++ b/lib/Insteon/IOLinc.pm @@ -81,7 +81,8 @@ The relay state will not be accurate if you are using a momentary mode. =head2 INHERITS -B, B +L, +L =head2 METHODS @@ -180,7 +181,7 @@ Works just like C but it requests the status of the sensor. Will cause the sensor status to be printed to the log. As an alternative to calling the function repeatedly, you can define an -C object. +L object. =cut @@ -197,7 +198,7 @@ sub request_sensor_status Checks to see if an incomming message contains the sensor state or the operating flags for the device. If not the message is passed on to -C. +L. =cut @@ -244,7 +245,7 @@ sub _is_info_request =item C<_process_message()> Checks for and handles unique IOLinc messages such as the momentary time settings. -All other messages are transferred to C. +All other messages are transferred to C. =cut @@ -487,7 +488,7 @@ mht file with the main IOLinc device defined as the controller. =head2 INHERITS -B +L =head2 METHODS diff --git a/lib/Insteon/Irrigation.pm b/lib/Insteon/Irrigation.pm index b42df9c83..50633d7a9 100755 --- a/lib/Insteon/Irrigation.pm +++ b/lib/Insteon/Irrigation.pm @@ -45,7 +45,8 @@ Provides basic support for the EzFlora (aka EzRain) sprinkler controller. =head2 INHERITS -B, +L, +L =head2 METHODS @@ -242,7 +243,7 @@ sub get_timers() { =item C<_is_info_request()> Used to intercept and handle unique EZFlora messages, all others are passed on -to C. +to C. =cut diff --git a/lib/Insteon/Lighting.pm b/lib/Insteon/Lighting.pm index e742e76a1..c7660e965 100644 --- a/lib/Insteon/Lighting.pm +++ b/lib/Insteon/Lighting.pm @@ -6,7 +6,7 @@ A generic base class for all Insteon lighting objects. =head2 INHERITS -B +L =head2 METHODS @@ -84,7 +84,7 @@ A generic base class for all dimmable Insteon lighting objects. =head2 INHERITS -B +L =head2 METHODS @@ -290,7 +290,7 @@ Provides support for the Insteon ApplianceLinc. =head2 INHERITS -B +L =head2 METHODS @@ -373,7 +373,8 @@ Provides support for the Insteon LampLinc. =head2 INHERITS -B, B +L, +L =head2 METHODS @@ -438,7 +439,8 @@ Provides support for the Insteon SwitchLinc Relay. =head2 INHERITS -B, B +L, +L =head2 METHODS @@ -521,7 +523,8 @@ Provides support for the Insteon SwitchLinc. =head2 INHERITS -B, B +L, +L =head2 METHODS @@ -556,7 +559,8 @@ sub new Handles setting and receiving states from the device. NOTE - This is just silly, the only thing this routine does is push the set -command to the C class. Simply reording the class +command to the L +class. Simply reording the class inheritance of this object would remove the need to do this. =cut @@ -607,7 +611,8 @@ Provides support for the Insteon KeypadLinc Relay. =head2 INHERITS -B, B +L, +L =head2 METHODS @@ -718,7 +723,8 @@ Provides support for the Insteon KeypadLinc. =head2 INHERITS -B, B +L, +L =head2 METHODS @@ -830,7 +836,8 @@ Provides support for the Insteon FanLinc. =head2 INHERITS -B, B +L, +L =head2 METHODS @@ -912,7 +919,7 @@ sub set =item C Will request the status of the device. For the light device, the process is -handed off to the C routine. This routine +handed off to the L routine. This routine specifically handles the fan request. =cut @@ -991,7 +998,7 @@ sub is_acknowledged =back -=head2 AUTHOR +=head2 AUTHOR Kevin Robert Keegan diff --git a/lib/Insteon/Security.pm b/lib/Insteon/Security.pm index 43dcec5ea..cdfaa39ac 100644 --- a/lib/Insteon/Security.pm +++ b/lib/Insteon/Security.pm @@ -95,7 +95,7 @@ certain threshold. =head2 INHERITS L, -B +L =head2 METHODS From 0cf21dd1a5cda706267d55416ac08b081695ad02 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 19:37:29 -0700 Subject: [PATCH 45/49] Insteon Docs: Missed a =cut --- lib/Insteon/Message.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Insteon/Message.pm b/lib/Insteon/Message.pm index 4f0d0e283..a496568aa 100644 --- a/lib/Insteon/Message.pm +++ b/lib/Insteon/Message.pm @@ -332,6 +332,7 @@ L =over +=cut package Insteon::InsteonMessage; use strict; From c2b8b2c7e840b5592ff80c8e7942c1d699c1dac6 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 19:42:20 -0700 Subject: [PATCH 46/49] Insteon Docs: Fix Various Perldoc Errors --- lib/Insteon.pm | 2 ++ lib/Insteon/Controller.pm | 4 ---- lib/Insteon/Security.pm | 8 -------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/Insteon.pm b/lib/Insteon.pm index 251b41145..f50e8c3ad 100755 --- a/lib/Insteon.pm +++ b/lib/Insteon.pm @@ -680,6 +680,8 @@ sub find_members { return @l_found; } +=back + =head1 INI PARAMETERS =over diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm index d5cf880e0..573439dc9 100644 --- a/lib/Insteon/Controller.pm +++ b/lib/Insteon/Controller.pm @@ -306,10 +306,6 @@ 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. -=cut - -=back - =head1 B =head2 SYNOPSIS diff --git a/lib/Insteon/Security.pm b/lib/Insteon/Security.pm index cdfaa39ac..27f7d04f0 100644 --- a/lib/Insteon/Security.pm +++ b/lib/Insteon/Security.pm @@ -508,10 +508,6 @@ 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. -=cut - -=back - =head1 B =head2 SYNOPSIS @@ -595,10 +591,6 @@ 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. -=cut - -=back - =head1 B =head2 SYNOPSIS From d492568bce02e47fdf2be15b074861c565bbcf48 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 20:20:55 -0700 Subject: [PATCH 47/49] Insteon Docs: Add Documentation to Insteon.pm --- lib/Insteon.pm | 215 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 208 insertions(+), 7 deletions(-) diff --git a/lib/Insteon.pm b/lib/Insteon.pm index f50e8c3ad..b5f2b225b 100755 --- a/lib/Insteon.pm +++ b/lib/Insteon.pm @@ -6,22 +6,169 @@ use strict; #@ This module creates voice commands for all insteon related items. -=head1 NAME +=head1 B -B - This module ..... +=head2 DESCRIPTION -=head1 SYNOPSIS +Provides the basic infrastructure for the Insteon stack, contains many of the +startup routines. +=head2 INHERITS -=head1 DESCRIPTION +None + +=head2 VOICE COMMANDS + +=head3 PLM + +=over + +=item Complete Linking as Responder + +If a device is first placed into linking mode, calling this command will cause +the PLM to complete the link, thus making the PLM the responder. The +C device voice command is likely an easier way to do this, +but this may be need for hard to reach devices or deaf devices. + +=item Initiate Linking as Controller + +Call this first, then press and hold the set button on a device that you wish +to have the PLM control. The C device voice command is +likely an easier way to do this, but this may be need for hard to reach devices +or deaf devices. This is also needed for i2cs devices in which the first link +must currently be manually created this way. + +=item Cancel Linking + +Cancel either of the above two commands without completing a link. + +=item Delete Link with PLM + +This does nothing and shoudl be removed. + +=item Scan Link Table + +This will scan and output to the log only the PLM link table. + +=item Log Links + +This will output only the PLM link table to log. + +=item Delete Orphan Links + +Misterhouse will review the state of all of the links in your system, as it knows +them without any additional scanning. If any of these links are not defined in +your mht file or the links are only half links (controller with no responder or +vice versa) MisterHouse will delete these links. + +It is usually best to: + +1. Run C first unless you know that the +information in MisterHouse is up-to-date. + +2. Run C and verify that what is being added is correct. + +3. Run C to add the links + +4. Run C first to see what will happen. +5. If everything looks right, run C to clean up the old links -=head1 INHERITS +Deleting the orphan links will make your devices happier. If you have unintended +links on your devices, they can run slower and may unnecessarily increase the +number of messages sent on your network. -This module inherits nothing +=item AUDIT Delete Orphan Links +Does the same thing as C but doesn't actually delete anything +instead it just prints what it would have done to the log. -=head1 METHODS +=item Scan All Device Link Tables + +Scans the link tables of the PLM and all devices on your network. On a large +network this can take sometime. You can generally run C +which is much faster without any issue. + +=item Scan Changed Device Link Tables + +Scans the link tables of the PLM and all devices whose link tables have changed +on your network. + +=item Sync All Links + +Similar to C exccept this adds any links that are missing. +This is helpful when adding a bunch of new devices, new scenes, or cleaning things +up. + +See the workflow described in C. + +=item AUDIT Sync All Links + +Same as C but prints what it would do to the log, without doing +anything else. + +=item Log All Device ALDB Status + +Logs some details about each device to the log. See C + +=back + +=head3 Devices + +=over + +=item on + +Turns the device on. + +=item off + +Turns the device off. + +=item Sync Links + +Similar to C above, but this will only add links that are related +to this device. Useful when adding a new device. + +=item Link to Interface + +Will create the controller/responder links between the device and the PLM. + +=item Unlink with Interface + +Will delete the controller/responder links between the device and the PLM. +Useful if you are removing a device from your network. + +=item Status + +Requests the status of the device. + +=item Get Engine Version + +Requests the engine version of the device. Generally you would not need to call +this, but every now and then it is needed when a new device is installed. + +=item Scan Link Table + +This will scan and output to the log only the link table of this device. + +=item Log Links + +Will output to the log only the link table of this device. + +=item Initiate Linking as Controller + +Generally only available for PLM Scenes. This places the PLM in linking mode +and adds any device which the set button is pressed for 4 seconds as a responder +to this scene. Generally not needed. + +=item Cancel Linking + +Cancels the above linking session without creating a link. + +=back + +=head2 METHODS =over @@ -93,6 +240,13 @@ sub scan_all_linktables &_get_next_linkscan($skip_unchanged); } +=item C<_get_next_linkscan_failure()> + +Called if a the scanning of a device fails. Logs the failure and proceeds to +the next device. + +=cut + sub _get_next_linkscan_failure { my($skip_unchanged) = @_; @@ -103,6 +257,12 @@ sub _get_next_linkscan_failure } +=item C<_get_next_linkscan()> + +Gets the next device to scan. + +=cut + sub _get_next_linkscan { my($skip_unchanged, $changed_device) = @_; @@ -313,6 +473,11 @@ sub log_all_ADLB_status } } +=item C + +Initiates the insteon stack, mostly just sets the trigger. + +=cut sub init { @@ -357,6 +522,15 @@ sub init { } +=item C + +Generates and sets the voice commands for all Insteon devices. + +Note: At some point, this function will be pushed out to the specific classes +so that each class can have its own unique set of voice commands. + +=cut + sub generate_voice_commands { @@ -455,6 +629,13 @@ sub generate_voice_commands package Insteon; } +=item C + +Adds object to the list of insteon objects that are managed by the stack. Makes +the object eligible for linking, scanning, and global functions. + +=cut + sub add { my ($object) = @_; @@ -466,6 +647,12 @@ sub add $insteon_manager->add_item($object); } +=item C + +Called as a non-object routine. Returns the object named name. + +=cut + sub find_members { my ($name) = @_; @@ -474,6 +661,13 @@ sub find_members return $insteon_manager->find_members($name); } +=item C + +Returns the object identified by p_id and p_group. Where p_id is the 6 digit +hexadecimal address of the object without periods and group is a two digit +representation of the group number of the device. + +=cut sub get_object { @@ -509,6 +703,13 @@ sub get_object return $retObj; } +=item C + +Sets p_interface as the new active interface. Should likely only be called on +startup or reload. + +=cut + sub active_interface { my ($interface) = @_; From 6c3fc7cf362711d1cc2e6077b0f606d324879300 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 13 Jun 2013 20:32:35 -0700 Subject: [PATCH 48/49] Insteon Docs: Continue Documentation of Insteon.pm --- lib/Insteon.pm | 117 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 14 deletions(-) diff --git a/lib/Insteon.pm b/lib/Insteon.pm index b5f2b225b..52ff2c9cf 100755 --- a/lib/Insteon.pm +++ b/lib/Insteon.pm @@ -23,14 +23,14 @@ None =over -=item Complete Linking as Responder +=item C If a device is first placed into linking mode, calling this command will cause the PLM to complete the link, thus making the PLM the responder. The C device voice command is likely an easier way to do this, but this may be need for hard to reach devices or deaf devices. -=item Initiate Linking as Controller +=item C Call this first, then press and hold the set button on a device that you wish to have the PLM control. The C device voice command is @@ -38,23 +38,23 @@ likely an easier way to do this, but this may be need for hard to reach devices or deaf devices. This is also needed for i2cs devices in which the first link must currently be manually created this way. -=item Cancel Linking +=item C Cancel either of the above two commands without completing a link. -=item Delete Link with PLM +=item C This does nothing and shoudl be removed. -=item Scan Link Table +=item C This will scan and output to the log only the PLM link table. -=item Log Links +=item C This will output only the PLM link table to log. -=item Delete Orphan Links +=item C Misterhouse will review the state of all of the links in your system, as it knows them without any additional scanning. If any of these links are not defined in @@ -78,23 +78,23 @@ Deleting the orphan links will make your devices happier. If you have unintende links on your devices, they can run slower and may unnecessarily increase the number of messages sent on your network. -=item AUDIT Delete Orphan Links +=item C Does the same thing as C but doesn't actually delete anything instead it just prints what it would have done to the log. -=item Scan All Device Link Tables +=item C Scans the link tables of the PLM and all devices on your network. On a large network this can take sometime. You can generally run C which is much faster without any issue. -=item Scan Changed Device Link Tables +=item C Scans the link tables of the PLM and all devices whose link tables have changed on your network. -=item Sync All Links +=item C Similar to C exccept this adds any links that are missing. This is helpful when adding a bunch of new devices, new scenes, or cleaning things @@ -102,12 +102,12 @@ up. See the workflow described in C. -=item AUDIT Sync All Links +=item C Same as C but prints what it would do to the log, without doing anything else. -=item Log All Device ALDB Status +=item C Logs some details about each device to the log. See C @@ -756,12 +756,52 @@ sub check_all_aldb_versions main::print_log("[Insteon] DEBUG4 Checking aldb version of all devices completed") if ($main::Debug{insteon} >= 4); } +=back + +=head2 INI PARAMETERS + +Need to add these + +=head2 AUTHOR + +Gregg Limming, Kevin Robert Keegan, Micheal Stovenour, many others + +=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. + +=head1 B + +=head2 DESCRIPTION + +Provides the basic infrastructure for the Insteon stack, contains many of the +startup routines. + +=head2 INHERITS + +L + +=head2 METHODS + +=over + +=cut package InsteonManager; use strict; use base 'Class::Singleton'; +=item C<_new_instance()> + +Defines a new instance of the class. + +=cut + sub _new_instance { my $class = shift; @@ -770,6 +810,13 @@ sub _new_instance return $self; } +=item C<_active_interface()> + +Sets and returns the active interface. Likely should only be caled on startup +or reload. It also sets all of the hooks for the Insteon stack. + +=cut + sub _active_interface { my ($self, $interface) = @_; @@ -787,6 +834,12 @@ sub _active_interface return $$self{active_interface}; } +=item C + +Adds a list of objects to be tracked. + +=cut + sub add { my ($self,@p_objects) = @_; @@ -805,6 +858,12 @@ sub add } } +=item C + +Adds an object to be tracked. + +=cut + sub add_item { my ($self,$p_object) = @_; @@ -816,6 +875,12 @@ sub add_item return $p_object; } +=item C + +Removes all of the Insteon objects. + +=cut + sub remove_all_items { my ($self) = @_; @@ -827,6 +892,12 @@ sub remove_all_items { delete $self->{objects}; } +=item C + +Adds an item to be tracked if it is not already in the list. + +=cut + sub add_item_if_not_present { my ($self, $p_object) = @_; @@ -841,6 +912,12 @@ sub add_item_if_not_present { return 1; } +=item C + +Removes the Insteon object. + +=cut + sub remove_item { my ($self, $p_object) = @_; return 0 unless $p_object and ref $p_object; @@ -855,6 +932,11 @@ sub remove_item { return 0; } +=item C + +Returns true if object is in the list. + +=cut sub is_member { my ($self, $p_object) = @_; @@ -868,6 +950,13 @@ sub is_member { return 0; } +=item C + +Find and return all tracked objects of type p_type where p_type is an object +class. + +=cut + sub find_members { my ($self,$p_type) = @_; @@ -895,7 +984,7 @@ For debugging debug=insteon or debug=insteon:level where level is 1-4. =head1 AUTHOR -Bruce Winter +Bruce Winter, Gregg Liming, Kevin Robert Keegan, Michael Stovenour, many others =head1 SEE ALSO From b188edb4d314e82719502a42117ef49ee065c590 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 14 Jun 2013 18:13:06 -0700 Subject: [PATCH 49/49] Insteon Docs: Add Documentation to Insteon_PLM; Add INI Parameters --- lib/Insteon.pm | 48 ++++++--- lib/Insteon/BaseInsteon.pm | 26 ++++- lib/Insteon/BaseInterface.pm | 16 +++ lib/Insteon/Message.pm | 11 ++ lib/Insteon_PLM.pm | 199 +++++++++++++++++++++++++++++------ 5 files changed, 255 insertions(+), 45 deletions(-) diff --git a/lib/Insteon.pm b/lib/Insteon.pm index 52ff2c9cf..eb3b59c47 100755 --- a/lib/Insteon.pm +++ b/lib/Insteon.pm @@ -311,10 +311,10 @@ calling the device's sync_links() command. sync_all_links() loads up the module global variable @_sync_devices then kicks off the recursive call backs by calling _get_next_linksync. -=item B - Causes sync to walk through but not actually +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 @@ -416,24 +416,39 @@ sub _get_next_linksync_failure } + =item C Walks through every Insteon device and logs: -=over(8) +=back + +=over8 + +=item * + +Hop Count + +=item * + +Engine Version + +=item * -- Hop Count +ALDB Type -- Engine Version +=item * -- ALDB Type +ALDB Health -- ALDB Health +=item * -- ALDB Scan Time +ALDB Scan Time =back +=over + =cut sub log_all_ADLB_status @@ -760,7 +775,14 @@ sub check_all_aldb_versions =head2 INI PARAMETERS -Need to add these +=over + +=item insteon_menu_states + +A comma seperated list of states that will be added as voice commands to dimmable +devices. + +=back =head2 AUTHOR @@ -972,7 +994,7 @@ sub find_members { =back -=head1 INI PARAMETERS +=head2 INI PARAMETERS =over @@ -982,15 +1004,15 @@ For debugging debug=insteon or debug=insteon:level where level is 1-4. =back -=head1 AUTHOR +=head2 AUTHOR Bruce Winter, Gregg Liming, Kevin Robert Keegan, Michael Stovenour, many others -=head1 SEE ALSO +=head2 SEE ALSO None -=head1 LICENSE +=head2 LICENSE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index 81a1a4ca3..d5ebbb457 100644 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -1006,9 +1006,17 @@ sub failure_reason =head2 INI PARAMETERS -Insteon_PLM_max_queue_time - Was previously used to set the maximum amount of time +=over + +=item Insteon_PLM_max_queue_time + +Was previously used to set the maximum amount of time a message could remain in the queue. This parameter is no longer used in the code -but it still appears in the initialization. It may be removed at a future date. +but it still appears in the initialization. It may be removed at a future date. +This also gets set in L +as well for some reason, but is not used there either. + +=back =head2 AUTHOR @@ -2026,6 +2034,20 @@ sub check_aldb_version =back +=head2 INI PARAMETERS + +=over + +=item Insteon_PLM_max_queue_time + +Was previously used to set the maximum amount of time +a message could remain in the queue. This parameter is no longer used in the code +but it still appears in the initialization. It may be removed at a future date. +This also gets set in L +as well for some reason, but is not used there either. + +=back + =head2 AUTHOR Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 93d599e54..b2493956a 100644 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -854,6 +854,22 @@ sub _is_duplicate_received { =back +=head2 INI PARAMETERS + +=over + +=item Insteon_PLM_scan_at_startup + +By default, MisterHouse will scan all devices at startup. This scan involves +asking each device for its current state and asking each device for its engine +version. In a larger network this can take a few seconds to complete and it does +send a lot of messages all at once, but polling at startup is a good way to make +sure that MisterHouse has an accurate understanding of the network. + +If set to false, will disable the scan at startup. + +=back + =head2 AUTHOR Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour diff --git a/lib/Insteon/Message.pm b/lib/Insteon/Message.pm index a496568aa..a9c8966b2 100644 --- a/lib/Insteon/Message.pm +++ b/lib/Insteon/Message.pm @@ -304,6 +304,17 @@ sub to_string =back +=head2 INI PARAMETERS + +=over + +=item Insteon_retry_count + +Sets the number of times MisterHouse will attempt to resend a message that has +not been acknowledged. The default setting is 5. + +=back + =head2 AUTHOR Gregg Limming, Kevin Robert Keegan diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 79b2d0704..90e670463 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -1,43 +1,24 @@ -=begin comment -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +=head1 B -File: - Insteon_PLM.pm +=head2 SYNOPSIS -Description: +---Example Code and Usage--- - This is the base interface class for Insteon Power Line Modem (PLM) +=head2 DESCRIPTION - For more information regarding the technical details of the PLM: - http://www.smarthome.com/manuals/2412sdevguide.pdf +This is the base interface class for Insteon Power Line Modem (PLM) -Author(s): - Jason Sharpee / jason@sharpee.com - Gregg Liming / gregg@limings.net +=head2 INHERITS -License: - This free software is licensed under the terms of the GNU public license. GPLv2 +L, +L -Usage: - Use these mh.ini parameters to enable this code: - - Insteon_PLM_serial_port=/dev/ttyS4 - - Example initialization: - - -Notes: - -Special Thanks to: - Brian Warren for significant testing and patches - Bruce Winter - MH - -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +=head2 METHODS +=over =cut - package Insteon_PLM; use strict; @@ -82,6 +63,11 @@ my %prefix = ( plm_get_config => '0273' ); +=item C + +Creates a new serial port connection. + +=cut sub serial_startup { my ($instance) = @_; @@ -93,6 +79,12 @@ sub serial_startup { } +=item C + +Instantiates a new object. + +=cut + sub new { my ($class, $port_name, $p_deviceid) = @_; $port_name = 'Insteon_PLM' if !$port_name; @@ -126,6 +118,11 @@ sub new { return $self; } +=item C + +This is called by mh on exit to save the cached ALDB of a device to persistant data. + +=cut sub restore_string { @@ -137,6 +134,17 @@ sub restore_string return $restore_string; } +=item C + +Called once per loop. This checks for any data waiting on the serial port, if +data exists it is sent to C<_parse_data>. If there is no data waiting, then +this checks to see if the timers for any previous commands have expired, if they +have, it calls C. Else, this checks to see if there +is any timeout preventing a transmission right now, if there is no timeout it +calles C. + +=cut + sub check_for_data { my ($self) = @_; @@ -194,6 +202,11 @@ sub check_for_data { } } +=item C + +Used to send X10 messages, generates an X10 command and queues it. + +=cut sub set { @@ -206,6 +219,12 @@ sub set } } +=item C + +Puts the PLM into linking mode as a responder. + +=cut + sub complete_linking_as_responder { my ($self, $group) = @_; @@ -220,12 +239,24 @@ sub complete_linking_as_responder $self->queue_message($message) } +=item C + +Causes MisterHouse to dump its cache of the PLM link table to the log. + +=cut + sub log_alllink_table { my ($self) = @_; $self->_aldb->log_alllink_table if $self->_aldb; } +=item C + +Causes MisterHouse to scan the link table of the PLM only. + +=cut + sub scan_link_table { my ($self,$callback) = @_; @@ -236,6 +267,13 @@ sub scan_link_table $self->_aldb->get_first_alllink(); } +=item C + +Puts the PLM into linking mode as a controller, if p_group is specified the +controller will be added for this group, otherwise it will be for group 00. + +=cut + sub initiate_linking_as_controller { my ($self, $group) = @_; @@ -249,6 +287,14 @@ sub initiate_linking_as_controller $self->queue_message($message); } +=item C + +Puts the PLM into unlinking mode, if p_group is specified the PLM will try +to unlink any devices linked to that group that identify themselves with a set +button press. + +=cut + sub initiate_unlinking_as_controller { my ($self, $group) = @_; @@ -262,6 +308,11 @@ sub initiate_unlinking_as_controller $self->queue_message($message); } +=item C + +Cancels any pending linking session that has not completed. + +=cut sub cancel_linking { @@ -269,13 +320,23 @@ sub cancel_linking $self->queue_message(new Insteon::InsteonMessage('all_link_cancel', $self)); } +=item C<_aldb()> + +Returns the PLM's aldb object. + +=cut + sub _aldb { my ($self) = @_; return $$self{aldb}; } +=item C<_send_cmd()> +Causes a message to be sent to the serial port. + +=cut sub _send_cmd { my ($self, $message, $cmd_timeout) = @_; @@ -330,6 +391,15 @@ sub _send_cmd { } } +=item C<_parse_data()> + +A complex routine that parses data comming in from the serial port. In many cases +multiple messages or fragments of messages may arrive at once. This routine sorts +through the string of hexadecimal characters and determines what type of message +has arrived and its full content. Based on the type of message, it is then +passed off to lower level message handling routines. + +=cut sub _parse_data { my ($self, $data) = @_; @@ -753,17 +823,86 @@ sub _parse_data { return; } -# dummy sub required to support the X10 integrtion +=item C + +Dummy sub required to support the X10 integrtion, does nothing. + +=cut sub add_id_state { # do nothing } +=item C + +Stores and returns the firmware version of the PLM. + +=cut + sub firmware { my ($self, $p_firmware) = @_; $$self{firmware} = $p_firmware if defined $p_firmware; return $$self{firmware}; } +=back + +=head2 INI PARAMETERS + +=over + +=item Insteon_PLM_serial_port + +Identifies the port on which the PLM is attached. Example: + + Insteon_PLM_serial_port=/dev/ttyS4 + +=item Insteon_PLM_xmit_delay + +Sets the minimum amount of seconds that must elapse between sending Insteon messages +to the PLM. Defaults to 0.25. + +=item Insteon_PLM_xmit_x10_delay + +Sets the minimum amount of seconds that must elapse between sending X10 messages +to the PLM. Defaults to 0.50. + +=item Insteon_PLM_disable_throttling + +Periodically, the PLM will report that it is too busy to accept a message from +MisterHouse. When this happens, MisterHouse will wait 1 second before trying +to send a message to the PLM. If this is set to 1, downgrades the delay to only +.3 seconds. Most of the issues which caused the PLM to overload have been handled +it is unlikely that you would need to set this. + +=back + +=head2 NOTES + +Special Thanks to: + +Brian Warren for significant testing and patches + +Bruce Winter - MH + +=head2 AUTHOR + +Jason Sharpee / jason@sharpee.com, Gregg Liming / gregg@limings.net, Kevin Robert Keegan, Michael Stovenour + +=head2 SEE ALSO + +For more information regarding the technical details of the PLM: +L + +=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;