From f062fc7451e86c8a58381ca867a01c3e14ccc25e Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Sun, 3 Mar 2013 17:54:25 -0700 Subject: [PATCH 01/34] Insteon: Fix Bug in PLM Sanity Check Which Caused Crash on X10 Messages Fix issue identified by Marc http://misterhouse.10964.n7.nabble.com/Insteon-IOLinc-Support-Draft-Done-tp17944p17950.html --- 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 a8d4b2770..6ee319833 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -308,7 +308,7 @@ sub _send_cmd { $self->_set_timeout('command', $cmd_timeout); # a commmand needs to be PLM ack'd w/i 3 seconds or it gets dropped } } - my $is_extended = ($message->command_type eq "insteon_ext_send") ? 1 : 0; + my $is_extended = ($message->can('command_type') && $message->command_type eq "insteon_ext_send") ? 1 : 0; if (length($command) != (Insteon::MessageDecoder::insteon_cmd_len(substr($command,0,4), 0, $is_extended)*2)){ &::print_log( "[Insteon_PLM]: ERROR!! Command sent to PLM " . lc($command) . " is of an incorrect length. Message not sent."); From ed7a009f3552f21fb0eff23d0f3b1c2047a1d944 Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 05:59:17 -0400 Subject: [PATCH 02/34] Remove executable mode from lib/Insteon/ Perl Module files. --- lib/Insteon/AllLinkDatabase.pm | 0 lib/Insteon/BaseInsteon.pm | 0 lib/Insteon/BaseInterface.pm | 0 lib/Insteon/Controller.pm | 0 lib/Insteon/Lighting.pm | 0 lib/Insteon/Message.pm | 0 lib/Insteon/MessageDecoder.pm | 0 lib/Insteon/Security.pm | 0 8 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 lib/Insteon/AllLinkDatabase.pm mode change 100755 => 100644 lib/Insteon/BaseInsteon.pm mode change 100755 => 100644 lib/Insteon/BaseInterface.pm mode change 100755 => 100644 lib/Insteon/Controller.pm mode change 100755 => 100644 lib/Insteon/Lighting.pm mode change 100755 => 100644 lib/Insteon/Message.pm mode change 100755 => 100644 lib/Insteon/MessageDecoder.pm mode change 100755 => 100644 lib/Insteon/Security.pm diff --git a/lib/Insteon/AllLinkDatabase.pm b/lib/Insteon/AllLinkDatabase.pm old mode 100755 new mode 100644 diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm old mode 100755 new mode 100644 diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm old mode 100755 new mode 100644 diff --git a/lib/Insteon/Controller.pm b/lib/Insteon/Controller.pm old mode 100755 new mode 100644 diff --git a/lib/Insteon/Lighting.pm b/lib/Insteon/Lighting.pm old mode 100755 new mode 100644 diff --git a/lib/Insteon/Message.pm b/lib/Insteon/Message.pm old mode 100755 new mode 100644 diff --git a/lib/Insteon/MessageDecoder.pm b/lib/Insteon/MessageDecoder.pm old mode 100755 new mode 100644 diff --git a/lib/Insteon/Security.pm b/lib/Insteon/Security.pm old mode 100755 new mode 100644 From ca91ce194e178eaa15fa65b86c0cfa2acce3e668 Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 06:27:03 -0400 Subject: [PATCH 03/34] Add missing shabang to lib/Insteon/MessageDecoder_test.pl file. --- lib/Insteon/MessageDecoder_test.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/MessageDecoder_test.pl b/lib/Insteon/MessageDecoder_test.pl index 54ed58a3e..8e409bc9c 100755 --- a/lib/Insteon/MessageDecoder_test.pl +++ b/lib/Insteon/MessageDecoder_test.pl @@ -1,4 +1,5 @@ - +#!/usr/bin/perl -w + use strict; use lib ".."; use Insteon::MessageDecoder; From 9d2459e81ec9234bc446503412aa9e394d37aea6 Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 11:41:26 -0400 Subject: [PATCH 04/34] Correct Perl path in bin/display_callers shabang line. --- bin/display_callers | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/display_callers b/bin/display_callers index c8e1ee051..506ab66ca 100755 --- a/bin/display_callers +++ b/bin/display_callers @@ -1,5 +1,3 @@ -#!d:/perl/bin/perl.exe -# -*- Perl -*- #!/usr/bin/perl #--------------------------------------------------------------------------- # File: From d4be2c5a9653d459ba7d11c07f28659170adeef7 Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 11:47:03 -0400 Subject: [PATCH 05/34] Correct Perl path in bin/test_x10 shabang line. --- bin/test_x10 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/test_x10 b/bin/test_x10 index 86441d908..ef76cd399 100755 --- a/bin/test_x10 +++ b/bin/test_x10 @@ -1,4 +1,4 @@ -#!/bin/perl -w +#!/usr/bin/perl -w # Use this as a stand-alone (outside of mh) way to # test a CM11 and/or CM17 X10 device From 50e0a4ae47d1c2021932d8f54eab8eb08d2ec58b Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 11:49:57 -0400 Subject: [PATCH 06/34] Correct Perl path in bin/xAP-festival.pl shabang line. --- bin/xAP-festival.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/xAP-festival.pl b/bin/xAP-festival.pl index d3a8561f5..9c59d9e00 100755 --- a/bin/xAP-festival.pl +++ b/bin/xAP-festival.pl @@ -1,4 +1,4 @@ -#!/bin/perl +#!/usr/bin/perl =begin comment From fb89e016912ee452a266bd41488098bd9663c51d Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 11:55:30 -0400 Subject: [PATCH 07/34] Correct Perl path in web/bin/dbmedit.cgi shabang line. --- web/bin/dbmedit.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/bin/dbmedit.cgi b/web/bin/dbmedit.cgi index 43663f7ab..cd525bf7e 100755 --- a/web/bin/dbmedit.cgi +++ b/web/bin/dbmedit.cgi @@ -1,4 +1,4 @@ -#!/usr/local/bin/perl +#!/usr/bin/perl # # DBMEdit 1.0 # From 369709f411b8d633c1234f95cad3f8db841bd31e Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 11:57:33 -0400 Subject: [PATCH 08/34] Correct Perl path in web/bin/test_cgi_error shabang line. --- web/bin/test_cgi_error.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/bin/test_cgi_error.pl b/web/bin/test_cgi_error.pl index 4cbcaa403..1423a4118 100644 --- a/web/bin/test_cgi_error.pl +++ b/web/bin/test_cgi_error.pl @@ -1,4 +1,4 @@ -#!/local/bin/perl +#!/usr/bin/perl # Test for returning errors From d0ce9f38eead3cf7340b3335668ee417462fd24b Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 11:59:31 -0400 Subject: [PATCH 09/34] Correct Perl path in web/bin/weather_graph_zoom.pl shabang line. --- web/bin/weather_graph_zoom.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/bin/weather_graph_zoom.pl b/web/bin/weather_graph_zoom.pl index 603fdb7d9..ad24d803a 100755 --- a/web/bin/weather_graph_zoom.pl +++ b/web/bin/weather_graph_zoom.pl @@ -1,4 +1,4 @@ -#!/local/bin/perl +#!/usr/bin/perl # # $Date$ # $Revision$ From 2005d3ded7a19ee2cac1ddbee262ac775de8c8dc Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 12:00:58 -0400 Subject: [PATCH 10/34] Correct Perl path in web/newclock/index.pl shabang line. --- web/newclock/index.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/newclock/index.pl b/web/newclock/index.pl index 589f7b50e..f73215d1e 100644 --- a/web/newclock/index.pl +++ b/web/newclock/index.pl @@ -1,4 +1,4 @@ -#!/local/bin/perl +#!/usr/bin/perl use CGI; From b8952887924a08e36cdea6709d8d81dd09454b70 Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 12:02:45 -0400 Subject: [PATCH 11/34] Correct Perl path in web/newclock/alarm.pl shabang line. --- web/newclock/alarm.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/newclock/alarm.pl b/web/newclock/alarm.pl index 1486a4197..7899b7cdf 100644 --- a/web/newclock/alarm.pl +++ b/web/newclock/alarm.pl @@ -1,4 +1,4 @@ -#!/local/bin/perl +#!/usr/bin/perl use CGI; From c7f026da712e2267c4c57766bbf7838f444d1486 Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 12:03:56 -0400 Subject: [PATCH 12/34] Correct Perl path in web/organizer/calendar.pl shabang line. --- web/organizer/calendar.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/organizer/calendar.pl b/web/organizer/calendar.pl index 6f069c53b..c224a889c 100644 --- a/web/organizer/calendar.pl +++ b/web/organizer/calendar.pl @@ -1,4 +1,4 @@ -#!/usr/local/bin/perl -w +#!/usr/bin/perl -w # # $Date$ # $Revision$ From 14b11d9e7d73b6942fe5ec8bc4f8d394b89c4163 Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 12:05:30 -0400 Subject: [PATCH 13/34] Correct Perl path in web/organizer/contacts.pl shabang line. --- web/organizer/contacts.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/organizer/contacts.pl b/web/organizer/contacts.pl index 8ff29c93f..6efca86d8 100644 --- a/web/organizer/contacts.pl +++ b/web/organizer/contacts.pl @@ -1,4 +1,4 @@ -#!/usr/local/bin/perl -w +#!/usr/bin/perl -w # ---------------------------------------------------------------------------- # contacts.pl # Copyright (c) 2001 Jason M. Hinkle. All rights reserved. This script is From 81f55739b3ea492dbc0b7d145f3481522f45f601 Mon Sep 17 00:00:00 2001 From: Robert James Clay Date: Sun, 24 Mar 2013 12:06:28 -0400 Subject: [PATCH 14/34] Correct Perl path in web/organizer/tasks.pl shabang line. --- web/organizer/tasks.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/organizer/tasks.pl b/web/organizer/tasks.pl index 5ee765650..12ef7971b 100644 --- a/web/organizer/tasks.pl +++ b/web/organizer/tasks.pl @@ -1,4 +1,4 @@ -#!/usr/local/bin/perl -w +#!/usr/bin/perl -w # ---------------------------------------------------------------------------- # tasks.pl # Copyright (c) 2001 Jason M. Hinkle. All rights reserved. This script is From 49b51575471c0b99a2e038cc1efcbb1ada209fff Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Mon, 22 Apr 2013 19:00:51 -0700 Subject: [PATCH 15/34] Insteon: Clear No_Hop_Flag Even If No Debug; Don't Call Setby if Undef Fixes errors pointed out by CDragon and MStovenour --- lib/Insteon/Message.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Insteon/Message.pm b/lib/Insteon/Message.pm index 841553322..a4851923f 100755 --- a/lib/Insteon/Message.pm +++ b/lib/Insteon/Message.pm @@ -116,10 +116,11 @@ sub send $self->setby->default_hop_count($self->setby->default_hop_count + 1); } } - elsif (defined($$self{no_hop_increase}) && $main::Debug{insteon} + elsif (defined($$self{no_hop_increase}) && ref $self->setby && $self->setby->isa('Insteon::BaseObject')){ &main::print_log("[Insteon::BaseMessage] Hop count not increased for " - . $self->setby->get_object_name . " because no_hop_increase flag was set."); + . $self->setby->get_object_name . " because no_hop_increase flag was set.") + if $main::Debug{insteon}; $$self{no_hop_increase} = undef; } } From aaadbb5f8d1af090469ea204f791c1de44d55100 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Mon, 29 Apr 2013 07:54:25 -0700 Subject: [PATCH 16/34] Insteon: Fix Error in PLM Message Integrity Check Logic Fix bugs in which PLM commands with a letter were rejected as being too long. Notably this prevented the scanning of the PLM link table. Also fix bug which prevented MH from sending extended length messages to the PLM. Fixes Issues hollie/misterhouse#170 mstovenour/misterhouse#14 --- lib/Insteon/MessageDecoder.pm | 13 +++++++++---- lib/Insteon_PLM.pm | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/Insteon/MessageDecoder.pm b/lib/Insteon/MessageDecoder.pm index 231902d99..e518988cf 100755 --- a/lib/Insteon/MessageDecoder.pm +++ b/lib/Insteon/MessageDecoder.pm @@ -115,7 +115,7 @@ my %plmcmdlen = ( '0258' => [3, 3], '0260' => [2, 9], '0261' => [5, 6], - '0262' => [8, 9], # could get 9 or 23 (Standard or Extended Message received) + '0262' => [8, 9, 22, 23], # could get 9 or 23 (Standard or Extended Message received) '0263' => [4, 5], '0264' => [4, 5], '0265' => [2, 3], @@ -892,10 +892,15 @@ sub insteon_decode_cmd { } -#Takes a 2 byte hex cmd, 0 for send, 1, for rec and returns expected byte length +#$plm_cmd is 2 byte hex cmd; $send_rec is 0 for send, 1, for rec; $is_extended is 1 if extended send +#returns expected byte length sub insteon_cmd_len{ - my ($plm_cmd, $send_rec) = @_; - return $plmcmdlen{$plm_cmd}->[$send_rec] + my ($plm_cmd, $send_rec, $is_extended) = @_; + if ($is_extended && $plmcmdlen{uc($plm_cmd)} > 2) { + return $plmcmdlen{uc($plm_cmd)}->[($send_rec+2)]; + } else { + return $plmcmdlen{uc($plm_cmd)}->[$send_rec]; + } } diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index ff26da46f..a8d4b2770 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -308,8 +308,8 @@ sub _send_cmd { $self->_set_timeout('command', $cmd_timeout); # a commmand needs to be PLM ack'd w/i 3 seconds or it gets dropped } } - - if (length($command) != (Insteon::MessageDecoder::insteon_cmd_len(substr($command,0,4), 0)*2)){ + my $is_extended = ($message->command_type eq "insteon_ext_send") ? 1 : 0; + if (length($command) != (Insteon::MessageDecoder::insteon_cmd_len(substr($command,0,4), 0, $is_extended)*2)){ &::print_log( "[Insteon_PLM]: ERROR!! Command sent to PLM " . lc($command) . " is of an incorrect length. Message not sent."); $self->clear_active_message(); @@ -719,4 +719,4 @@ sub firmware { } -1; \ No newline at end of file +1; From df316a72625fb5794920f6e0c3f11a4b27eed4e8 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Mon, 29 Apr 2013 19:16:16 -0700 Subject: [PATCH 17/34] Insteon: Catch and Log AllLink_Cleanup_Reports Fix bug in which MH set the state of a device to 'link_cleanup_report.' Log the results of the cleanup reports. Fixes Issue hollie/misterhouse#168 --- lib/Insteon/BaseInsteon.pm | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index 4ec80281f..9a672f79b 100755 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -560,8 +560,18 @@ sub _process_message $p_state = $msg{command}; if ($msg{type} eq 'alllink') { - $self->set($p_state, $self); - $$self{_pending_cleanup} = 1; + if ($msg{command} eq 'link_cleanup_report'){ + if ($msg{extra} == 0){ + ::print_log("[Insteon::BaseObject] DEBUG Received AllLink Cleanup Success for " + . $self->{object_name}) if $main::Debug{insteon} >= 1; + } else { + ::print_log("[Insteon::BaseObject] WARN " . $msg{extra} . " Device(s) failed to " + . "acknowledge the command from " . $self->{object_name}); + } + } else { + $self->set($p_state, $self); + $$self{_pending_cleanup} = 1; + } } elsif ($msg{type} eq 'cleanup') { From b2e3a68ec399cd403acf9bf0625e3d19a10b869e Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Mon, 29 Apr 2013 19:56:36 -0700 Subject: [PATCH 18/34] Insteon: Catch Error if Device ID in All_Link_Failure Does Not Exist Checks to make sure an object exists, if no object exists for that device_id then it sends a message to the log reminding the user to delete_orphan links. Fixes mstovenour/misterhouse#17 --- lib/Insteon_PLM.pm | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 9bfbf9229..f47de6126 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -636,10 +636,15 @@ sub _parse_data { . "$failure_device and group: $failure_group") if $main::Debug{insteon} >= 2; my $failed_object = &Insteon::get_object($failure_device,'01'); - my $message = new Insteon::InsteonMessage('all_link_direct_cleanup', $failed_object, - $self->active_message->command, $failure_group); - push(@{$$failed_object{command_stack}}, $message); - $failed_object->_process_command_stack(); + if (ref $failed_object){ + my $message = new Insteon::InsteonMessage('all_link_direct_cleanup', $failed_object, + $self->active_message->command, $failure_group); + push(@{$$failed_object{command_stack}}, $message); + $failed_object->_process_command_stack(); + } else { + &::print_log("[Insteon_PLM] WARN: Device ID: $failure_device does not exist. You may " + . "want to run delete orphans to remove this link from your PLM"); + } } else { &::print_log("[Insteon_PLM] DEBUG2: Received all-link cleanup failure." . " But there is no pending message.") if $main::Debug{insteon} >= 2; @@ -746,4 +751,4 @@ sub firmware { } -1; \ No newline at end of file +1; From 951a5076d82adfdb713db84d9f4483a62bdd43b3 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Tue, 30 Apr 2013 18:01:56 -0700 Subject: [PATCH 19/34] Insteon: Add Function to Filter Out Duplicate Received Messages This creates a log of recently received messages with a timestamp. Subsequent messages are check to see if they match. If a match is found and if they message was received within the time permitted by the number of remaining hops plus a little wiggle room, the message is dropped. Fixes issue hollie/misterhouse#169 --- lib/Insteon/BaseInterface.pm | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 3ed30426e..d698e7b17 100755 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -52,6 +52,7 @@ sub new my $self = {}; @{$$self{command_stack2}} = (); @{$$self{command_history}} = (); + $$self{received_commands} = {}; bless $self, $class; $self->transmit_in_progress(0); # $self->debug(0) unless $self->debug; @@ -329,6 +330,7 @@ sub on_interface_info_received sub on_standard_insteon_received { my ($self, $message_data) = @_; + return if $self->_is_duplicate_received($message_data); my %msg = &Insteon::InsteonMessage::command_to_hash($message_data); if (%msg) { @@ -475,6 +477,7 @@ sub on_standard_insteon_received sub on_extended_insteon_received { my ($self, $message_data) = @_; + return if $self->_is_duplicate_received($message_data); my %msg = &Insteon::InsteonMessage::command_to_hash($message_data); if (%msg) { @@ -555,5 +558,46 @@ sub _aldb return $$self{aldb}; } +# Returns 1 if the received message is a duplicate message +# See discussion at: https://github.com/hollie/misterhouse/issues/169 +sub _is_duplicate_received { + my ($self, $message_data) = @_; + my $is_duplicate; + + #Current time in milliseconds + my $curr_milli = sprintf('%.0f', &main::get_tickcount); + + #Key is the message with the hops_left portion zeroed out + my $key = $message_data; + substr($key,12,2) = substr($key,12,2) & 0xF3; + + #How long does it take to transmit each hop of this message + my $message_time = (length($message_data) > 18) ? 108 : 50; + + #Get hops left + my $hops_left = hex(substr($message_data,13,1)) >> 2; + + #Add additional delay to catch PLM delays or out of sync messages + my $delay = ($message_time * ($hops_left+2)); + + #Clean hash of outdated entries + for (keys $$self{received_commands}){ + if ($$self{received_commands}{$_} < $curr_milli){ + delete($$self{received_commands}{$_}); + } + } + + #Check if the message exists + if (exists($$self{received_commands}{$key})){ + $is_duplicate = 1; + ::print_log("[Insteon::BaseInterface] WARN! Dropped duplicate incoming message " + . $message_data) if $main::Debug{insteon}; + } else { + #Message was not in hash, so add it + $$self{received_commands}{$key} = $curr_milli + $delay; + } + + return $is_duplicate; +} 1 From 419ce45d611e73bb5d6ff50b34aa2c0fb57643d0 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Tue, 7 May 2013 18:25:25 -0700 Subject: [PATCH 20/34] Insteon: Update PLM Scene State on Change When a PLM Scene is successfully sent, MH will now update the state of the scene. Fixes issue hollie/misterhouse#177 --- lib/Insteon_PLM.pm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 5441707b2..487ce7bf9 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -682,6 +682,11 @@ sub _parse_data { my $message_to_string = ($self->active_message) ? $self->active_message->to_string() : ""; &::print_log("[Insteon_PLM] Received all-link cleanup success: $message_to_string") if $main::Debug{insteon}; + if (ref $self->active_message->setby){ + my $object = $self->active_message->setby; + $object->is_acknowledged(1); + $object->_process_command_stack(); + } $self->clear_active_message(); } } From 6c95036727e59acc392e92b8effe6ee860e7d4e9 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Tue, 7 May 2013 18:35:25 -0700 Subject: [PATCH 21/34] Insteon: Extend Temporal Search Window for Duplicate Messages Apparently the prior settings were not catching duplicative device commands. Unfortunately extending the window results in numerous false positives for direct ACK messages. In order to prevent errors, only alllink related commands are examined for duplicative messages. --- lib/Insteon/BaseInterface.pm | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index d698e7b17..7c69f1dfa 100755 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -330,8 +330,8 @@ sub on_interface_info_received sub on_standard_insteon_received { my ($self, $message_data) = @_; - return if $self->_is_duplicate_received($message_data); my %msg = &Insteon::InsteonMessage::command_to_hash($message_data); + return if $self->_is_duplicate_received($message_data, %msg); if (%msg) { if ($msg{hopsleft} > 0) { @@ -477,8 +477,8 @@ sub on_standard_insteon_received sub on_extended_insteon_received { my ($self, $message_data) = @_; - return if $self->_is_duplicate_received($message_data); my %msg = &Insteon::InsteonMessage::command_to_hash($message_data); + return if $self->_is_duplicate_received($message_data, %msg); if (%msg) { if ($msg{hopsleft} > 0) { @@ -561,24 +561,25 @@ sub _aldb # Returns 1 if the received message is a duplicate message # See discussion at: https://github.com/hollie/misterhouse/issues/169 sub _is_duplicate_received { - my ($self, $message_data) = @_; + my ($self, $message_data, %msg) = @_; my $is_duplicate; + + #Duplicate testing is currently only performed on alllink related commands + #use on direct commands may result in false positives for ACK messages + return if (($msg{type} ne 'cleanup') && ($msg{type} ne 'alllink')); #Current time in milliseconds my $curr_milli = sprintf('%.0f', &main::get_tickcount); - #Key is the message with the hops_left portion zeroed out + # $key will be set to $message_data with max hops and hops left set to 0 my $key = $message_data; - substr($key,12,2) = substr($key,12,2) & 0xF3; - + substr($key,13,1) = 0; + #How long does it take to transmit each hop of this message my $message_time = (length($message_data) > 18) ? 108 : 50; - - #Get hops left - my $hops_left = hex(substr($message_data,13,1)) >> 2; - + #Add additional delay to catch PLM delays or out of sync messages - my $delay = ($message_time * ($hops_left+2)); + my $delay = ($message_time * ($msg{hops_left})) + 500; #Clean hash of outdated entries for (keys $$self{received_commands}){ @@ -591,7 +592,7 @@ sub _is_duplicate_received { if (exists($$self{received_commands}{$key})){ $is_duplicate = 1; ::print_log("[Insteon::BaseInterface] WARN! Dropped duplicate incoming message " - . $message_data) if $main::Debug{insteon}; + . $message_data . ", from " . $msg{source}) if $main::Debug{insteon}; } else { #Message was not in hash, so add it $$self{received_commands}{$key} = $curr_milli + $delay; From ef4956d030192e96dbc4648499953e20ae8fb674 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 8 May 2013 18:35:25 -0700 Subject: [PATCH 22/34] Insteon: Expand Duplicate Window for Messages Requiring an ACK Move function which prevented sequential set commands in less than 1 second to BaseObject Expand the logic of the duplicate message checker. Attempt to take into account whether the message received requires an ACK. If an ACK is required, attempt to catch duplicate messages which result from the failure of the device to receive the ACK. --- lib/Insteon/BaseInsteon.pm | 11 ++++++++++- lib/Insteon/BaseInterface.pm | 33 ++++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index 7782a3e66..519eec481 100755 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -289,7 +289,16 @@ sub is_acknowledged sub set_receive { my ($self, $p_state, $p_setby, $p_response) = @_; - $self->SUPER::set($p_state, $p_setby, $p_response); + my $curr_milli = sprintf('%.0f', &main::get_tickcount); + my $window = 1000; + if ($p_state eq $self->state && ($curr_milli - $$self{set_milliseconds} < $window)){ + ::print_log("[Insteon::BaseObject] Ignoring duplicate set " . $p_state . + " state command for " . $self->get_object_name . " received in " . + "less than $window milliseconds") if $main::Debug{insteon}; + } else { + $$self{set_milliseconds} = $curr_milli; + $self->SUPER::set($p_state, $p_setby, $p_response); + } } sub set_with_timer { diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 7c69f1dfa..046e58844 100755 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -563,10 +563,6 @@ sub _aldb sub _is_duplicate_received { my ($self, $message_data, %msg) = @_; my $is_duplicate; - - #Duplicate testing is currently only performed on alllink related commands - #use on direct commands may result in false positives for ACK messages - return if (($msg{type} ne 'cleanup') && ($msg{type} ne 'alllink')); #Current time in milliseconds my $curr_milli = sprintf('%.0f', &main::get_tickcount); @@ -577,9 +573,30 @@ sub _is_duplicate_received { #How long does it take to transmit each hop of this message my $message_time = (length($message_data) > 18) ? 108 : 50; - - #Add additional delay to catch PLM delays or out of sync messages - my $delay = ($message_time * ($msg{hops_left})) + 500; + + #What will the next max_hops count from this device be? + my $max_hops = ($msg{max_hops} < 3) ? $msg{max_hops} + 1 : 3; + #Need to add 1 "hop" for the initial transmit timeslot + $max_hops++; + + #Does the device expect an ACK? + if (!$msg{is_ack}) && !$msg{is_nack}) && $msg{type} ne 'alllink' + && $msg{type} ne 'broadcast') + { + #The device expects the PLM to ACK this command + #If the ACK is lost, a subsequent duplicate message would take + #double the max hops to arrive + $max_hops = $max_hops * 2; + #For non-ACK commands, it is assumed that a device could not respond to a + #PLM request in less than the max_hops since it would take double the + #max_hops for a message to be sent by the PLM and responded to by the device. + #As a result, legitimate duplicate messages should not be caught by this + #routine. + } + + #Delay is equal to the number of hops left, plus the maximum number of + #hops it would take for a subsequent resent message to arrive at the PLM. + my $delay = ($message_time * ($msg{hops_left} + $max_hops)); #Clean hash of outdated entries for (keys $$self{received_commands}){ @@ -591,6 +608,8 @@ sub _is_duplicate_received { #Check if the message exists if (exists($$self{received_commands}{$key})){ $is_duplicate = 1; + #Reset the time in case there are multiple duplicates + $$self{received_commands}{$key} = $curr_milli + $delay; ::print_log("[Insteon::BaseInterface] WARN! Dropped duplicate incoming message " . $message_data . ", from " . $msg{source}) if $main::Debug{insteon}; } else { From e8b8b0ecc419122e9a1b56e41b34620d61dd3e66 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 8 May 2013 18:35:25 -0700 Subject: [PATCH 23/34] Insteon: Fix typo in _is_duplicate_received --- lib/Insteon/BaseInterface.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 046e58844..349a6d114 100755 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -580,7 +580,7 @@ sub _is_duplicate_received { $max_hops++; #Does the device expect an ACK? - if (!$msg{is_ack}) && !$msg{is_nack}) && $msg{type} ne 'alllink' + if (!$msg{is_ack} && !$msg{is_nack} && $msg{type} ne 'alllink' && $msg{type} ne 'broadcast') { #The device expects the PLM to ACK this command From fb0d7d6fb564fb02a7c405b1d1e9cfaa77fcc789 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 8 May 2013 20:40:27 -0700 Subject: [PATCH 24/34] Insteon: More Adjustments to is_duplicate_received The message window is now calculated based on some basis in reality. The message window is the amount of time during which no proper message should be received. This depends on whether the message needs to be ACKed or not. If a message needs to be ACKed, then no message should be received from the device until: - All hops left expire - Max hops + 1 elapses for an ACK to be received - Max hops - less hops left for a new request to be sent If no ACK is required then no message should be received from the device until: -All hops left expire -Max hops for a PLM message to be received by the device (since MH is more sensitive to false positives in these types of messages, and since when duplicates occur here they normally occur very fast, we are more conservative for these types of messages) --- lib/Insteon/BaseInterface.pm | 56 ++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 349a6d114..a3d59c567 100755 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -558,45 +558,50 @@ sub _aldb 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 sub _is_duplicate_received { my ($self, $message_data, %msg) = @_; my $is_duplicate; - #Current time in milliseconds my $curr_milli = sprintf('%.0f', &main::get_tickcount); # $key will be set to $message_data with max hops and hops left set to 0 my $key = $message_data; substr($key,13,1) = 0; - - #How long does it take to transmit each hop of this message - my $message_time = (length($message_data) > 18) ? 108 : 50; - #What will the next max_hops count from this device be? - my $max_hops = ($msg{max_hops} < 3) ? $msg{max_hops} + 1 : 3; - #Need to add 1 "hop" for the initial transmit timeslot - $max_hops++; + #Standard = 50 millis; Extended = 108 millis; + #In practice requires 75% more + my $message_time = (length($message_data) > 18) ? 183 : 87; - #Does the device expect an ACK? + #Wait period before PLM can send ACK or next request + my $max_hops = $msg{hopsleft}; + if (!$msg{is_ack} && !$msg{is_nack} && $msg{type} ne 'alllink' && $msg{type} ne 'broadcast') { - #The device expects the PLM to ACK this command - #If the ACK is lost, a subsequent duplicate message would take - #double the max hops to arrive - $max_hops = $max_hops * 2; - #For non-ACK commands, it is assumed that a device could not respond to a - #PLM request in less than the max_hops since it would take double the - #max_hops for a message to be sent by the PLM and responded to by the device. - #As a result, legitimate duplicate messages should not be caught by this - #routine. + #ACK sent with same max hops plus 1 for initial timeslot + $max_hops += $msg{maxhops} + 1; + #Subsequent Reply, arrives in same number of hops + 1 for intial timeslot + $max_hops += ($msg{maxhops} - $msg{hopsleft}) + 1; + } else { + #Subsequent PLM request is sent with max hops + 1 for intial timeslot + $max_hops += $msg{maxhops} + 1; } - - #Delay is equal to the number of hops left, plus the maximum number of - #hops it would take for a subsequent resent message to arrive at the PLM. - my $delay = ($message_time * ($msg{hops_left} + $max_hops)); + + my $delay = ($message_time * $max_hops); #Clean hash of outdated entries for (keys $$self{received_commands}){ @@ -610,13 +615,16 @@ sub _is_duplicate_received { $is_duplicate = 1; #Reset the time in case there are multiple duplicates $$self{received_commands}{$key} = $curr_milli + $delay; + #Make a nicer name + my $source = $msg{source}; + my $object = &Insteon::get_object($msg{source}, $msg{group}); + $source = $object->get_object_name() if (defined $object); ::print_log("[Insteon::BaseInterface] WARN! Dropped duplicate incoming message " - . $message_data . ", from " . $msg{source}) if $main::Debug{insteon}; + . $message_data . ", from $source.") if $main::Debug{insteon}; } else { #Message was not in hash, so add it $$self{received_commands}{$key} = $curr_milli + $delay; } - return $is_duplicate; } From 40d15cddd7ce6ec42e2bdc950626daee1290973c Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 8 May 2013 20:50:14 -0700 Subject: [PATCH 25/34] Insteon: Add Time to Allow for ACK to Finish Transmitting MH already pauses to all hops_left time to expire. This adds a pause for messages that require ACKs to be sent to devices. MH doesn't send the ACKs, they are automatically sent by the PLM. However, anecdotal evidence suggests that the PLM doesn't abide by collision avoidance, ie it seems to permit a message to be sent immediately after an ACK without concern for allowing the ACK hops to complete. --- lib/Insteon/BaseInterface.pm | 54 +++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index a3d59c567..b7cec1755 100755 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -334,18 +334,23 @@ sub on_standard_insteon_received return if $self->_is_duplicate_received($message_data, %msg); if (%msg) { - if ($msg{hopsleft} > 0) { - &::print_log("[Insteon::BaseInterface] DEBUG2: Message received with $msg{hopsleft} hops left, delaying next " - ."transmit to avoid collisions with remaining hops.") if $main::Debug{insteon} >= 2; - $self->_set_timeout('xmit', $msg{hopsleft} * 100) #Standard msgs should only take 50 millis; - } - else { - #This prevents the majority of corrupt messages on aldb scans - #For some reason duplicate messages arrive with the same hop count - #My theory is that they are created by bridging the powerline and rf - #A mere 50 millisecond pause seems to fix everything. - $self->_set_timeout('xmit', 50); + my $wait_time; + my $wait_message = "[Insteon::BaseInterface] DEBUG3: Message received " + ."with $msg{hopsleft} hops left, "; + if (!$msg{is_ack} && !$msg{is_nack} && $msg{type} ne 'alllink' + && $msg{type} ne 'broadcast') { + #Wait for ACK to be delivered + $wait_time = $msg{maxhops}; + $wait_message .= "plus ACK will take $msg{maxhops} to deliver, "; } + $wait_time += $msg{hopsleft}; + #Standard msgs should only take 50 millis, but in practice additional + #time has been required. Extra 50 millis helps prevent dupes + $wait_time = ($wait_time * 100) + 50; + $wait_message .= "delaying next transmit by $wait_time milliseconds to avoid collisions."; + ::print_log($wait_message) if ($main::Debug{insteon} >= 3 && $wait_time > 50); + $self->_set_timeout('xmit', $wait_time); + # get the matching object my $object = &Insteon::get_object($msg{source}, $msg{group}); if (defined $object) @@ -481,18 +486,23 @@ sub on_extended_insteon_received return if $self->_is_duplicate_received($message_data, %msg); if (%msg) { - if ($msg{hopsleft} > 0) { - &::print_log("[Insteon::BaseInterface] DEBUG2: Message received with $msg{hopsleft} hops left, delaying next " - ."transmit to avoid collisions with remaining hops.") if $main::Debug{insteon} >= 2; - $self->_set_timeout('xmit', $msg{hopsleft} * 200) #Extended msgs take longer to deliver; + my $wait_time; + my $wait_message = "[Insteon::BaseInterface] DEBUG3: Message received " + ."with $msg{hopsleft} hops left, "; + if (!$msg{is_ack} && !$msg{is_nack} && $msg{type} ne 'alllink' + && $msg{type} ne 'broadcast') { + #Wait for ACK to be delivered + $wait_time = $msg{maxhops}; + $wait_message .= "plus ACK will take $msg{maxhops} to deliver, "; } - else { - #This prevents the majority of corrupt messages on aldb scans - #For some reason duplicate messages arrive with the same hop count - #My theory is that they are created by bridging the powerline and rf - #A mere 50 millisecond pause seems to fix everything. - $self->_set_timeout('xmit', 50); - } + $wait_time += $msg{hopsleft}; + #Standard msgs should only take 108 millis, but in practice additional + #time has been required. Extra 50 millis helps prevent dupes + $wait_time = ($wait_time * 200) + 50; + $wait_message .= "delaying next transmit by $wait_time milliseconds to avoid collisions."; + ::print_log($wait_message) if ($main::Debug{insteon} >= 3 && $wait_time > 50); + $self->_set_timeout('xmit', $wait_time); + # get the matching object my $object = &Insteon::get_object($msg{source}, $msg{group}); if (defined $object) From ea7b71edf613210bbf8960948be3896130899eb5 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 16 May 2013 17:35:00 -0700 Subject: [PATCH 26/34] Insteon: Catch Multiple Calls to Set_Receive in the Same Pass Resolves one of the three loopholes discovered by @peloy which permitted duplicate messages received in the same pass to be processed. Hopefully the final fix for hollie/misterhouse#169 --- lib/Insteon/BaseInsteon.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index 519eec481..2ac1bc13e 100755 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -291,7 +291,8 @@ sub set_receive my ($self, $p_state, $p_setby, $p_response) = @_; my $curr_milli = sprintf('%.0f', &main::get_tickcount); my $window = 1000; - if ($p_state eq $self->state && ($curr_milli - $$self{set_milliseconds} < $window)){ + if (($p_state eq $self->state || $p_state eq $self->state_final) + && ($curr_milli - $$self{set_milliseconds} < $window)){ ::print_log("[Insteon::BaseObject] Ignoring duplicate set " . $p_state . " state command for " . $self->get_object_name . " received in " . "less than $window milliseconds") if $main::Debug{insteon}; From 780ada228a5c61367ad977717a61ef2ef374d209 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 16 May 2013 17:45:15 -0700 Subject: [PATCH 27/34] Insteon: Catch Cleanup Messages Sent in the Same Pass as AllLink Messages Issue discovered by @peloy. MH should be ignoring the cleanup message received after an AllLink message. However, both messages were previously processed if they were received in the same pass. This resolves that discrepancy by checking what the state of the object will be at the start of the next pass. Partially fixes hollie/misterhouse#185 --- lib/Insteon/BaseInsteon.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index 7782a3e66..9fe8f38df 100755 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -703,7 +703,8 @@ sub _process_message } elsif ($msg{type} eq 'cleanup') { - if (lc($self->state) eq lc($p_state) and $$self{_pending_cleanup}){ + if (($self->state eq $p_state or $self->state_final eq $p_state) + and $$self{_pending_cleanup}){ ::print_log("[Insteon::BaseObject] Ignoring Received Direct AllLink Cleanup Message for " . $self->{object_name} . " since AllLink Broadcast Message was Received.") if $main::Debug{insteon}; } else { From 31e42e454993196d2515092da2518f90fc2351b0 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 16 May 2013 17:50:25 -0700 Subject: [PATCH 28/34] Insteon: Log Output if PLM Parser Drops a Duplicate Message As discovered by @peloy, the PLM Parser was silently dropping duplicate messages sequentially received in the same pass. This adds a debug3 message to the log when such messages are dropped. Partial fix for hollie/misterhouse#186 --- lib/Insteon_PLM.pm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 5441707b2..69953dbd2 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -597,7 +597,11 @@ sub _parse_data { { #ignore blanks.. the split does odd things next if $parsed_data eq ''; - next if $previous_parsed_data eq $parsed_data; # guard against repeats + 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; + next; + } $previous_parsed_data = $parsed_data; # and, now reinitialize $entered_rcv_loop = 1; @@ -750,4 +754,4 @@ sub firmware { } -1; \ No newline at end of file +1; From 295c276171d7475b3d1950712d910a49e62d39a4 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Thu, 16 May 2013 17:55:35 -0700 Subject: [PATCH 29/34] Insteon: Relocate PLM Decoder to Allow Decoding Multiple Messages Received at the Same Time PLM Decoder will not decode each message if multiple are received in one check data request. The only place that could create a hiccup, is if the PLM Parser has a bug. Since we now rely on the PLM Parser to first identify a valid message before asking the decoder to decode it, we rely on the PLM Parser to accurately discover messages. We still display the raw message, so the information is not lost, but we will not have a nice display of the message. I don't see this as a big deal, if the PLM Parser is missing messages we would likely have other problems anyways. Fixes the remainder of hollie/misterhouse#186 --- lib/Insteon_PLM.pm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 69953dbd2..9a5861b88 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -353,7 +353,6 @@ sub _parse_data { } &::print_log( "[Insteon_PLM] DEBUG3: Received PLM raw data: $data") if $main::Debug{insteon} >= 3; - &::print_log( "[Insteon_PLM] DEBUG4:\n".Insteon::MessageDecoder::plm_decode($data)) if $main::Debug{insteon} >= 4; # begin by pulling out any PLM ack/nacks my $prev_cmd = ''; @@ -389,6 +388,7 @@ sub _parse_data { $entered_ack_loop = 1; if ($parsed_data =~ /^($ackcmd)|($nackcmd)|($prefix{plm_info}\w{12}06)|($prefix{plm_info}\w{12}15)|($prefix{all_link_first_rec}15)|($prefix{all_link_next_rec}15)|($badcmd)$/) { + &::print_log( "[Insteon_PLM] DEBUG4:\n".Insteon::MessageDecoder::plm_decode($data)) if $main::Debug{insteon} >= 4; my $ret_code = substr($parsed_data,length($parsed_data)-2,2); my $record_type = substr($parsed_data,0,4); my $message_data = substr($parsed_data,4,length($parsed_data)-4); @@ -553,6 +553,7 @@ sub _parse_data { # is $parsed_data an accidental anomoly? (there are other cases; but, this is a good start) if ($parsed_data =~ /^($prefix{insteon_send}\w{12}06)|($prefix{insteon_send}\w{12}15)$/) { + &::print_log( "[Insteon_PLM] DEBUG4:\n".Insteon::MessageDecoder::plm_decode($data)) if $main::Debug{insteon} >= 4; # first, parse the content to confirm that it could be a legitimate ACK my $unknown_deviceid = substr($parsed_data,4,6); my $unknown_msg_flags = substr($parsed_data,10,2); @@ -597,6 +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; 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; @@ -754,4 +756,4 @@ sub firmware { } -1; +1; From be73691bc2578c0a99f0598549e86102c393a658 Mon Sep 17 00:00:00 2001 From: Eloy Paris Date: Wed, 15 May 2013 17:33:14 -0400 Subject: [PATCH 30/34] Return a web page instead of HTML code when visiting Phone Calls/VoiceMail Msgs -> Phone List (starting at the top IA5 page). --- web/bin/phone_list.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/bin/phone_list.pl b/web/bin/phone_list.pl index 4e7e20604..816f333db 100644 --- a/web/bin/phone_list.pl +++ b/web/bin/phone_list.pl @@ -69,8 +69,8 @@ sub rejected_call_list{ $html .= ""; print "dbx3\n"; - return $html; + return &html_page('', $html); } From d8dabd56b503bbe32d80f838291b007070c9b743 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Mon, 20 May 2013 20:28:21 -0700 Subject: [PATCH 31/34] Insteon: Move Failure_Reason into BaseObject from Message The active_message must be cleared before calling the failure_callback, otherwise we get into a strange loop with sync and scan links Once the active_message is cleared, we lose our ability to keep track of the failured message and corresponding failure_reason To resolve this, moved failure_reason from the message object into BaseObject. --- lib/Insteon/BaseInsteon.pm | 24 ++++++++++++++++++++++-- lib/Insteon/BaseInterface.pm | 8 ++++---- lib/Insteon/Message.pm | 20 -------------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/Insteon/BaseInsteon.pm b/lib/Insteon/BaseInsteon.pm index 7782a3e66..7bb29344e 100755 --- a/lib/Insteon/BaseInsteon.pm +++ b/lib/Insteon/BaseInsteon.pm @@ -660,7 +660,7 @@ sub _process_message { main::print_log("[Insteon::BaseObject] WARN: Now calling message failure callback: " . $p_setby->active_message->failure_callback) if $main::Debug{insteon}; - $p_setby->active_message->failure_reason('NAK'); + $self->failure_reason('NAK'); package main; eval $p_setby->active_message->failure_callback; main::print_log("[Insteon::BaseObject] problem w/ retry callback: $@") if $@; @@ -817,6 +817,26 @@ sub get_nack_msg_for { return $nack_messages{ $msg }; } +=item C + +Stores the resaon for the most recent message failure [NAK | timeout]. Used to +process message callbacks after a message fails. If called with no parameter +returns the saved failure reason. + +Parameters: + reason: failure reason + +Returns: failure reason + +=cut + +sub failure_reason +{ + my ($self, $reason) = @_; + $$self{failure_reason} = $reason if $reason; + return $$self{failure_reason}; +} + #################################### ### ##################### ### BaseObject ##################### @@ -1253,7 +1273,7 @@ Returns: nothing sub _get_engine_version_failure { my ($self) = @_; - my $failure_reason = $self->interface->active_message->failure_reason(); + my $failure_reason = $self->failure_reason(); main::print_log("[Insteon::BaseDevice::_get_engine_version_failure] DEBUG4: " ."failure reason: $failure_reason") if $main::Debug{insteon} >= 4; diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 3ed30426e..aadc2592c 100755 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -249,20 +249,20 @@ sub process_queue &main::print_log("[Insteon::BaseInterface] WARN! Unable to clear acknowledge for " . ((defined($failed_message->setby)) ? $failed_message->setby->get_object_name : "undefined")); } - + # clear active message + $self->clear_active_message(); # may instead want a "failure" callback separate from success callback if ($failed_message->failure_callback) { &::print_log("[Insteon::BaseInterface] WARN: Message Timeout: Now calling callback: " . $failed_message->failure_callback) if $main::Debug{insteon}; - $failed_message->failure_reason('timeout'); + $failed_message->setby->failure_reason('timeout') + if (defined($failed_message->setby) and $failed_message->setby->can('failure_reason')); package main; eval $failed_message->failure_callback; &::print_log("[Insteon::BaseInterface] problem w/ retry callback: $@") if $@; package Insteon::BaseInterface; } - - $self->clear_active_message(); $self->process_queue(); } } diff --git a/lib/Insteon/Message.pm b/lib/Insteon/Message.pm index 5d0ec292a..df0c6ae48 100755 --- a/lib/Insteon/Message.pm +++ b/lib/Insteon/Message.pm @@ -55,26 +55,6 @@ sub failure_callback return $$self{failure_callback}; } -=item C - -Stores the resaon for the most recent message failure [NAK | timeout]. Used to -process message callbacks after a message fails. If called with no parameter -returns the saved failure reason. - -Parameters: - reason: failure reason - -Returns: failure reason - -=cut - -sub failure_reason -{ - my ($self, $reason) = @_; - $$self{failure_reason} = $reason if $reason; - return $$self{failure_reason}; -} - sub send_attempts { my ($self, $send_attempts) = @_; From 0077b029150d99a77c68dbe934401d309bb76c5f Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Tue, 21 May 2013 17:35:35 -0700 Subject: [PATCH 32/34] Insteon: Call Message Decoder on Parsed_Data Message decoder only decodes the first message it finds So to decode all messages, we need to send it the parsed_data Closed #186 --- lib/Insteon_PLM.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 40bdb84a4..db50f4a0e 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -388,7 +388,7 @@ sub _parse_data { $entered_ack_loop = 1; if ($parsed_data =~ /^($ackcmd)|($nackcmd)|($prefix{plm_info}\w{12}06)|($prefix{plm_info}\w{12}15)|($prefix{all_link_first_rec}15)|($prefix{all_link_next_rec}15)|($badcmd)$/) { - &::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; my $ret_code = substr($parsed_data,length($parsed_data)-2,2); my $record_type = substr($parsed_data,0,4); my $message_data = substr($parsed_data,4,length($parsed_data)-4); @@ -553,7 +553,7 @@ sub _parse_data { # is $parsed_data an accidental anomoly? (there are other cases; but, this is a good start) if ($parsed_data =~ /^($prefix{insteon_send}\w{12}06)|($prefix{insteon_send}\w{12}15)$/) { - &::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; # first, parse the content to confirm that it could be a legitimate ACK my $unknown_deviceid = substr($parsed_data,4,6); my $unknown_msg_flags = substr($parsed_data,10,2); From e30b675d1a912896d415e1a66abdfefbc37d7454 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Tue, 21 May 2013 17:38:45 -0700 Subject: [PATCH 33/34] Insteon: Fix Bug in Link Scan Callback When Nack Received Clearing $current_scan_device was resulting in an undefined object. This would happen when a device's aldb was listed as out-of-sync. In that scenario, query_aldb_delta would be called, but it would immediately call the aldb_changed_callback without exiting the loop. The callback would then set the current_scan_device and call scan_link_table on that device. At this point, a _send_msg would be queued and the loop would begin to exit. As it exited it would fall all the way back to line 117 of Insteon.pm and clear the current_scan_device. This patch prevents that error, by not relying on the state of an otherwise global variable in the logic tree. --- lib/Insteon.pm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Insteon.pm b/lib/Insteon.pm index 14ccd1946..a911b13a1 100755 --- a/lib/Insteon.pm +++ b/lib/Insteon.pm @@ -114,13 +114,12 @@ sub _get_next_linkscan $current_scan_device->_aldb->{_aldb_unchanged_callback} = '&Insteon::_get_next_linkscan('.$skip_unchanged.')'; $current_scan_device->_aldb->{_aldb_changed_callback} = '&Insteon::_get_next_linkscan('.$skip_unchanged.', '.$current_scan_device->get_object_name.')'; $current_scan_device->_aldb->query_aldb_delta("check"); - $current_scan_device = undef; $checking = 1; } } else { $current_scan_device = $changed_device; } - if ($current_scan_device) + if ($current_scan_device && ($checking == 0)) { &main::print_log("[Scan all link tables] Now scanning: " . $current_scan_device->get_object_name . " (" From 09fee83b7285ca231674bce97e62802818c44e4e Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Fri, 24 May 2013 22:24:13 -0700 Subject: [PATCH 34/34] Insteon: Fix Hash Keys Error with Older Perl Versions Hopefully this fixes the error found by Jim see http://misterhouse.10964.n7.nabble.com/help-td18065.html --- lib/Insteon/BaseInterface.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Insteon/BaseInterface.pm b/lib/Insteon/BaseInterface.pm index 9d44f139a..1e8f03e47 100755 --- a/lib/Insteon/BaseInterface.pm +++ b/lib/Insteon/BaseInterface.pm @@ -614,7 +614,7 @@ sub _is_duplicate_received { my $delay = ($message_time * $max_hops); #Clean hash of outdated entries - for (keys $$self{received_commands}){ + for (keys %{$$self{received_commands}}){ if ($$self{received_commands}{$_} < $curr_milli){ delete($$self{received_commands}{$_}); }