From fe853c3282fa3364b7d76f8ca1ae04a985700c12 Mon Sep 17 00:00:00 2001 From: AndTH Date: Wed, 31 Jul 2013 01:18:03 -0400 Subject: [PATCH 1/3] Initial update for Insteon 2412N Added initial code to allow Insteon PLM to communicate with an ethernet connected PLM as well as serial. --- lib/Insteon_PLM.pm | 97 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 7 deletions(-) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 90e670463..c32624ea3 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -28,7 +28,8 @@ use Insteon::BaseInsteon; use Insteon::AllLinkDatabase; use Insteon::MessageDecoder; -@Insteon_PLM::ISA = ('Serial_Item','Insteon::BaseInterface'); +#@Insteon_PLM::ISA = ('Serial_Item','Socket_Item','Insteon::BaseInterface'); +my $PLM_socket = undef; my %prefix = ( @@ -71,6 +72,10 @@ Creates a new serial port connection. sub serial_startup { my ($instance) = @_; + my $PLM_use_tcp =0; + $PLM_use_tcp = $::config_parms{$instance . "_use_TCP"}; + if ($PLM_use_tcp == 1) {return;} + my $port = $::config_parms{$instance . "_serial_port"}; my $speed = 19200; @@ -89,6 +94,26 @@ sub new { my ($class, $port_name, $p_deviceid) = @_; $port_name = 'Insteon_PLM' if !$port_name; my $port = $::config_parms{$port_name . "_serial_port"}; + my $PLM_use_tcp =0; + $PLM_use_tcp = $::config_parms{$port_name . "_use_TCP"}; + my $PLM_tcp_host = 0; + my $PLM_tcp_port = 0; + + + if ($PLM_use_tcp == 1) + { + @Insteon_PLM::ISA = ('Socket_Item','Insteon::BaseInterface'); + $PLM_tcp_host = $::config_parms{$port_name . "_TCP_host"}; + $PLM_tcp_port = $::config_parms{$port_name . "_TCP_port"}; + &::print_log("[Insteon_PLM] 2412N using TCP, tcp_host=$PLM_tcp_host, tcp_port=$PLM_tcp_port"); + } + else + { + @Insteon_PLM::ISA = ('Serial_Item','Insteon::BaseInterface'); + $PLM_use_tcp =0; + &::print_log("[Insteon_PLM] 2412[US] using serial, serial_port=$port"); + } + my $self = new Insteon::BaseInterface(); $$self{state} = ''; @@ -96,11 +121,22 @@ sub new { $$self{state_now} = ''; $$self{port_name} = $port_name; $$self{port} = $port; + $$self{use_tcp} = $PLM_use_tcp; + $$self{tcp_host} = $PLM_tcp_host; + $$self{tcp_port} = $PLM_tcp_port; $$self{last_command} = ''; $$self{_prior_data_fragment} = ''; bless $self, $class; $self->restore_data('debug'); $$self{aldb} = new Insteon::ALDB_PLM($self); + if ($PLM_use_tcp == 1) + { + my $tcp_hostport = "$PLM_tcp_host:$PLM_tcp_port"; + + $PLM_socket = new Socket_Item(undef, undef, $tcp_hostport, 'Insteon PLM 2412N', 'tcp', 'raw'); + start $PLM_socket; + $$self{socket} = $PLM_socket; + } &Insteon::add($self); @@ -114,8 +150,10 @@ sub new { &::print_log("[Insteon_PLM] setting x10 xmit delay to: $$self{xmit_x10_delay}"); $self->_clear_timeout('xmit'); $self->_clear_timeout('command'); + - return $self; + + return $self; } =item C @@ -148,9 +186,30 @@ calles C. sub check_for_data { my ($self) = @_; + my $PLM_use_tcp =0; + #$PLM_use_tcp = $::config_parms{$self . "_use_TCP"}; + $PLM_use_tcp = $$self{use_tcp}; my $port_name = $$self{port_name}; - &::check_for_generic_serial_data($port_name) if $::Serial_Ports{$port_name}{object}; - my $data = $::Serial_Ports{$port_name}{data}; + my $data = undef; + if ($PLM_use_tcp == 1) + { + if ((not active $PLM_socket) and (($main::Second % 6) == 0) and $::New_Second) + { + &::print_log("[Insteon PLM] resetting socket connection"); + start $PLM_socket; + } + $data = said $PLM_socket; + #&::print_log("[Insteon PLM] data recieved $data") if $data; + + } + else + { + &::check_for_generic_serial_data($port_name) if $::Serial_Ports{$port_name}{object}; + $data = $::Serial_Ports{$port_name}{data}; + } + + + # always check for data first; if it exists, then process; otherwise check if pending commands exist if ($data) { @@ -208,6 +267,8 @@ Used to send X10 messages, generates an X10 command and queues it. =cut + + sub set { my ($self,$p_state,$p_setby,$p_response) = @_; @@ -341,9 +402,22 @@ Causes a message to be sent to the serial port. sub _send_cmd { my ($self, $message, $cmd_timeout) = @_; my $instance = $$self{port_name}; - if (!(ref $main::Serial_Ports{$instance}{object})) { + my $PLM_use_tcp = $$self{use_tcp}; + if ($PLM_use_tcp == 1) + { + #stop $PLM_socket; + if (not connected $PLM_socket) + { + &::print_log("[Insteon PLM] starting socket connection "); + start $PLM_socket; + } + } + else + { + if (!(ref $main::Serial_Ports{$instance}{object})) { print "WARN: Insteon_PLM serial port not initialized!\n"; return; + } } unshift(@{$$self{command_history}},$::Time); $self->transmit_in_progress(1); @@ -381,8 +455,16 @@ sub _send_cmd { &::print_log( "[Insteon_PLM] DEBUG3: Sending PLM raw data: ".lc($command)) if $main::Debug{insteon} >= 3; &::print_log( "[Insteon_PLM] DEBUG4:\n".Insteon::MessageDecoder::plm_decode($command)) if $main::Debug{insteon} >= 4; my $data = pack("H*",$command); - $main::Serial_Ports{$instance}{object}->write($data) if $main::Serial_Ports{$instance}; - + if ($PLM_use_tcp == 1) + { + my $port_name = $PLM_socket->{port_name}; + my $sentBytes = $main::Socket_Ports{$port_name}{sock}->send($data) if $main::Socket_Ports{$port_name}{sock}; + #print "Insteon_2412N $sentBytes bytes sent ($data)[$command]\n"; + } + else + { + $main::Serial_Ports{$instance}{object}->write($data) if $main::Serial_Ports{$instance}; + } if ($delay) { $self->_set_timeout('xmit',$delay * 1000); @@ -483,6 +565,7 @@ sub _parse_data { else { &::print_log("[Insteon_PLM] DEBUG3: Received PLM acknowledge: " + . $pending_message->to_string) if $main::Debug{insteon} >= 3; } From eee652c9cb7df6cfdbdbdcf7c5e382dbbe462aea Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Sun, 2 Feb 2014 13:25:00 -0800 Subject: [PATCH 2/3] InsteonIP: Attempt to Avoid Errors When Messages are Sent by Insteon IP Hub Messages are going to come in that MH will potentially see as acknowledging commands that it never sent. These changes attempt to avoid failures that might appear. I don't have a hub to test this on, so these are just guesses. --- lib/Insteon_PLM.pm | 50 ++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 4c5151a58..90f3a13ab 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -602,7 +602,9 @@ sub _parse_data { package main; eval ($self->active_message->success_callback); &::print_log("[Insteon_PLM] WARN1: Error encountered during ack callback: " . $@) - if $@ and $self->active_message->setby->debuglevel(1, 'insteon'); + if ($@ && $self->active_message->can('setby') + && ref $self->active_message->setby + && $self->active_message->setby->debuglevel(1, 'insteon')); package Insteon_PLM; } # clear the active message because we're done @@ -641,7 +643,9 @@ sub _parse_data { package main; eval ($callback); &::print_log("[Insteon_PLM] WARN1: Error encountered during ack callback: " . $@) - if $@ and $self->active_message->setby->debuglevel(1, 'insteon'); + if ($@ && $self->active_message->can('setby') + && ref $self->active_message->setby + && $self->active_message->setby->debuglevel(1, 'insteon')); package Insteon_PLM; } } @@ -915,27 +919,29 @@ sub _parse_data { { #ALL-Link Cleanup Status Report &::print_log( "[Insteon_PLM] DEBUG4:\n".Insteon::MessageDecoder::plm_decode($parsed_data)) if $self->debuglevel(4, 'insteon'); my $cleanup_ack = substr($message_data,0,2); - if ($cleanup_ack eq '15') - { - &::print_log("[Insteon_PLM] WARN1: All-link cleanup failure for scene: " - . $self->active_message->setby->get_object_name . ". Retrying in 1 second.") - if $self->active_message->setby->debuglevel(1, 'insteon'); - $self->retry_active_message(); - # except that we should cause a bit of a delay to let things settle out - $self->_set_timeout('xmit', 1000); - $process_next_command = 0; - } - else - { - 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 $self->active_message->setby->debuglevel(1, 'insteon'); - if (ref $self->active_message && ref $self->active_message->setby){ - my $object = $self->active_message->setby; - $object->is_acknowledged(1); - $object->_process_command_stack(); + if (ref $self->active_message){ + if ($cleanup_ack eq '15') + { + &::print_log("[Insteon_PLM] WARN1: All-link cleanup failure for scene: " + . $self->active_message->setby->get_object_name . ". Retrying in 1 second.") + if $self->active_message->setby->debuglevel(1, 'insteon'); + $self->retry_active_message(); + # except that we should cause a bit of a delay to let things settle out + $self->_set_timeout('xmit', 1000); + $process_next_command = 0; + } + else + { + 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 $self->active_message->setby->debuglevel(1, 'insteon'); + if (ref $self->active_message && ref $self->active_message->setby){ + my $object = $self->active_message->setby; + $object->is_acknowledged(1); + $object->_process_command_stack(); + } + $self->clear_active_message(); } - $self->clear_active_message(); } } elsif (substr($parsed_data,0,2) eq '15') From 39fd913c3ab279e358228a6458cc155b999868f7 Mon Sep 17 00:00:00 2001 From: KRKeegan Date: Wed, 12 Mar 2014 18:17:00 -0700 Subject: [PATCH 3/3] InsteonIP: Add documentation This completes the requirements for merging this into master. --- lib/Insteon_PLM.pm | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/Insteon_PLM.pm b/lib/Insteon_PLM.pm index 90f3a13ab..b684dc8d5 100644 --- a/lib/Insteon_PLM.pm +++ b/lib/Insteon_PLM.pm @@ -1057,6 +1057,36 @@ Identifies the port on which the PLM is attached. Example: Insteon_PLM_serial_port=/dev/ttyS4 +=item Insteon_PLM_use_TCP + +Setting this to 1, will enable MisterHouse to use a networked PLM such as the +Insteon Hub. This functionality seems fairly stable, but has not been +extensively tested. + +You will also need to set values for C and +C. + +There are a few quirks when using a networked PLM, they include: + +The communication may be slightly slower with the network PLM. In order to +prevent MisterHouse from clobbering the device it is recommended that you +set the C to 1 second. Testing may reveal that slightly +lower delays are also acceptable. + +Changes made using the hub's web interface will not be understood by MisterHouse. +Device states may become out of sync. (It is possible that future coding may +be able to overcome this limiation) + +=item Insteon_PLM_TCP_host + +If using a network PLM, set this to the IP address of the PLM. See +C. + +=item Insteon_PLM_TCP_port + +If using a network PLM, set this to the port address of the PLM. Generally, the +port number is 9761. See C. + =item Insteon_PLM_xmit_delay Sets the minimum amount of seconds that must elapse between sending Insteon messages