[OH2] [Astro Binding] [Feature Request] Between Sunset and Rise

Tags: #<Tag:0x00007f61701f3ac8> #<Tag:0x00007f61701f3a00> #<Tag:0x00007f61701f3938>

Hi Everyone,
hopefully this is the right way to post a FR. If not, please feel free to point me to the right direction.

Currently, i’ve build a rule which controls a switch item that simply tells me that it is between set and rise:
I Use this rule f.e. to open a rollershutter if that window is opened and this switch is set.

Or, if there is any other simpler way, drop a line how you get this done.

rule "Time between Set and Rise"
	when
		Time cron "0 */5 16-9 * * ?" or
		Item DEBUGSwitch received command ON
	then
	if (DEBUGSwitch.state == ON) {
		logInfo("Rule Start","Time between Set and Rise")
	}
	var SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
	var String SunRiseString = LocalSun_Rise_EndTime.state.toString()
	var String SRStr = SunRiseString.replace("T", " ")
	var Date SunRiseSDF = sdf.parse(SRStr)
	var String SRStrFmt = sdf.format(SunRiseSDF)
	var Date SunRiseDate = sdf.parse(SRStrFmt)
	
	var String SunSetString  = Sonne_Set_EndTime.state.toString()
	var String SSStr = SunSetString.replace("T", " ")
	var Date SunSetSDF = sdf.parse(SSStr)
	var String SSStrFmt = sdf.format(SunSetSDF)
	var Date SunSetDate = sdf.parse(SSStrFmt)
	
	var Date CurrentDateTime = new Date()
	var String CurrentDateTimeStr = sdf.format(CurrentDateTime)
	var Date CurrentDateTimeSDF = sdf.parse(CurrentDateTimeStr)
	
	if ( ( CurrentDateTimeSDF.getTime() < SunRiseDate.getTime() ) || ( CurrentDateTimeSDF.getTime() > SunSetDate.getTime() ) ) {
		sendCommand(TIME_BETWEEN_SET_AND_RISE, ON)
		if (DEBUGSwitch.state == ON) {
			logInfo("+++ Debug +++","TIME_BETWEEN_SET_AND_RISE.State: " + TIME_BETWEEN_SET_AND_RISE.state)
		}
	} else {
		sendCommand(TIME_BETWEEN_SET_AND_RISE, OFF)
		if (DEBUGSwitch.state == ON) {
			logInfo("+++ Debug +++","TIME_BETWEEN_SET_AND_RISE.State: " + TIME_BETWEEN_SET_AND_RISE.state)
		}
	}
	if (DEBUGSwitch.state == ON) {
		logInfo("Rule Ended","Time between Set and Rise")
	}
end

The thread at Astro binding to move switches at sunset/sunrise may give you further ideas. Have a look towards the end of the thread.

If you have one time period over the day you probably have several. The above shows how to set up a state machine driven by Astro and cron that sets a String Item with the time of day.

You have basically already implemented it but your conditionals can be made much simpler.

For example:

rule "Time between Set and Rise"
when
    System started or
    Channel 'astro:sun:home:rise#event' triggered START or
    Channel 'astro:sun:home:set#event' triggered START
