How to Send INSTEON i2CS Modules Raw Commands (Python)

Posted on
Tue Aug 28, 2012 11:43 am
nsheldon offline
Posts: 2469
Joined: Aug 09, 2010
Location: CA

How to Send INSTEON i2CS Modules Raw Commands (Python)

Hey guys.

I'm converting my "BrightenWithRate" Indigo AppleScript attachment to an Indigo Plugin and I'd like to make it compatible with newer i2CS INSTEON modules, but I have no such modules with which to test the code.

My understanding is that i2CS modules will only respond to extended commands. I'm assuming that I'd need to test to see if the device is an i2CS module and use the Python method "indigo.insteon.sendRawExtended()" for those that are, even if the only data being sent is in the command bytes.

My question is how do I tell which dimmer modules are i2CS and which are not? I'm guessing I check the device version. Is there any place I can find a list of INSTEON dimmer devices and which versions are i2CS and which versions are not?

Posted on
Tue Aug 28, 2012 7:50 pm
matt (support) offline
Site Admin
User avatar
Posts: 21429
Joined: Jan 27, 2003
Location: Texas

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

Not all of the commands require extended + CRC for i2CS modules. For example, the normal ON/OFF/Set Brightness don't use it (off the top of my head I'm not sure if they fail to work if you use extended). I'm not sure about the BrightenWithRate command, and I'm not sure it is documented anywhere. I'd check it, but I don't have an i2CS dimmable module wired up right this second.

Presuming it does require it, here is the technique we use in the INSTEON Commands plugin for determining and i2CS module and switching to the extended version of the method:

Code: Select all
   dev = indigo.devices[someDevIdHere]
   devAddr = dev.address
   setFunc = indigo.insteon.sendRaw
   if dev.version >= 0x41:      # i2CS firmware requires extended command for settings changes
      setFunc = indigo.insteon.sendRawExtended
   setFunc(devAddr, [0x20, 0x06], waitUntilAck=True)


The exact firmware used by i2CS varies depending on the module type, but I think for most of the SwitchLinc/KeypadLinc line if it is 0x41 or higher than it is i2CS.

Image

Posted on
Wed Aug 29, 2012 2:32 am
nsheldon offline
Posts: 2469
Joined: Aug 09, 2010
Location: CA

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

Hey Matt.

Thanks! If the normal on/off/set brightness commands don't require the CRCs, the commands I'm sending may not either. I tried sending the commands to my existing i2 engine modules as extended commands (with all 14 data bytes set to zero) and though the i2 SwitchLinc Dimmers acknowledged the commands, they didn't actually do anything. As for the documentation of the brighten-with-rate command I'm using, I found out about it in the SmartLabs INSTEON Command Tables document (rev. 20070927a, Section 2.1.1, page 10), so I'll bet it's handled similarly (though maybe not consistently across all firmware versions) to the other on/off/set brightness commands.

Thanks for the code snippet. I actually checked out the INSTEON Commands plugin code too before posting the question, but wasn't sure if that version check applied to all modules or just specific ones.

Posted on
Wed Aug 29, 2012 4:22 pm
nsheldon offline
Posts: 2469
Joined: Aug 09, 2010
Location: CA

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

Another somewhat related question for you (or anyone who knows).

Is there a way to specify a timeout period with the sendRaw() method when using the "waitUntilAck=True" option? I'm using the waitUntilAck=True option so I can verify that a message was acknowledged by the device (and thus update the device status in Indigo appropriately). However, I'm finding that when executing the brighten-with-rate action from within an embedded Python script and no acknowledgement is received, Indigo is force-quitting the embedded executor host because it isn't responding in a timely manner. I'd rather my plugin (or the pluginHost) timeout the sendRaw reply than the embedded executor host dying (and thus loosing all queued embedded script execution requests).

Posted on
Wed Aug 29, 2012 4:26 pm
matt (support) offline
Site Admin
User avatar
Posts: 21429
Joined: Jan 27, 2003
Location: Texas

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

Nope, there is currently no way to specify a timeout. But only the embedded script executor should force the sandbox to quit after taking too long. So if you are doing this from a plugin that shouldn't be a problem?

Image

Posted on
Wed Aug 29, 2012 4:34 pm
nsheldon offline
Posts: 2469
Joined: Aug 09, 2010
Location: CA

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

Gocha.

What's happening is I'm testing the plugin functions via embedded Python within triggers (i.e. executing plugin actions using embedded Python code in trigger actions). So, does the embedded script executor start a new thread/sandbox for each trigger action that executes Python code? If that's the case, that shouldn't be a problem (other than the difficulty of figuring out which embedded trigger script was hanging when multiple embedded scripts have been called in succession). I was thinking that there was just one global embedded script executor process, in which case any other embedded scripts would be dropped due to one misbehaving script.

Posted on
Wed Aug 29, 2012 4:41 pm
jay (support) offline
Site Admin
User avatar
Posts: 18260
Joined: Mar 19, 2008
Location: Austin, Texas

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

There is only a single embedded script execution process and all embedded scripts are passed to it for execution. That's why there's a 10 second limit - so misbehaving embedded scripts don't cause other failures.

Plugins and external scripts run in their own process and the 10 second timeout period doesn't apply.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Wed Aug 29, 2012 4:41 pm
matt (support) offline
Site Admin
User avatar
Posts: 21429
Joined: Jan 27, 2003
Location: Texas

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

There is only one embedded script executor, so if it takes too long the Indigo Server will kill it and start a new one to prevent other scripts from being hung indefinitely.

But each plugin itself runs in its own process sandbox and can take as long as it needs. That is, your plugin should not be killed because its actions take too long (actions themselves occur in the plugin process space).

