Time related heating depending on presence

Hi,
I tried for several months to have my heating change values related to the time but depending that on my presence.
So, I searched and read rules and defs over and over but can’t find what’s wrong with this rule:

rule "Flur Heizung"
	when
		Time cron "0 0 * * * ?"
		or
		Item Presence changed
	then
		var Number hour_Corridor = now.getHourOfDay
		//22-6
		if ((Presence.state == ON) && (hour_Corridor >= 22) && (hour_Corridor <=6))
			{ sendCommand(Heating_GF_Corridor, 5.0)
			}
		//6-12
		else if ((Presence.state == ON) && (hour_Corridor >= 6) && (hour_Corridor <=12))
			{ sendCommand(Heating_GF_Corridor, 16.0)
			}
		//12-18
		else if ((Presence.state == ON) && (hour_Corridor >= 12) && (hour_Corridor <=18))
			{ sendCommand(Heating_GF_Corridor, 12.0)
			}
		//18-22
		else if ((Presence.state == ON) && (hour_Corridor >= 18) && (hour_Corridor <=22))
			{ sendCommand(Heating_GF_Corridor, 16.0)
			}
end

Can anyone help please? Thanks a lot…

I am surely no rules specialist, but how can a value be greater than 22 AND at the same time lower than 6? Shouldn’t it be an OR relation instead of an AND relation?

There you’re right quite sure. :smiley:
I meant the time between 22.00h and 6.00h… think I should edit that.

This is 24 hour clock so it is a time range from 10 pm to 6 am. It is a range confition so it must be AND. With OR you will get true all the time.

Although this makes sense in a 24 hour clock context, it remains a fact that hour_Corridor as a number cannot be greater than 22 AND less than 6.

I guess you will have to rewrite the if statement as follows:

if ( (hour_Corridor >= 22) && (hour_Corridor <=24) ) || ( (hour_Corridor >= 0) && (hour_Corridor <= 6) )

I’m not rule expert either, but if I understand it correctly.

If your Presence is set to OFF (ie, not home), the sendCommand will never work when the Time Cron job runs??

What is the purpose of the Time Cron?

EDIT. Nevermind. I think i was misunderstanding myself. When your not home, it should not run.

@KjetilA I’ll try that tomorrow right after my night shift. Thanks a lot so far. :slight_smile:

@ptmuldoon I surely know that situations myself… :smiley:

If you will have other rules that may need to do different things based on time of day I recommend the following:

I’m pretty certain that @KjetilA has the solution. You can never have an hour that is both >=22 and <=6.

Assuming you didn’t apply the design pattern above, I think you can make this code a little easier to understand the following way:

if(Presence.state == ON){
    var Number hour = now.getHourOfDay

    var heat = 16.0
    if     (hour > 22 || hour <= 6)  heat = 5.0
    else if(hour > 12 && hour <= 18) heat = 12.0

    Heating_GF_Corridor.sendCommand(heat)
}

In the above we have just one if statement at the top to see if Presence.state == ON. If not then all the code is skipped. Now we don’t need to worry about presence in the rest of the rule.

Next I notice that the heating value passed for two of your time periods are the same. So I initialize a var to 16.0 and now only need to check for the other two time periods, reducing the number of conditionals by half.

1 Like

You are right. I overseen this, whole life with IFs and such mistake! If you know that clock is limited to 24 hours then this if could be flipped to IF (hour <= 6 || hour => 22). @rlkoshak pattern is also fine since it allows to use same signs for comparision.

@rlkoshak Wow, way shorter. :smiley: strongly believe that this is what I searched for.
One problem I had so far is that when coming home at 5:50 am the heating is at 5.0, but it’s not set to 16.0 at 6:01 am because nothing does change.
But if I use your IF construction under a cron expression, that should work, right?

Yes. The problem is you were using <= for all of your comparisons. So, for example, your system wouldn’t go to heating 16.0 until 7 am because at 6 am your first conditional will evaluate to True. The conditionals are evaluated in order.

To correct your comments in the original code:

		//22-6
		if ((Presence.state == ON) && (hour_Corridor >= 22) && (hour_Corridor <=6))
			{ sendCommand(Heating_GF_Corridor, 5.0)
			}
		//7-12
		else if ((Presence.state == ON) && (hour_Corridor >= 6) && (hour_Corridor <=12))
			{ sendCommand(Heating_GF_Corridor, 16.0)
			}
		//13-18
		else if ((Presence.state == ON) && (hour_Corridor >= 12) && (hour_Corridor <=18))
			{ sendCommand(Heating_GF_Corridor, 12.0)
			}
		//19-22
		else if ((Presence.state == ON) && (hour_Corridor >= 18) && (hour_Corridor <=22))
			{ sendCommand(Heating_GF_Corridor, 16.0)
			}

In my example, I adjusted to use > instead of >= to account for this. However, what I have may not be quite right.

As written it will:

23:00 to 06:59  set to 5.0
13:00 to 18:59  set to 12.0
All other times set to 16.0

If you want it to go to 5.0 at 06:00 you need to check for hour <= 5 which will give you:

23:00 to 05:59  set to 5.0
13:00 to 18:59  set to 12.0
All other times set to 16.0
1 Like

@rlkoshak :clap: :bow:
Thanks a lot.

1 Like

The complete rule now looks like this:

rule "Heizung"

when
	Time Cron "0 0 * * * ?"
	or
	Item Presence changed
then
	if (Presence.state == ON)	{
	var Number hour_Corridor = now.getHourOfDay

	var heat_Corridor = 16.0
	if	(hour_Corridor > 22 || hour_Corridor <= 5) heat_Corridor = 5.0
	else if (hour_Corridor > 11 && hour_Corridor <= 18) heat_Corridor = 12.0

	Heating_GF_Corridor.sendCommand(heat_Corridor)
	}
end

Does that look right?

Looks OK to me. I’d indent the code between the { } but I see nothing syntactically or logically wrong. As written:

  • 23:00 to 23:59 -> 5.0
  • 00:00 to 05:59 -> 5.0
  • 12:00 to 18:59 -> 12.0
  • All other times -> 16.0
1 Like

Me again. I gave it several tries, but actually, I still get the error ``` The argument ‘command’ must not be null or empty.

What am I doing wrong? :frowning:

If using the code exactly as above the error means that one of:

  • heat_Corridor is null
  • heat_Corridor is “”
  • heat_Corridor cannot be converted to the proper type to become Heating_GF_Corridor’s state.

The last is most likely.

So lets force the issue and explicitly define heat_Corridor as a Number.

var Number heat_Corridor = 16.0

Unfortunately, OH is a bit touchy when dealing with numerical values in Rules.

Edited my .rules, but the error still persists… :persevere:
Think I’ll need to get back so some more complex rule even I really loved this short one.

One final thing you can do is send the String as the state.

Heating_GF_Corridor.sendCommand(heat_Corridor.toString)

So meanwhile I tried it, getting another error:

Rule 'Heizung': An error occured during the script execution: The name 'Heating_GF_Corridor' cannot be resolved to an item or type.

Any ideas left?

Can you post your latest item definition and rules.