If you got this working after only a couple of weeks with OH then you are doing great! This is an alternative way of implementing Design Pattern: Manual Trigger Detection using proxy Items that I haven’t written up yet.
From looking at your rules I’v ea couple of recommendations mostly having to do with style:
-
Use the sendCommand methods instead of the Actions: https://docs.openhab.org/configuration/rules-dsl.html#sendcommand-method-vs-action
-
Only use !== or === when one of the operands are
null
-
You can turn your first rule into a one liner:
then
LOCK_LTS_GF_OFFC.sendCommand(receivedCommand)
end
OK, with that out of the way I suspect you have these rules repeated over and over again, once for each room with a motion sensor. You might be able to make these Rule generic using triggeringItem, Design Pattern: Associated Items, and Design Pattern: Working with Groups in Rules.
For example, here is how I detect a manual command to a light and set an override flag (I use timestamps instead of a proxy Item).
// Theory of operation: any change in the relevant lights that occur more than five seconds after
// the change to DAY or after a change caused by cloudy is an override
rule "Watch for overrides"
when
Item aFrontLamp changed or
Item aFamilyLamp changed
then
// wait a minute before reacting after vTimeOfDay changes, ignore all other times of day
if(vTimeOfDay.state != "DAY" || vTimeOfDay.lastUpdate("mapdb").isAfter(now.minusMinutes(1).millis)) return;
// Assume any change to a light that occurs more than n seconds after time of day or cloudy is a manual override
val n = 5
val causedByClouds = vIsCloudy.lastUpdate("mapdb").isAfter(now.minusSeconds(n).millis)
val causedByTime = vTimeOfDay.lastUpdate("mapdb").isAfter(now.minusSeconds(n).millis)
if(!causedByClouds && !causedByTime) {
logInfo(logName, "Manual light trigger detected, overriding cloudy control for " + triggeringItem.name)
postUpdate(triggeringItem.name+"_Override", "ON")
}
end
// Thoery of operation: If it is day time, turn on/off the weather lights when cloudy conditions
// change. Trigger the rule when it first becomes day so we can apply cloudy to lights then as well.
rule "Turn on lights when it is cloudy"
when
Item vIsCloudy changed or
Item vTimeOfDay changed
then
// We only care about daytime
if(vTimeOfDay.state != "DAY") return;
// give the time of day time to complete
if(triggeringItem.name == "vTimeOfDay") Thread::sleep(1000)
logInfo(logName, "It is DAY and cloudy changed: " + vIsCloudy.state.toString)
// Apply the cloudy state to all the lights in the weather group
gLights_ON_WEATHER.members.forEach[ l |
val overrideName = l.name+"_Override"
val override = gLights_WEATHER_OVERRIDE.members.findFirst[ o | o.name == overrideName ] as SwitchItem
if(override.state != ON && l.state != vIsCloudy.state) l.sendCommand(vIsCloudy.state as OnOffType)
logInfo(logName, l.name + if(override.state == ON) " is overridden" else " is not overridden")
]
end
So for you the rule could look something like the following:
rule "Manual turn on light"
when
Item ALEXA_LTS_GF_OFFC received command or
Item ALEXA_blah_blah_blah received command or
...
then
sendCommand(triggeringItem.name.replace("ALEXA", "LOCK"), receivedCommand)
end
Wow that’s satisfying. A one liner that handles ALL of your locking of the lights and all you have to do is add triggers (and keep up this naming convention). Note this is one of the few cases where using the sendCommand Action is appropriate.
You could do the same for the motion sensor rule.
rule "Motion Sensors"
when
Item MS_GF_OFFC changed or
Item MS_blah_blah changed or
...
then
val lock = LightLocks.members.findFirst[ l | l.name == triggeringItem.name.replace("MS", "LOCK_LTS") ]
// only send a command if the lock isn't ON
if(lock.state != ON){
sendCommand(triggeringItem.name.replace("MS", "LTS"), triggeringItem.state)
}
end
Note that I’m not certain this will work for you as there are some different Items that you are using in your example Rule that do not follow the naming pattern. You would also need to put all your locks into a Group so you can get access to them using the findFirst trick.
I leave it to you to determine if this approach will work for you.