Image

Posted on
Wed Aug 29, 2012 4:59 pm
nsheldon offline
Posts: 2469
Joined: Aug 09, 2010
Location: CA

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

Thanks guys.

Actually, I'm not worried about the plugin process being killed. Here's the process I'm testing...

  1. Trigger 1 is executed
    1. Embedded script 1 begins execution with the code
      Code: Select all
      id = "com.nathansheldon.indigoplugin.DimmerExtender"
      plug = indigo.server.getPlugin(id)
      dev = indigo.devices['Hallway Light']
      if plug.isEnabled():
         plug.executeAction("setBrightness", dev.id, props={'brightness':100, 'rate':2})
  2. (1 second passes)
  3. Trigger 2 is executed
    1. Embedded script 2 begins executing with the code
      Code: Select all
      id = "com.nathansheldon.indigoplugin.DimmerExtender"
      plug = indigo.server.getPlugin(id)
      dev = indigo.devices['Family Room West Lamp']
      if plug.isEnabled():
         plug.executeAction("setBrightness", dev.id, props={'brightness':100, 'rate':2})
  4. (9+ seconds pass)
  5. Indigo Server kills the embedded script executor
    Code: Select all
      Error                           because embedded scripts execute sequentially they must complete their execution within 10 seconds.
      Error                           modify the script to exit quickly or convert it to an external file (not embedded).
      Stopping embedded script executor host (pid 96778)
      Error                           process (pid 96778) failed to quit after polite request -- forcing it to quit now
      Embedded script executor host started
  6. Neither embedded script 1 or 2 completes execution.

I'd like to avoid loosing embedded script 2 simply because a device didn't respond from embedded script 1. Is there some way I can abort a sendRaw() method call from within my plugin if it doesn't receive an acknowledgement within, say 8 seconds? Would I need to set up my own threading system within the plugin?

Posted on
Wed Aug 29, 2012 5:21 pm
matt (support) offline
Site Admin
User avatar
Posts: 21429
Joined: Jan 27, 2003
Location: Texas

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

Hmm... there is no way to cancel sendRaw() but I'm surprised it is taking 8+ seconds to fail. You can pass waitUntilAck=False to sendRaw() -- then it will return immediately. You won't get any ack/failure information back, however.

Which PowerLinc are you using? Could the problem be that the plugin's action is trying to send multiple INSTEON messages to an unresponsive device and the issue is the cumulative failure time? If so, then you could detect the first error and bail out of the action at that point, which would speed it up.

You can use python threading and a queue so that your plugin's action methods return immediately. That is what the EasyDAQ plugin does, for example. It isn't terribly difficult, but somewhat of a pain if the only problem is the INSTEON failures taking a long time.

Note this won't be a problem for your plugin actions that are created via UI, because IndigoServer won't try to wait for the action to complete nor will it try to kill the plugin.

Image

Posted on
Wed Aug 29, 2012 5:41 pm
nsheldon offline
Posts: 2469
Joined: Aug 09, 2010
Location: CA

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

matt (support) wrote:
Hmm... there is no way to cancel sendRaw()

Bummer. Okay, I'll try working around the long delay another way maybe.

matt (support) wrote:
but I'm surprised it is taking 8+ seconds to fail. You can pass waitUntilAck=False to sendRaw() -- then it will return immediately. You won't get any ack/failure information back, however.

Yea, I've started a number of threads in the forum before regarding long INSTEON timeouts. My workaround, which still works, is to insert a small (0.2 to 0.5 second) delay before sending wire commands that are triggered by other (esp. wireless) INSTEON commands. The consensus from those other threads is that the long delays are due to the moderately large number (54) of INSTEON devices on my setup and the PowerLinc's internal send timeout. Yea, I could set the waitUntilAck to False, but then I wouldn't be able to verify that the command was received by the device or not, potentially leaving the Indigo status out of sync with the actual state.

matt (support) wrote:
Which PowerLinc are you using? Could the problem be that the plugin's action is trying to send multiple INSTEON messages to an unresponsive device and the issue is the cumulative failure time? If so, then you could detect the first error and bail out of the action at that point, which would speed it up.

It's the PowerLinc 2413U. No, I don't have any code to try to re-send failed messages. The sendRaw() method is only being called once per action call.

matt (support) wrote:
You can use python threading and a queue so that your plugin's action methods return immediately. That is what the EasyDAQ plugin does, for example. It isn't terribly difficult, but somewhat of a pain if the only problem is the INSTEON failures taking a long time.

I might check out that code, though I'm not sure it'll be worth the time. We'll see. What about using the runConcurrentThread() method that's going to get called in a separate thread as a kind of queue manager? That way I wouldn't have to write my own threading code. :-)

Thanks again for all the help guys!

Posted on
Thu Aug 30, 2012 10:50 am
nsheldon offline
Posts: 2469
Joined: Aug 09, 2010
Location: CA

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

I changed the plugin so that it adds commands to a command queue list which is then executed by code in the runConcurrentThread method. This seems to work well and allows multiple commands to be enqueued by embedded scripts without them having to wait for each to complete (since the separate plugin thread for runConcurrentThread is dealing with it).

Posted on
Fri Aug 31, 2012 9:00 am
matt (support) offline
Site Admin
User avatar
Posts: 21429
Joined: Jan 27, 2003
Location: Texas

Re: How to Send INSTEON i2CS Modules Raw Commands (Python)

nsheldon wrote:
I changed the plugin so that it adds commands to a command queue list which is then executed by code in the runConcurrentThread method.

Yep -- that sounds like a good approach.

Image

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 4 guests