[Deprecated] Design Pattern: Time Of Day

As stated in the first link in the DP that describes the purpose of a DP, it is not and never was intended to be a complete copy and paste solution. The code above and the table that goes with it is intended to be just an example. As an example, it should avoid unnecessary complexities. Those complexities that are specific to your part of the world are very much “an exercise left to the student” to implement.

I’m not inclined to add these complexities to the example as they don’t really add anything in terms of explanation of the DP. They are just more of the same sorts of things already demonstrated.

But, even in my part of the world sunrise will happen before 06:00. And during those times of year, the MORNING state simply never occurs.

NOTE: There is a new capability in OH 2.5 M2 or later (I think) called Ephemeris which will let you define and use type of day type information (e.g. weekend, workday, etc.) in your Rules. See Ephemeris binding?.

2 Likes

Thanks for the tips, the logInfo line fixed the error. I also created the thing called astro:sun:minus90 (sorry for not seeing this myself :slight_smile: )

I rebooted the OpenHab but still I am not seeing the correct current time of the day :frowning:.

The log now looks like this:

2019-10-12 12:59:29.306 [vent.ItemStateChangedEvent] - vMorning_Time changed from NULL to 2019-10-12T06:00:00.000+0200

2019-10-12 12:59:29.328 [vent.ItemStateChangedEvent] - vNight_Time changed from NULL to 2019-10-12T23:00:00.000+0200

2019-10-12 12:59:29.331 [vent.ItemStateChangedEvent] - vBed_Time changed from NULL to 2019-10-12T00:00:00.000+0200

==> /var/log/openhab2/openhab.log <==

2019-10-12 12:59:33.679 [INFO ] [b.handler.EspMilightHubBridgeHandler] - Sucessfully subscribed to milight/states/#

==> /var/log/openhab2/events.log <==

2019-10-12 12:59:34.538 [hingStatusInfoChangedEvent] - ‘zwave:device:a5af8125:node6’ changed from OFFLINE (BRIDGE_OFFLINE): Controller is offline to ONLINE

2019-10-12 12:59:34.545 [hingStatusInfoChangedEvent] - ‘zwave:serial_zstick:a5af8125’ changed from OFFLINE (BRIDGE_OFFLINE): Controller is offline to ONLINE

2019-10-12 12:59:34.552 [me.event.ThingUpdatedEvent] - Thing ‘zwave:serial_zstick:a5af8125’ has been updated.

2019-10-12 12:59:34.555 [hingStatusInfoChangedEvent] - ‘zwave:device:a5af8125:node5’ changed from OFFLINE (BRIDGE_OFFLINE): Controller is offline to ONLINE

2019-10-12 12:59:46.972 [hingStatusInfoChangedEvent] - ‘zwave:device:a5af8125:node5’ changed from ONLINE to ONLINE: Node initialising: REQUEST_NIF

2019-10-12 12:59:47.424 [vent.ItemStateChangedEvent] - SW_Buitenlamp changed from NULL to 0

2019-10-12 12:59:47.692 [hingStatusInfoChangedEvent] - ‘zwave:device:a5af8125:node5’ changed from ONLINE: Node initialising: REQUEST_NIF to ONLINE

2019-10-12 12:59:59.360 [hingStatusInfoChangedEvent] - ‘ntp:ntp:local’ changed from ONLINE to REMOVING

2019-10-12 12:59:59.372 [hingStatusInfoChangedEvent] - ‘ntp:ntp:local’ changed from REMOVING to REMOVED

2019-10-12 12:59:59.421 [hingStatusInfoChangedEvent] - ‘ntp:ntp:local’ changed from REMOVED to UNINITIALIZED

2019-10-12 12:59:59.437 [hingStatusInfoChangedEvent] - ‘ntp:ntp:local’ changed from UNINITIALIZED to UNINITIALIZED (HANDLER_MISSING_ERROR)

==> /var/log/openhab2/openhab.log <==

This is my things file:

Thing astro:sun:minus90 “Offset -90” [geolocation=“12.34578,1.23456,123”, interval=300]{
Channels:
Type rangeEvent : set#event [
offset=-90
]
Type start : set#start [
offset=-90
]
Type end : set#end [
offset=-90
]
}

Thing astro:sun:local “Local Sun” [geolocation=“12.34578,1.23456,123”, interval=300]{
Channels:
Type rangeEvent : rise#event [
offset=-0
]
Type start : rise#start [
offset=-0
]
Type rangeEvent : set#event [
offset=-0
]
Type end : rise#end [
offset=-0
]
}

This my time of the day rules file:
rule “Calculate time of day state”
when
System started or // run at system start in case the time changed when OH was offline
Channel ‘astro:sun:local:rise#event’ triggered START or
Channel ‘astro:sun:local:set#event’ triggered START or
Channel ‘astro:sun:minus90:set#event’ triggered START or
Time cron “0 1 0 * * ? *” or // one minute after midnight so give Astro time to calculate the new day’s times
Time cron “0 0 6 * * ? *” or
Time cron “0 0 23 * * ? *”
then

  // logInfo(logName, "Calculating Time Of The Day")
  logInfo("Calculate time of day state", "Calculating Time Of the Day")

  // Calculate the times for the static tods and populate the associated Items
  // Update when changing static times
  // Jump to tomorrow and subtract to avoid problems at the change over to/from DST
  val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18)
  vMorning_Time.postUpdate(morning_start.toString) 

  val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(1)
  vNight_Time.postUpdate(night_start.toString)

  val bed_start = now.withTimeAtStartOfDay
  vBed_Time.postUpdate(bed_start.toString)

  // Convert the Astro Items to Joda DateTime
  val day_start = new DateTime(vSunrise_Time.state.toString) 
  val evening_start = new DateTime(vSunset_Time.state.toString)
  val afternoon_start = new DateTime(vEvening_Time.state.toString)

  // Calculate the current time of day
  var curr = "UNKNOWN"
  switch now {
  	case now.isAfter(morning_start)   && now.isBefore(day_start):       curr = "MORNING"
  	case now.isAfter(day_start)       && now.isBefore(afternoon_start): curr = "DAY"
  	case now.isAfter(afternoon_start) && now.isBefore(evening_start):   curr = "AFTERNOON"
  	case now.isAfter(evening_start)   && now.isBefore(night_start):     curr = "EVENING"
  	case now.isAfter(night_start):                                      curr = "NIGHT"
  	case now.isAfter(bed_start)       && now.isBefore(morning_start):   curr = "BED"
  }

  // Publish the current state
  logInfo(logName, "Calculated time of day is" + curr)
  vTimeOfDay.sendCommand(curr)
end

The item on my sitemap says: Current time of the day: UNKNOWN

The two lines at the end of your rule should produce a line each in your logs.
Can’t see that in the log snippets shown.
Maybe your xx.rules file didn’t load (there will be a log)

As Rossko said, there seems to be something wrong with your rule. When looking in your log, one can see, that the times for your items are set:

Morning = 06:00:00 Night = 23:00:00 Bed = 00:00:00

So that seems to be ok.

But what is weird, is the state of your current time of the day. It’s initially set to “UNKNOWN” and the “state machine” should set it to its correct value, when triggering.

So I’m wondering how can it be, that there was a change of your items (vBed_Time, etc) at 12:59:29. I can’t find a Trigger in the rule at that time.

Can you really see the rule triggering as Rossko asked ?

There are two logs in the rule:

logInfo("Calculate time of day state", "Calculating Time Of the Day")
.......
logInfo(logName, "Calculated time of day is" + curr)

and as I said some posts before: Either you have to define the variable “logName” or you have to change the second logInfo like in the first one shown.

EDIT:

I’ve made a short test and changed something in my rule and it triggers after that (I think it’s because of the “System started” Trigger).And you should see this in the log:

2019-10-12 14:32:56.010 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'rich_time.rules'
2019-10-12 14:33:03.446 [INFO ] [e.smarthome.model.script.Time Of Day] - Calculating time of day...
2019-10-12 14:33:03.472 [INFO ] [e.smarthome.model.script.Time Of Day] - Calculated time of day is DAY

Thanks guys for the replies, the logs let me see that the rule for the calculating part is triggered:

2019-10-12 13:17:34.250 [INFO ] [l.script.Calculate time of day state] - Calculating Time Of the Day

But I wont’t get the output which states the time of the day.

and as I said some posts before: Either you have to define the variable “logName” or you have to change the second logInfo like in the first one shown.

When I change this one into the format like the first one I’ll get an error. I changed the second one into:

logInfo("Calculated time of day is" + curr)
  vTimeOfDay.sendCommand(curr)

I do get this error after saving it:

2019-10-12 15:21:01.705 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model ‘lighting.rules’

2019-10-12 15:21:07.986 [INFO ] [l.script.Calculate time of day state] - Calculating Time Of the Day

2019-10-12 15:21:08.029 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Error during the execution of startup rule ‘Calculate time of day state’: index=1, size=1

Remon: I think there is a syntax error in your log statement. Please examine Peter’s example from above

logInfo("myRuleName in double quotes", "Calculating Time Of the Day")

There is
logInfo (“some stuff in double quotes” , “actual log statement”)

So the order is the
logInfo
open parenthesis
stuff in double quotes
comma
atual log entry in double quotes
close parenthesis

here is the documentation for adding log entries to your rules

2 Likes

Thanks Andrew you were right and that was the final step to take! I changed the logInfo to:
logInfo("Calculated time of day is", "Calculated time of day logs" + curr)

And now it gives me the time of the day state. Thanks a lot!

1 Like

“Little Step for mankind, but giant leap for you”. (Hope so) :crazy_face::wink:

@rlkoshak
I have a problem with this rule. So it seemed that AFTERNOON never got triggered. And I assumed that some config was wrong.
Added a dummy switch to trigger the rule manually. If I trigger it in the AFTERNOON state, it calculates it right, but not automatically.

The vEvening_Time has the right time (sunset - 90 mins) if I look at it (so the config is right I think).
The trigger can be also seen in the log, however:

2019-10-30 16:29:00.015 [vent.ChannelTriggeredEvent] - astro:sun:91a227b3:set#event triggered START
2019-10-30 16:29:00.025 [vent.ChannelTriggeredEvent] - astro:sun:local:set#event triggered START

(91a227b3 -> this is the sun with the offset). So the trigger however not seem to get shifted. Why is that? Do you have any idea? And that trigger time is the actual sunset time (so it looks like that the offset doesn’t have an effect on the trigger, but only on item output)

I have this problem long time ago, I have restarted the system numerous time, now I even have a fresh install, and still the same problem…

There is something wrong with your Thing definition if the event isn’t being offset. You’ve not supplied the offset or you’ve supplied it in an incorrect manner. Or there is a bug with Astro and an issue needs to be filed.

But the item which is linked to that Thing, shows the correct offset. So that being said, I assume that the config is right, or not?

There is something different about it in some way. You’ve not posted the latest versions of the Item nor have you posted the Rule triggers. I don’t actually use Astro events any longer (see the Python version above) so I’ve no recent experience using this, but no one else is complaining about this issue so there is either something wrong with your Thing definition or there is a bug that is unique to your configuration.

Yes I saw that, I’m already planning to migrate everything to Python, but that takes some time… And I assumed that I will also have this problem there as well, because that seems to be an Astro issue nor a rule issue for me.

Rules:

val String filename = "DayState.rules"

rule "Calculate time of day state" 
when
	System started or // run at system start in case the time changed when OH was offline
	Channel 'astro:sun:local:rise#event'		triggered START or
	Channel 'astro:sun:local:set#event'			triggered START or
	Channel 'astro:sun:91a227b3:set#event'		triggered START or
	Item Recalculate_DayState received command ON or
	Time cron "10 1 0 * * ? *" or // one minute after midnight so give Astro time to calculate the new day's times
	Time cron "0 0 6 * * ? *" or
	Time cron "1 0 22 * * ? *"
