Controlling KeypadLinc button LEDs

With the open-sourcing of Altsteon, I figured I would take a crack at the one remaining issue I have in my home automation setup: KeypadLinc button indicators getting out-of-sync with reality: light is off, but some KPL buttons controlling it remain lit. I’m an experienced C++ developer and so I’m hoping this is something I can help solve.

I’ve read on this forum in the past of some attempts to be able to control KeypadLinc button LEDs directly from Vera. These reports included KPL or PLC hangs – not really encouraging.

So I figured I’d report the results of my initial experiments. Using altsteon_cli and with the source as a reference, I’ve been able to reliably control the LEDs on one of my KeypadLincs. I haven’t experienced any hangs. The relevant commands are:

[ul][li] set_button_led 1 sets the button LEDs. Doesn’t work for button 1 (load), which goes on & off with the load instead.[/li]
[li] get_extended_devopts <button#> returns a lot of info, including bitmap state of button lights. Every button returns the bitmap of the whole device.[/li][/ul]

here is a 1-byte value with bit n corresponding to LED for button n (for an 8-button KPL, which is what I have. I believe 6-button KPLs simply omit buttons 2 & 8 ).

What this means is that there’s a syncronization problem here: if Vera were to retrieve the button-LED state as one command, alter it for the changed button, and then set that value as a second command, there’s a possibility some other button will have tried to update its state in between the two commands, and the resulting state would be incorrect. This may seem unlikely, except that a given scene is very likely to want to alter the LED state of multiple buttons.

So my feeling is that I should write some code in Altsteon daemon to include a model of the state of the button LEDs in the existing KPL model. This state would be updated with other KPL state by polling (like the other device state like dimmer level etc.), but more importantly, this modeled state could be used to provide an atomic “set button n LED on/off” command: this command would update the internal state, then set the KPL’s button state to match. With no synchronization issues.

My one real question, though, is: if I do this, am I likely to hit the same KPL or PLM hang issues that people have seen in the past? What sort of commands seemed to trigger these hangs?

Anyway, I’ve written much more than I intended as an introductory note here. I’d welcome any thoughts or additional information.

-Doug

Hi Doug,

I have modified the daemon to handle setting a single key.

I modeled it after the method “InsteonDevCat02::setLed”
I added “InsteonDevCat02::setLedIndiv” which takes a digit and a new value (0 or 1).

So far, I haven’t run into any hangs using the CLI.

I am no Vera UI expert, so I might let someone else add the service, etc. Any takers? :wink:

I do not have my altsteon setup right now. I had to disconnect my setup for the time being. I would like to help but my testing would be limited. You’ll need to add the command to the I_InsteonPlm.xml file for the child devices to execute and also add the service and action to the following files for the child devices, I_InsteonDimmerKpl.xml and I_InsteonRelayKpl.xml.

  • Garrett

Well, I think I have it working, at least for a DimmerKPL (I don’t have a RelayKPL to test, but it should be nearly identical).

My mods were:
S_InsteonOptions.xml: <stateVariable sendEvents="no"> <name>ButtonValue</name> <dataType>ui2</dataType> <defaultValue>0</defaultValue> <shortCode>buttonvalue</shortCode> </stateVariable> <stateVariable sendEvents="no"> <name>ButtonNumber</name> <dataType>ui2</dataType> <defaultValue>0</defaultValue> <shortCode>buttonnumber</shortCode> </stateVariable> ... <action> <name>SetLedIndiv</name> <argumentList> <argument> <name>targetButton</name> <direction>in</direction> <relatedStateVariable>ButtonNumber</relatedStateVariable> </argument> <argument> <name>newTargetValue</name> <direction>in</direction> <relatedStateVariable>ButtonValue</relatedStateVariable> </argument> </argumentList> </action>

I_InsteonDimmerKpl.xml: <action> <serviceId>urn:geektaco-info:serviceId:InsteonOptions1</serviceId> <name>SetLedIndiv</name> <run> setKPLled(lul_device, lul_settings) </run> </action>

I_InsteonPlm.xml:[code]
function setKPLled(lul_device, lul_settings)
local state = “0”
local button = lul_settings.targetButton
local targetdev = “”

if (lul_settings.newTargetValue==“1”) then
state = “1”
end

local devs = string.split(luup.devices[lul_device].id, “_”)
targetdev = devs[1]

plmSend(“setKPLled”, “"” … targetdev … "" set_button_led_indiv " … button … " " … state … “\n”)
end[/code]

I didn’t following any naming convention, etc.

