Simple Manual/Motion Switch Rules

Using OpenHAB 3.1, but new to the ECMA scripting in it.

I thought this would be easy, but it’s driving me nuts. I have a motion sensor, and a light, and all I want to do, is:

  1. If there is motion, the light comes ON for 5 minutes, then reverts to the manual state.
  2. If the switch is thrown, that becomes the manual state and any timer running from the motion is cancelled.

So, I started with something like:

var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.MotionLightNew");
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution"); 
var ZonedDateTime = Java.type("java.time.ZonedDateTime");

var previousState = itemRegistry.getItem("BackHallLightPower_Switch").getState()

function lambdaSchmamda() 
{
  logger.info("Motion Timer: Back to Previous: " + previousState);
  events.sendCommand('BackHallLightPower_Switch', previousState);
}

// Turn the light on
events.sendCommand('BackHallLightPower_Switch', 'ON');

// And start a timer
ScriptExecution.createTimer(ZonedDateTime.now().plusMinutes(5), lambdaSchmamda);

logger.info("Motion: Back Hall Light ON: Previous: " + previousState);

This works reasonably for the motion part. But now I need a manual “override” and am having a heck of a time figuring out how to do it. I’ve tried all sorts of things, and nothing “works”. My latest attempt was to try to add a rule that only triggers when the switch is manually toggled, which sets an Item state to the “manual state” of the switch:

var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.MotionLightNew");

// Record manual state
var previousState = itemRegistry.getItem("BackHallLightPower_Switch").getState();
itemRegistry.getItem("BackHallManualState").setState( previousState );
logger.info("Manual: toggle from " + previousState);

And when the motion timer runs out, I changed it to revert to the state of the “BackHallManualState” item.

But I have the problem that I can’t “manual toggle” because rule gets kicked when the motion script turns the light on or off. I don’t think I would need to cancel the timer if it always set the state back to the “manual” setting but I can’t find a way to set the BackHallManualState ONLY when the switch is physically toggled. I’ve tried adding another item that indicates the incoming “manual” state change should be ignored because it’s coming from the other script. That didn’t work out at all.

It just seems to me that this MUST have been solved by someone, it’s got to be one of the most common things! but my Google foo has failed me.

Is there a place somewhere that would contain a library of common rules like this? Can someone share THEIR solution? Any help would be great!

I just use the expire on the switch and do it like this:

Also some examples are here:

It’s a logic problem. With no ‘memory’, there is no way to distinguish between a manual switch operation and an operation that was commanded by some rule. Maybe there’s also a possibility of command from a UI - should you treat that as manual, too?

One approach might be to use the motion sensor itself as ‘memory’. Assuming the motion stays on for a few seconds, as is typical; if the switch changes state, AND motion sensor is active, it’s a good guess that was a change resulting from your automatic timing rule.
But that might not be true - if someone switches the light OFF they’ve probably just triggered motion too, yes? And you want to deal with that case.as well.

Your rule can treat the cases differently; if changed to ON and motion active, assume it was an auto response i.e. ignore it, the timer is already in charge.
If however we have changed to ON with no motion, or changed to OFF with or without motion, just kill any existing timer.

It does get more complicated if you now want to remember that there was a manual action, and maybe inhibit auto action for a while. Example, someone’s turned the light off deliberately and does not want the damned motion sensor to keep turning it on again.
You have to specify what you want carefully.

I use proxy items as stand-ins for memory. So there could be a proxy that turns on/off whenever the switch is triggered manually or via UI, which then becomes a check condition for the motion sensor. But as @rossko57 notes, this gets complicated with multiple inputs and behaviours. You really have to map it out.

For another example, what happens if you trigger the motion sensor by walking into the room and then want to keep it on? The simple solution would be to manually turn the light off and then back on again, but that’s annoying and inelegant.

Due to complexity like this, I only have one motion-sensor rule, which turns on the lights when I go to the kitchen at night. The rest of the time, my behaviour is too random for motion to be a reliable indicator of intent. And even then, there are times I have to manually turn the light on or off due to how the sensor is positioned.

You could also go down the path of detecting occupancy with your motion sensor, but if you search the community you’ll find that most people come to the same conclusion: occupancy detection is extremely hard, because humans are extremely unpredictable. You end up programming rules that are restrictive, and then change how you behave so as stay within those restrictions. Sometimes, it’s better for a light switch to just be a light switch…no matter how badly we want to automate it. :wink:

I think expire is best when you want something to happen 100% of the time, but I mostly end up using timers to allow flexibility and, more importantly, avoid confusing myself.

