Switching lights on at dark and of at specific times

I have written the rule below to switch on lights when it is dark outside and switch them off on different times depending on the day (at 5 on Sundays, on other days at midnight). If I put the whole timing part of the rule in brackets it doesn’t switch the lights off, but if I do the lights don’t switch on. Any ideas?
Many thanks in advance.

rule "Hofbeleuchtung"
	when 
		Time cron "0 0 * ? * * *"	
	then
		//var Number minute = now.getMinuteOfHour
		var Number hour = now.getHourOfDay
		var Number day = now.getDayOfWeek
		
		if	(((day <=6) && (hour >=7) && (hour<=23)) || ((day ==7) && (hour >=7) && (hour<=4)) &&
			Luminance_Garden_Terrace.state < 80)
			{
			sendCommand(Light_Garden_Hof, ON)	
			}
		else 
			{
			sendCommand(Light_Garden_Hof, OFF)
			}
end		
Time cron "0 0 * ? * * *"	// "0 0 * * * ?" aka *:00:00 at **/**/**** would be more common

Maybe the rule will not trigger at all. You can check this by adding a logInfo:

logInfo("myLog","Rule Hofbeleuchtung triggered")

and the log line should emerge in openhab.log the moment, the rule is triggered.

if (
((day <=6) && (hour >=7) && (hour<=23)) // hour will never be more than 23
|| 
((day ==7) && (hour >=7) && (hour<=4)) // hour will never be more than 6 AND less than 5 at the same time
&& 
Luminance_Garden_Terrace.state < 80 // please use (Luminance_Garden_Terrace.state as Number).intValue instead
)
sendCommand(Light_Garden_Hof, ON) // whenever possible, please use the method instead of the action
                                  //Light_Garden_Hof.sendCommand(ON)

First I’ll recommend Design Pattern: Time Of Day which will let you centralize this sort of logic in case you do this sort of thing for other lights or activities. I think it will let you get rid of the polling cron expression and only have to trigger your rule based off of events which simplifies things significantly.

I don’t know what you mean by “If I put the whole timing part of the rule in brackets”.

I’ll assume you are having problems with the if condition. Since your only special case is Sunday lets treat it separately.

First, a question which you can answer with a quick log statement. Is Sunday 7, or is it 6 or is it 0? Make sure you know which because it drastically changes your conditional.

Let’s assume it is 7 (it is, I just looked it up). If I write your expression a little simpler for Sunday it reads:

if(day == 7 && hour <=4 && hour >= 7)

So the above will only return true if it is Sunday and the hour is between 00 and 04 and the hour is between 07 and 24. Wait, the hour cannot both be less than 4 and greater than 7 at the same time! There is your first error. It should be:

if(day == 7 && (hour <=4 || hour >= 7))

A little better, maybe a lot better. Do you intend for the light to be on between midnight and 04:00, off from 4:00AM to 7:00AM, then on from 7:00AM to midnight on Sundays? That is what the above will do. Do you mean 7pm, i.e. 19:00?

if(day == 7 && (hour <=4 || hour >= 19))

That seems more reasonable.

Now let’s treat the other days. I see the some of the same problems and more.

The hour >=7 will match Sunday, so that is plain wrong to start. Normally you would just use > 7 in a case like this. However, there are no days of the week > 7 so this whole clause does nothing (once corrected).

Next, we are already testing for Sunday so we don’t need to test for the rest of the days so we can drop the <= 6 entirely.

So assuming you want the light to be on between midnight and 06:00 and between 23:00 and midnight on the rest of the days then your if concerning time and day of the week becomes:

if((day == 7 && (hour <=4 || hour >=19) || (hour >=7 || hour <=23))

Everything is evaluated from the inside to the outside (just like parens in math) so checking the hours on Sunday evaluates first, then the day == 7, then the hours for the rest of the week.

Finally, you only want to turn on the light if the light is below a certain luminance. As written in your original though, the light will only turn on at < 80 on Sunday (assuming that that part of the conditional was right) because the && gets evaluated before the ||. So you need to group all the time conditionals into its own set of parens.

if(((day == 7 && (hour <= 4 || hour >= 19) || (hour >= 7 || hour <= 23)) && Luminance_Garden_Terrace.state as Number < 80)

OK, well that is correct, but it sure is kinda hard to read. I would recommend breaking it up a bit along these lines (actually I would recommend moving this all into a Time of Day DP approach but for completeness):

var lightState = OFF

// Sunday from 00:00 to 04:00 or 19:00 to 00:00
if(day == 7 && (hour <= 4 || hour >= 19)) lightState = ON

// Not Sunday from 00:00 to 07:00 or 23:00 to 00:00
else if(hour >= 7 || hour <= 23) lightState = ON

// Too bright outside?
if(Luminance_Garden_Terrace.state as Number > 80) lightState = OFF

Light_Garden_Hof.sendCommand(lightState)

It really isn’t more lines than what you have but by breaking it up it is much easier to read and understand and you don’t have to mess with all of those parens.

2 Likes

Thanks again, Rich!
I think the main issue was the order in which the “ifs” were evaluated. I have adjusted your suggestions and now get the behavior I was looking for:

  • The lights only switch on when it is dark (luminance value above 80)
  • On Sundays the lights must always be off between 5 and 7 in the morning
  • On all other days the lights must be off between 0 and 7 in the morning

In case somebody is interested this is the rule:

rule "Hofbeleuchtung"
	when 
		Time cron "10 0 * ? * * *"	
	then
		var Number hour = now.getHourOfDay
		var Number day = now.getDayOfWeek
		var lightState = OFF

		// Sunday from 00:00 to 05:00 or 7:00 to 00:00
		if(day == 7 && (hour <= 4 || hour >= 7)) lightState = ON

		// Mon-Sat from 07:00 to 00:00
		else if(hour >= 7 && hour <= 23) lightState = ON

		// Too bright outside?
		if(Luminance_Garden_Terrace.state as Number >= 80) lightState = OFF

	Light_Garden_Hof.sendCommand(lightState)
end	
1 Like