Currently, the daemon tracks the state of the LED bitmap internally. It’s not perfect, since it doesn’t query it on startup, and also doesn’t handle toggles that are local to the keypadlinc.

I am also running the daemon on a Linux virtual machine, to make debugging easier. I am going to work tomorrow or this weekend on compiling a binary to run the daemon on Vera.

Great work. I would highly recommend that when getting all of this together, to follow fba’s naming conventions, etc to keep the code maintainable.

  • Garrett

PurdueGuy,

Awesome. This looks quite promising.

If you post your code for InsteonDevCat02::setLedIndiv I’ll play around with it this weekend as well. Or maybe you did post it and I’m just blind. I bet we can get it updating the daemon’s button bitmap when it gets other status from the KPL.

-Doug

I have the updating the daemon updating whenever “get_extended_devopts” is run, but no other time.

I will try to post the code later on. The mods were small.

[quote=“garrettwp, post:5, topic:175424”]Great work. I would highly recommend that when getting all of this together, to follow fba’s naming conventions, etc to keep the code maintainable.

  • Garrett[/quote]
    Garrett,

I will. I really didn’t think I would get the Vera side working, so I hacked it together, and was shocked I got it playing nicely at all! ;D

-Jacob

Here are my updates for the daemon.

Again, this only gets the LED state when “get_extended_devopts” is run.

It would need to be expanded to update the LED state from the controller:

  • on startup
  • on button-presses
  • ???

Edit: For completeness, here is the sequence for calling from LUUP: luup.call_action("urn:geektaco-info:serviceId:InsteonOptions1", "SetLedIndiv", {newTargetValue = "0",targetButton = "6"}, <DEVICE_ID>)

-Jacob

This is GREAT guys! It was on my list of things to work on! I’ll have to get it patched in and try it out.

If you intend to keep state in memory, it probably makes sense to just add the call to get extended devopts to the poll() method of that devcat. (You probably want to put it inside an areKpl() test so we don’t send commands that have less value on non-kpl devices.) If you add the check to poll() you should cover the start up case. When altsteon starts it applies a randomized poll interval to start with. While this doesn’t get your status as quickly as polling as soon as you come up, it does save you from flooding the queue up front, which could impact the responsiveness of the unit.

If you REALLY want to queue it as fast as you can on startup, you should put the command in the standard queue. That will at least minimize the delay a user would experience. If the daemon is in the process of running a command from the standard queue, that will finish before the priority queue is processed next. If your device has to retry a couple times, the delay can add up. So there is a balancing act. As an aside, just pushing the command back to the queue may cause things to respond a bit quicker. However, Insteon doesn’t seem to have any form of collision detection or avoidance. So, you may send the next command out while the response from the previous one is coming in. This will cause a delay and retransmission in the daemon which will add a minimum of 3 seconds, probably more. However, I do believe there are some tweaks that could be added to the queuing strategy that would improve some of the responsiveness in weird situations.

Catching the button presses that change LEDs should already mostly be in place. You will want to look for on and off events that use group numbers. The group numbers start with 1 and go up to 8 on the KPLs. On a 6 button KPL, group 1 & 2 are the On button and groups 7 & 8 are the off button. However, I have never seen a 6 button KPL push in group 2 or (IIRC) 8. So, you should be able to track the bitmap without needing to know how many buttons are in the kpl.

I’m actually thinking about augmenting/extending the code.

I realized when I want to add some calls that I was sometimes ending up with 4 or so writes to update the KPL (such as a fan - when updated from Vera, the KPL isn’t updated, and I had to turn 1 on and 3 off).

I’m thinking something along the lines of “setGroup” that takes:

  • bitmap of which bits are to be altered
  • bitmap of what those bits should be, ignoring all the rest

I’m going to work on adding that tonight/tomorrow.

Sounds great. Let me know when you are satisfied enough with the code to start letting it out to others. When that happens, send me a patch and we will get it out. I think a lot of people are looking forward to this functionality!

Any updates on this. I would love to be able to keep my keypadlic’s synced properly. Right now I have one of my buttons linked to a sceen that controls my garage door. It would be awesome if I could somehow link the led to reflect of the door is opened of closed.

Also, I would like to say thanks for everyone’s hard work on this.

If it wasn’t for fba’s dedication to getting Altsteon up and running, and everyone else’s work on expanding it’s capabilities, I would have probably sent back my Vera back. I love all the abilities that Vera has, but the default Insteon support was not very good. It was Altsteon and everyone else’s hard work that has made this such a great product.

I updated the code and a nightly build was produced last week.
http://forum.micasaverde.com/index.php/topic,15248.msg115847.html#msg115847