then
    if(now.isAfter((LocalSun_Rise_EndTime.state as DateTimeType).calendar.timeInMillis &&
       now.isBefore((Sonne_Set_EndTime.state as DateTimeType).calendar.timeInMillis)){
        TIME_BETWEEN_SET_AND_RISE.sendCommand(ON)
    }
    else {
        TIME_BETWEEN_SET_AND_RISE.sendCommand(OFF)
    }
end

I didn’t include your DEBUGSwitch (note, the typical way one does this is set your log statements to logDebug and put that logger (in this case “+++ Debug +++” into Debug mode). See http://docs.openhab.org/administration/logging.html

Also, if you end up with more than just these two states, a switch statement is easier to read as illustrated in the Time of Day Design Pattern linked above.

Note in the above the rule only triggers when OH restarts or one of the given events occur. You don’t need to poll when you use these events.

1 Like

Hey mate, thats friggin awesome!
There so many ways to get things done, so if your not into coding java, it could get complicated.

Love this! Brilliant and simple solution. I’ll give it a try this evening.

Again, thanks!!!

Hey,
i just tried your rule but it seems not to be working:

2017-02-09 18:29:43.541 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'Time between Set and Rise': An error occured during the script execution: The name '<XFeatureCallImplCustom>.calendar' cannot be resolved to an item or type.

But it seems that i get the correct boolean states:

2017-02-09 18:43:37.571 [INFO ] [smarthome.model.script.+++ DEBUG +++] - now.isAfter Sonne_Set_StartTime: true
2017-02-09 18:43:37.571 [INFO ] [smarthome.model.script.+++ DEBUG +++] - now.isBefore LocalSun_Rise_StartTime: false

Well - at least close. As you can see, the state “is before SunRise” is false. thats because the astro binding dont update this until midnight. So i guess i’ll have to add 1 day to this?

I’m not sure what could be wrong. It looks right to me. Are you certain both DateTime Items have a state when this is running? If not what could be happening (if you are not using restoreOnStartup) is the rule is executing before the Astro binding is calculating the date times. You can try changing the triggers to:

Item LocalSun_Rise_EndTime received update or
Item Sonne_Set_Endtime received update or
Channel 'astro:sun:home:rise#event' triggered START or
Channel 'astro:sun:home:set#event' triggered START

Based on timing it might still generate one error in the logs (i.e. one of the Items is updated but the other one hasn’t been updated yes) but the rule will execute again when the second one gets calculated.

Or you can implement restoreOnStartup and it initialize the Items with whatever value they were in before the restart of OH.

You don’t have to wait until midnight. It should work but it appears the System started is not working for you.

no, thats not what i ment. The astro binding is showing the sunrise date for today - not for the next day. this is only updated after midnight. so the if statement will never be true, right?

i did got triggered the rule by the the channel events…

The calculations are done a little after midnight for that day so the if statement will evaluate to true without problem.

The reason to add the two updated triggers is so that TIME_BETWEEN_SET_AND_RISE gets updated when OH reboots or you chage the .items files. Otherwise the switch will be undefined until the next Channel event.

The above example from Rich does work as I tested it to increase my knowledge on channels. I had to change the sunrise and sunset names to match the names as used for Astro in the demo program (Sunrise_Time and Sunset_Time).

There is a however a missing bracket in the example which might be causing your error if you just copied it. There should be a single closing bracket after the ‘timeInMillis’ in the first line after the ‘then’ statement.

   if(now.isAfter((LocalSun_Rise_EndTime.state as DateTimeType).calendar.timeInMillis) &&

The only issue I found is that the command is run twice at each event.
Still don’t understand channels :slight_smile:

1 Like

Ah ok,

now the rule is working without errors. But the state is wrong :wink: Right now it is between Set and Rise but the switch isn’t on (i triggered the rule via a debug switch)

if(now.isAfter((Sonne_Set_EndTime.state as DateTimeType).calendar.timeInMillis) && now.isBefore((LocalSun_Rise_EndTime.state as DateTimeType).calendar.timeInMillis)){
        TIME_BETWEEN_SET_AND_RISE.sendCommand(ON)
    }
    else {
        TIME_BETWEEN_SET_AND_RISE.sendCommand(OFF)
    }

I cant find the reason why this is not working (well i know why it isn’t working, because now.isBefore((LocalSun_Rise_EndTime.state as DateTimeType).calendar.timeInMillis) is not true) - in my first post the if statement seems to be the same as rlkoshak ones…

if ( ( CurrentDateTimeSDF.getTime() < SunRiseDate.getTime() ) || ( CurrentDateTimeSDF.getTime() > SunSetDate.getTime() ) ) {

OK I didn’t realize you are looking for a night time flag, not a day time flag. Now I understand what you ment by the condition will never be true.

In that case you need to check if the time is between Set and midnight or between midnight and rise.

if((now.isAfter((Sonne_Set_EndTime.state as DateTimeType).calendar.timeInMillis) &&
   now.isBefore(now.withTimeAtStartOfDay.plusHours(24)) ||
   now.isAfter(now.withTimeAtStartOfDay) &&
   now.isBefore((LocalSun_Rise_EndTime.state as DateTimeType).calendar.timeInMillis) )

I really recommend looking at the Time Of Day design pattern as a more flexible approach than complicated if statements like the above.

1 Like

Yes, thats what im looking for. I use this f.e. if the rollershutter is closed (because its dark outside) but i want to go outside or just get some air, in case the time frame between set and rise is true, the roller shutter is automaticlly open if i open the window.

But anyways, i just realized that you wrote allready this piece here. I will try to use this to get things going on :wink:

Cheers mate!