then

	logInfo(filename, "Calculating time of day...")

	// Calculate the times for the static tods and populate the associated Items
	// Update when changing static times
	// Jump to tomorrow and subtract to avoid problems at the change over to/from DST
	val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18)
	vMorning_Time.postUpdate(morning_start.toString) 

	val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(2)
	vNight_Time.postUpdate(night_start.toString)

	val bed_start = now.withTimeAtStartOfDay
	vBed_Time.postUpdate(bed_start.toString)

	val now_5= new DateTime(now.plusSeconds(5))

	// Convert the Astro Items to Joda DateTime
	val day_start = new DateTime(vSunrise_Time.state.toString) 
	val evening_start = new DateTime(vSunset_Time.state.toString)
	val afternoon_start = new DateTime(vEvening_Time.state.toString)

	// Calculate the current time of day
	var curr = "UNKNOWN"
	switch now_5 {
		case now.isAfter(morning_start)		&& now.isBefore(day_start) : curr = "MORNING"
		case now.isAfter(day_start)				&& now.isBefore(afternoon_start) : curr = "DAY"
		case now.isAfter(afternoon_start) && now.isBefore(evening_start) : curr = "AFTERNOON"
		case now.isAfter(evening_start)		&& now.isBefore(night_start) : curr = "EVENING"
		case now.isAfter(night_start) : curr = "NIGHT"
		case now.isAfter(bed_start)				&& now.isBefore(morning_start) : curr = "BED"
		default : curr = "Unknown"
	}
	
	if(Recalculate_DayState.state == ON) {
		Recalculate_DayState.sendCommand(OFF)
	}
	// Publish the current state
	if (vTimeOfDay.state.toString != curr) {
		logInfo(filename, "Calculated and set time of day is " + curr)
		vTimeOfDay.sendCommand(curr)
	}
	else {
		logInfo(filename, "Calculated time of day is " + curr)
	}
end

Item definition

DateTime    vEvening_Time   "Afternoon [ %1$tH:%1$tM]"  <sunset>        { channel="astro:sun:91a227b3:set#start" }

I use PaperUI to set up my Things, so I can’t show you textually the Thing defition. But it only differs from the autodiscovered Thing that I put -90 to the Sunset Offset.

The Python version doesn’t use triggers to the Rule to drive the state machine. Instead it uses only DateTime Items and uses Timers to drive the state machine. If the DateTime Item is correct, the Python Rule is correct.

I’ve just posted a new version of the Rule that lets you use Ephemeris and you can define different times of day for different types of days (weekends, workdays, holidays, etc).

On which Channel did you put the offset?

That question did the trick :slight_smile: I only set the offset for the Start Time, not for the Range Trigger. I assume that now it will be correct :slight_smile:

Yes I also saw that, that will be my new direction regarding this, because I already wanted to distinguish different days, not just day states.

Thanks!

Hi,

I’ve searched, and I can’t find anything on this line:

String vTimeOfDay “Current Time of Day [MAP(weather.map):%s]”

Is there any documentation I can read?

https://www.openhab.org/docs/concepts/items.html and https://www.openhab.org/docs/configuration/items.html

Geesh. I must have skimmed right over it in the State Transformation section 20 times times.

Thanks!

I wanted to use this method to set a reminder to feed my animals:

rule "Food reminder"
when
    Time cron "0 0 18 1/1 * ? *"
then {
  val DT_Feed_Next = DT_Feed_Last.plusDays(2)
  if (now.isAfter(DT_Feed_Next)) {
    sendBroadcastNotification("Feed!")
    }
  }
end

but I get the error:

[ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule 'Food reminder': 'plusDays' is not a member of 'org.eclipse.smarthome.core.library.items.DateTimeItem'; line 43, column 33, length 31

Not sure why since similar operations (plusMinutes, plusDays) work in other rules e.g. when setting up timers.