I use custom metadata for this type of switch memory. If the motion sensor triggers then it sets the light’s LastControl metadata to MOTION and turns on the light. Any use of the switch (or other manual control) unsets the metadata. When the motion sensor cancels its motion alarm then it only turns off the light if the LastControl metadata is still MOTION (which it also then unsets, of course).

2 Likes

Russ is right! Without a proxy item for each mode (e.g. manual, automatic) it’s never going to work properly.

In HABApp, there is a MultiModeItem that takes care of most of the ugly stuff for you.
For example the lights in my living room

  • turn on when there is movement and go off after a short time
  • turn on as long as the tv is on (but different color)
  • have a manual mode where I can turn them on and they stay on

Each state works independently and the final output is build whenever a mode changes.

@rpwong You should try it out some time - it really removes the complexity from the rules and makes it work properly.

1 Like

Maybe one day, but for now my DSL rules work exactly how I want them to work, so my motivation for changing anything is low. I enjoy these conceptual conversations about rules much more than actually coding rules. :wink:

1 Like

Hahaha! “Don’t mess with it if it ain’t broke”!

Dang! Now I’m going to have to go look at HABApp - I’d never heard of it before.

This might just work for what I’m thinking…good thought.

It does get extremely complex – and this is just for a dark hallway where I want the light to come on when you come in the garage door!

I’ve fallen back to a simple, “Light on with motion, and off 5 minutes after motion” which will cover 95% of the use cases. The only missing case I can think of is to keeping the light on regardless of motion, but that’s really rare anyway.

I’ll probably investigate other ideas more as a learning exercise than anything else.

that is actually one of the few situations where a motion sensor is useful for turning on and off lights. I use motion sensors to turn on the lights in situations when you walk into a room (the bathroom or closet for instance) and you want the light to come on, stay on for a few minutes and then shut it self off. Only problem is it can take a few seconds for the system to respond so the motion sensor usually needs to be placed somewhere to trigger it a few seconds ahead

That’s actually pretty similar to my kitchen nightlight. Works most of the time, doesn’t some of the time. Good enough for me.

Yeah, that’s why I get false-positives with my motion sensor. It has to be positioned such that it’ll turn on the light while I’m walking to the kitchen.

If you put a tilt sensor on your garage door, you could prime the system such that the light would only turn on (and then off after five minutes) if the garage door opened and then the motion sensor tripped.

Or even simpler, you could do away with motion and just have the light respond to operation of the garage door. That takes unpredictable motion out of the equation, so that if you go into the garage to get something the light will never turn off on you.

A really openhab-y way to do this is to use groups. The group represents the combined state of multiple trigger items, and there is one simple rule that copies the state of the group to the actual item that controls the light.

Here are the items:

Group LightTriggerGroup
Switch LightManualSwitch (LightTriggerGroup)
Switch LightMotionTrigger (LightTriggerGroup)
Switch RealLightControlSwitch

Bind the motion trigger to the motion sensor. Manual light switch is bound to nothing if you’re just using openhab to control it, or to a physical switch if you have one.

RealLightControlSwitch is the item that controls the actual physical light. This might be hidden from the ui as you want people using the LightManualSwitch instead to turn the light on.

The group is configured to be on if any of the members are on.

With this setup, all you need is a rule that is triggered when the group changes, and takes the group state and sends it as a command to the real control switch. The idea can be expanded with any number of different trigger items in the group without any additional complexity in the rules.

But this seems to work only for a very simple example.
If I want to manually dim the light to a certain percentage instead of the default that gets set through the movement sensor this approach will not work any more.

Yes, including dimmer levels certainly complicates it. Off the top of my head, I would say the group could change to a Number type and resolve to the Max of the member items. My suggestion was based on what the OP asked for, which was ON/OFF values, but the suggestion could be adapted to include the additional complexity you’re talking about. There might be better ways to do that though.

I find that in a hallway or closet or a simple scenario such as this, that setting the dimmer level based on the time of the day usually works well enough, for instance, if the hall light comes on in the middle of the night, use a lower dimmer level so as to not fry my eyeballs out

1 Like

Groups are not the way to go here because the aggregated state can only be described by a mathematical function and not by priority.
Real overlay (e.g. automatic and manual mode) can only be achieved if for every mode there is a dedicated state for every mode (e.g. item) and these states then get merged together to a final output.

Side node:
I know groups are used by many users a lot but imho it’s only because of openhabs lacking automation capabilities. It also dilutes the differentiation between definition of hardware description and automation logic.
I’ve hardly use them any more and if I use them it’s to group items together, not to aggregate a state.