I’m mainly looking at OpenHAB for support of the advanced functionality in the HomeSeer HS-WD100+ in-wall dimmers. Specifically, they have multi-tap functionality supporting four commands in addition to the generic On/Off function. For example, my pool light switch is out by the shed; wouldn’t be nice if I could just double-tap the switch at the back door instead?
Here’s one way of making it work in OpenHAB 2…
Out of the Box
OpenHAB fully recognizes the HomeSeer switches. When you include one into your network, you’ll get two channels: Dimmer and Scene Number. The Dimmer channel is self-explanatory; less obviously, however, you recognize multi-taps by looking at the Scene Number.
Put simply, the Scene Number is a floating point number with one of six possible values:
Scene # | Meaning |
---|---|
1.0 | Top button pressed |
1.3 | Top button double-tap |
1.4 | Top button triple-tap |
2.0 | Bottom button pressed |
2.3 | Bottom button double-tap |
2.4 | Bottom button triple-tap |
Simple enough; you just examine the number, and you know what happened at the switch. So how do you make that work with OpenHAB?
Configuring An Item
First, you need to add an item for your switch’s Scene Number
channel. I recommend doing this manually; the “simple linking” stuff
in OH2 is nice, but you can’t name your items. To add it manually, you
copy the channel name (zwave:device:9635f4cc:node2:scene_number
in
the example above) and paste it into an items file in a line that
looks like this:
Number light_office_scene "Office Switch Scene" { channel="zwave:device:9635f4cc:node2:scene_number" }
This item can then be used in your rules, both to detect updates and changes, and to simply see what the last action was.
Helpful Functions
It’s hard to keep the number-to-meaning mapping straight in your head, so let’s render that unnecessary. OpenHAB’s code reuse facilities are nearly non-existent, so we’ll hack around it using a stored lambda function. Just place this at the top of the rules file where you define your multi-tap actions:
import org.eclipse.xtext.xbase.lib.Functions.*
import org.eclipse.xtext.xbase.lib.Procedures.*
val Function5 hs100Scene = [
NumberItem sceneId,
Procedure0 doubleOn,
Procedure0 doubleOff,
Procedure0 tripleOn,
Procedure0 tripleOff |
switch(sceneId.state) {
case 1.3: { if (doubleOn != null) doubleOn.apply() }
case 2.3: { if (doubleOff != null) doubleOff.apply() }
case 1.4: { if (tripleOn != null) tripleOn.apply() }
case 2.4: { if (tripleOff != null) tripleOff.apply() }
}
]
When called, this function will examine the supplied Scene Number object, and then call one (and ONLY one) of the supplied lambda functions. Which one depends on which action was detected. If you don’t want to support an action on a given switch, just pass null for that argument.
Sound Complicated? It may seem it, but wait ’til you see what it does for you…
Applying Scenes
Once you’ve defined your item and the above helper function, all you need to do is define a rule on the Scene Number item. For example, this rule currently exists in my system, in the same file as the above function:
rule "Office Scenes"
when
Item light_office_scene received update
then
hs100Scene.apply(light_office_scene,
[| // double tap on
sendCommand(gLivingRoom, OFF)
sendCommand(light_office, ON)
],
[| // double tap off
sendCommand(gLivingRoom, ON)
sendCommand(light_office, OFF)
],
null, // no triple tap on
null // no triple tap off
)
end
It should be fairly easy to tell what this does: if you double-tap the top of the paddle, it will turn the office lights on and the living room lights off. If you double-tap the bottom of the paddle, it does the reverse. Triple tap would simply be a matter of adding two more lambdas in place of the nulls – but I don’t really have any other use for the feature on that particular switch.
See? It’s easy!
Notes
Just a few closing thoughts:
- Remember: you can’t use the hs100Scene function outside the rules file it was defined in.
- You almost certainly want to use a “received update” trigger instead of a “changed” trigger. If you use “changed”, you’ll only receive events if the scene number is different from the last one it saw. This is a recipe for sketchy behavior in most circumstances.
- This will likely work with the HS-WS100+ also, but I haven’t verified it.
- I don’t know where the x.1 and x.2 scene numbers went. It’s a mystery!
- I haven’t tinkered enough with lambdas in OpenHAB to know how the scoping works; you may or may not have issues accessing variables defined in the rule body. Consider it an experiment!
- You could easily break this into four functions (
eg.
onDoubleTap.apply(sceneObject, [| ... ])
). This could make things more readable.
The single-file scope is the biggest issue I see with this. If OpenHAB would implement a way to define global helper functions, I would be far happier with the system. It is, so far, the one glaring limitation.
In the mean time, however, my goal is accomplished: the HomeSeer switches are fully usable! When my pool guys finish fixing the light (it’s an ongoing saga involving a leak and crappy electrical conduit – don’t ask), and as soon as HomeSeer has the appropriate switches back in stock, I’ll be able to control my pool light from the back door instead of traipsing out to the shed to flip the switch.
Handy, right?
Updates:
- 2017/03/05: Fix a typo in the labmda code and a mental name collision in the article. Nothing you’d probably notice.