Is the joda part of my rule correct?

Hi,

I’m working on some Light automation for my hallway and landing. Basically if the Lux is below a certain level and there is movement the lights will come on. I’ve included a time element so that between 9am and 9pm the brightness is 80% and any other time the brightness is 50%.

When I did this with Domoticz I hade to have and elseif using OR instead of and but I’m not sure if I need to here.

Does this code look ok?

rule "lightsAutoH_ON"
when
	Item Security_Motion_H changed to ON
then
	if(Environment_Lux_H.state <= 15 && Light_Hue_White_H.state == 0 && now.getHourOfDay > 9 && now.getHourOfDay <= 21) {
		Light_Hue_White_H.sendCommand(80)
		}
	else if(Environment_Lux_H.state <=15 && Light_Hue_White.H.state == 0) {
		Light_Hue_White_H.sendCommand(50)
		}
end

rule	"lightsAutoH_OFF"
when
	Item Security_Motion_H changed to OFF or
	Item Environment_Lux_H received update
then
	if (gSafetyAlarms.state == OFF && Light_Hue_White_H.state > 0 && Environment_Lux_H.state > 20) {
		Light_Hue_White_H.sendCommand(0)
	}
end

Note you have a typo in your first Rule. Light_Hue_White**_**H.state

Often the quickest way to answer a question like this is to run it and see what happens. It looks OK to me but honestly I find these really long if clauses are hard to follow and understand.

So let’s apply some minor restructuring to maybe make it a little easier to understand.

rule "lightsAutoH_ON"
when
    Item Security_Motion_H changed to ON
then
    if(Environment_Lux_H.state > 15) return; // do nothing if lux is more than 15
    if(Light_Hue_White_H.state != 0) return; // do nothing if light's state is not 0

    val newState = if(now.getHourOfDay >= 9 && now.getHourOfDay < 21) 80 else 50 // If the hour is between 09:00 and 21:00 use a dimming value of 80 else use 50

    Light_Hue_White_H.sendCommand(newState)
end

rule "lightsAutoH_OFF"
when
    Item Security_Motion_H changed to OFF or
    Item Environment_Lux_H changed
then
    if(gSafteyAlarms.state != OFF) return; // do nothing if the safety alarms are off
    if(Light_Hue_White_H.state == 0) return; // do nothing if the light is at 0
    if(Environment_Lux_H.state <= 20) return; // do nothing if the lux is below 20

    Light_Hue_White_H.sendCommand(0)
end

By splitting up the big if clauses into short single if clauses that exit out of the Rule it makes what is going on a bit easier to understand. You don’t have to keep a complicated set of discrete math formulas in your brain to figure out what that one line does. Instead you can just march down the lines and look at them one at a time.

1 Like

Rich - Thank you for looking over my script.

I really appreciate you taking the time to re-write my script in a more concise manner. Having wrote mine and compared it to yours I can see how the change in logic and style make so much more sense.

Thanks again

1 Like

He is very good, I try and read as many post by Rich as possible. Just studying his replies has helped me a ton. Thanks Rich!

Still hoping for a YouTube tutorial, some of us need a visual aid from time to time :wink:

Thanks for the complements!

I can’t imagine I’ll ever start up YouTube videos but one never knows. Maybe someday I’ll have more time than I do now.

The ON rule is working exactly as I wanted but the OFF rule is not working.

The lights failed to turn off automatically but unfortunately I wasn’t able to look at the logs at the time.

Checking the logs today to ensure the indevidule items are functioning and they are

018-08-09 09:51:10.884 [DEBUG] [dclass.ZWaveBinarySensorCommandClass] - Sensor Type is MOTION

2018-08-09 09:51:10.887 [DEBUG] [dclass.ZWaveBinarySensorCommandClass] - NODE 6: Sensor Binary report, type=Motion, value=0

2018-08-09 09:51:10.907 [vent.ItemStateChangedEvent] - Security_Motion_H changed from ON to OFF


2018-08-09 09:55:51.287 [vent.ItemStateChangedEvent] - Environment_Lux_H changed from 34 to 31

2018-08-09 09:56:19.787 [vent.ItemStateChangedEvent] - Environment_Lux_H changed from 31 to 33

The only other item that affects the switching off is the group containing my smoke, heat and CO alarms. I grepped all the logs and this was returned;

./events.log:2018-08-05 02:06:58.644 [GroupItemStateChangedEvent] - gSafetyAlarms changed from NULL to OFF through gHeatAlarms
./events.log:2018-08-09 02:32:45.408 [GroupItemStateChangedEvent] - gSafetyAlarms changed from NULL to OFF through gHeatAlarms

So I reckon the rule is exiting because the group has a start up of NULL rather than OFF

Should I change the rule to

if(gSafetyAlarms.state == ON) return;

Thanks

It depends on how you want the NULL case to be handled. As written the NULL case is treated as ON. In other words, unless the states is explicitly OFF, assume the alarm is ON.

If you came the test as you indicate, the NULL case we’ll be treated as OFF. In other words, unless the states is explicitly ON, assume the alarm is OFF.

You will have to decide which is the more appropriate behavior.

That depends on the timing. At some point the alarm states changed to OFF at which point the rule should run.

It was still failing to turn the lights off even after the change so I reverted. I think the problem with the off script is that it can’t test for for motion or Lux in the one test.

The logic should be if not motion turn the lights off or if Lux is greater than 20 (regardless of movement) turn the lights off.

The current tests for no motion but because the lights dimmed and therefore lower than 20 Lux the lights stay on.

I’ve tried to split the motion and Lux into two but its failing.

Any advice?

 rule "lightsAutoL_ON"
when
    Item Security_Motion_L changed to ON
then
    if(Environment_Lux_L.state > 15) return; // do nothing if lux is more than 15
    if(Light_Hue_White_L.state != 0) return; // do nothing if light's state is not 0

    val newState = if(now.getHourOfDay >= 9 && now.getHourOfDay < 21) 80 else 1 // If the hour is between 09:00 and 21:00 use a dimming value of 80 else use 50

    Light_Hue_White_L.sendCommand(newState)
end

rule "lightsAutoL_OFF"
when
    Item Security_Motion_L changed to OFF 
then
	if(gSafetyAlarms.state != OFF) return; // Do nothing if Alarms active
	if(Light_Hue_White_L.state == 0)	// Do nothing if lights already off

	Light_Hue_White_L.sendCommand(0)
else if
    Item Environment_Lux_L changed
then
    if(gSafetyAlarms.state != OFF) return; // do nothing if the safety alarms are on
    if(Light_Hue_White_L.state == 0) return; // do nothing if the light is at 0
    if(Environment_Lux_L.state <= 20) return; // do nothing if the lux is below 20

    Light_Hue_White_L.sendCommand(0)
end

Then you need to trigger the Rule on changes to the Lux as well as the motion changing to OFF.

Download and use VSCode with the openHAB extension and then review the Rules syntax.

What you have written makes no sense syntactically. You should be seeing errors in your log file when you save this file and OH tries (and fails) to load it.

If you want to trigger a Rule based on more than one event you just list them all with or

when
    Item Security_Motion_L changed to OFF or
    Item Environment_Lux_L changed
then

If you want to have two different Rules, then you need to fully define two different Rules. the rule "Rule name" part is not options.

There is no such thing as an else if without a leading if statement and there is no such thing as an if or else if statement that doesn’t have an expression that evaluates to either true or false.

Yes it was giving errors.

In the meantime I did split it into two rules one for motion and one for lux.

It still doesn’t accurately turn off so I have commented out the gSafetyAlarm check for the time being.