The intention was for this rule to not be active when I set the brightness above 31%, however it keeps switching the lights off after motion inactivity and appears to ignore the brightness.
Any suggestions as to why? I just set the Dim to 40% and its gone off as an example
smarthome:status FrontRoomDim1
40
var Timer FrontRoom_Timer = null
val Integer FrontRoom_TimeOut = 2
rule "Front Room motion detection turns ON Front Room Lights when Lux is less than 20, with a 2 Minute Inactivity Timer"
when
Item FrontRoomMotion changed to ON
then
if(FrontRoomMotion_Armed.state == ON && Motion_PartyMode.state != ON){
var int Dim_FrontRoom = 0
try {Dim_FrontRoom = Integer::parseInt(FrontRoomDim1.state.toString)} catch (Exception e) {}
if (FrontRoomLux.state < 20 && Dim_FrontRoom < 31) {
if (FrontRoom_Timer !== null) {
FrontRoomDim1.sendCommand("30")
logInfo("FrontRoom_Motion","Front Room Motion Timer rescheduled for " + Eye1_TimeOut + " minutes")
FrontRoom_Timer.reschedule(now.plusMinutes(FrontRoom_TimeOut))
} else {
logInfo("FrontRoom_Motion", "Front Room Motion Detected! Turning ON Front Room Lights")
FrontRoomDim1.sendCommand("30")
logInfo("FrontRoom_Motion","Front Room Timer created with " + Eye1_TimeOut + " minutes")
FrontRoom_Timer = createTimer(now.plusMinutes(FrontRoom_TimeOut))
[ |
if (FrontRoomMotion.state == ON) {
logInfo("FrontRoom_Motion","Front Room Motion triggered, but rescheduled again for " + FrontRoom_TimeOut + " minutes")
FrontRoom_Timer.reschedule(now.plusMinutes(FrontRoom_TimeOut))
} else {
logInfo("FrontRoom_Motion", "Front Room, No Motion Detected! Turning OFF Front Room Lights")
FrontRoomSw1.sendCommand("OFF")
FrontRoom_Timer = null
}
]
}
}
}
end
What is the value of that key variable Dim_FrontRoom? Bit of an odd parsing at work there.
You probably need a bit of a logic restructure here.
Though you only start off or reschedule the off-timer if dim<31, once itās started timing itās started, and when expires will turn off lights regardless.
Iād be inclined to just have the timer do its start/reschedule thing without taking any notice of ādimā. The only time that is important is when deciding to turn the lights off.
Okay, to answer that, here is how you do it now var Dim_FrontRoom = Integer::parseInt(FrontRoomDim1.state.toString)
Here is how you would do it inside the Timer code, which is I think what you are asking var Dim_FrontRoom = Integer::parseInt(FrontRoomDim1.state.toString)
Yep. Iām suggesting that you donāt test for dim<31 when starting or managing the Timer. Who cares, its only a timer. It doesnāt do anything until/unless it expires.
Youāre more interested in the code that runs when the Timer expires, and would normally turn the lights off. Here, you test if dim<31 to decide if you should turn the lights off or not.
This saves you the problem of working out what to do if the timer is already running and then you change to dim<31.
The lights are motion driven, they work 100% fine.
What fails, is when I set the dim value to something higher than 31%, the lights still go out.
The intention, was that if the Dim was higher than 31% then the lighting rule would not kick in. I.e it would not be motion driven, rather if it was above 31% it would remain ON indefinitely, unless A) I lowered the dim and motion was triggered, or B) I pressed the light switch
Try using the Expire binding for timer control, then checking the Dim value at timer expiration to conditionally turn light off or reset timer. Also see this thread ā Automation/Orchestration Design Patterns
Thatās easy, make a rule that triggers on dim changing, does your condition check, sees if a timer exists, and kills it.
Donāt be afraid to have many small rules doing little event-driven jobs.
If you use the expire technique for timing, you canāt cancel that.
You can make your expire-triggered rule check the conditions at its appointed time, and avoid turning off the light.
Same as Iāve been suggesting you do with the existing timer. (That would avoid any need to cancel that too.)
There is more than one way to do most things.
A question that may help choices: have you any use for āoccupancy sensingā?
If so, you may want to use use the same start/reschedule/timeout process for that as well, whether dark or daylight or manual mode.
The process would of course have conditional checks to see if should do lighting actions at each stage, but that becomes almost like an add-on to the main flow.
Could I not just modify the existing rule to this, doing a check if the DIM is lower than 31 before switching off?
EDIT: That doesnt work, accepts the code but brings up big errors
var Timer FrontRoom_Timer = null
val Integer FrontRoom_TimeOut = 2
rule "Front Room motion detection turns ON Front Room Lights when Lux is less than 20, with a 2 Minute Inactivity Timer"
when
Item FrontRoomMotion changed to ON
then
if(FrontRoomMotion_Armed.state == ON && Motion_PartyMode.state != ON){
var int Dim_FrontRoom = 0
try {Dim_FrontRoom = Integer::parseInt(FrontRoomDim1.state.toString)} catch (Exception e) {}
if (FrontRoomLux.state < 20) {
if (FrontRoom_Timer !== null) {
FrontRoomDim1.sendCommand("30")
logInfo("FrontRoom_Motion","Front Room Motion Timer rescheduled for " + Eye1_TimeOut + " minutes")
FrontRoom_Timer.reschedule(now.plusMinutes(FrontRoom_TimeOut))
} else {
logInfo("FrontRoom_Motion", "Front Room Motion Detected! Turning ON Front Room Lights")
FrontRoomDim1.sendCommand("30")
logInfo("FrontRoom_Motion","Front Room Timer created with " + Eye1_TimeOut + " minutes")
FrontRoom_Timer = createTimer(now.plusMinutes(FrontRoom_TimeOut))
[ |
if (FrontRoomMotion.state == ON) {
logInfo("FrontRoom_Motion","Front Room Motion triggered, but rescheduled again for " + FrontRoom_TimeOut + " minutes")
FrontRoom_Timer.reschedule(now.plusMinutes(FrontRoom_TimeOut))
}
else {
if(FrontRoomDim1 < 31)
logInfo("FrontRoom_Motion", "Front Room, No Motion Detected! Turning OFF Front Room Lights")
FrontRoomSw1.sendCommand("OFF")
FrontRoom_Timer = null
}
]
}
}
}
end
One of the ways to make code easier to read is by following conventions. In OH, the most common convention is:
Items start with an upper case letter and use camel case or _, e.g. MyItem, My_Other_Item
variables start with a lower case letter and use camel case, e.g. myVar
constants are all upper case letters with underscores where necessary, e.g. MY_VAL
I admit that I donāt do the last one in my Rules.
Anyway, when users like rossko57 or I see something named āDim_FrontRoomā, without any other information, we will assume it is an Item because it is following the Item naming convention.
Yes, so I can move that check to the timer section. Ill try this
rule "Front Room motion detection turns ON Front Room Lights when Lux is less than 20, with a 2 Minute Inactivity Timer"
when
Item FrontRoomMotion changed to ON
then
if(FrontRoomMotion_Armed.state == ON && Motion_PartyMode.state != ON){
if (FrontRoomLux.state < 20) {
if (FrontRoom_Timer !== null) {
FrontRoomDim1.sendCommand("30")
logInfo("FrontRoom_Motion","Front Room Motion Timer rescheduled for " + Eye1_TimeOut + " minutes")
FrontRoom_Timer.reschedule(now.plusMinutes(FrontRoom_TimeOut))
} else {
logInfo("FrontRoom_Motion", "Front Room Motion Detected! Turning ON Front Room Lights")
FrontRoomDim1.sendCommand("30")
logInfo("FrontRoom_Motion","Front Room Timer created with " + Eye1_TimeOut + " minutes")
FrontRoom_Timer = createTimer(now.plusMinutes(FrontRoom_TimeOut))
[ |
var int Dim_FrontRoom = 0
try {Dim_FrontRoom = Integer::parseInt(FrontRoomDim1.state.toString)} catch (Exception e) {}
if (FrontRoomMotion.state == ON) {
logInfo("FrontRoom_Motion","Front Room Motion triggered, but rescheduled again for " + FrontRoom_TimeOut + " minutes")
FrontRoom_Timer.reschedule(now.plusMinutes(FrontRoom_TimeOut))
} else {
if (Dim_FrontRoom < 31)
logInfo("FrontRoom_Motion", "Front Room, No Motion Detected! Turning OFF Front Room Lights")
FrontRoomSw1.sendCommand("OFF")
FrontRoom_Timer = null
}
]
}
}
}
end
The way you had your original rule, it blocked the turn-light-on motion response if the current dim > 31.
Presumably that was desirable, because you didnāt want the motion action dimming the lights after āmanualā setting.
You might want to reintroduce that check as well rather than instead of.