Design Pattern: Simple State Machine (e.g. Time Of Day)

You are right, I posted it to the script action. I deleted the old rule and recreated it like you said. It works now. But when I run it I am getting the following error:

Default_Morning has undefined which is not a valid day type, expected one of default,weekday,weekend,dayset,holiday,custom.

This is the meta data I have in Default_Morning:
Value: MORNING
Config: {}

I tried to put in:
type= default
but it disappears every time I put it in.

How. It sounds like you didnā€™t do it correctly syntactically. It should look something like:

value: AFTERNOON
config:
  type: default

I donā€™t know whatā€™s going on. Hereā€™s what I typed in:

value: MORNING
config:
type: default

I save it and when I go back in it shows this:

value: MORNING
config: {}

Are you click on save? If you just hit back on the browser or click on cancel the change wonā€™t be saved.

Yes, Iā€™ve been saving them. I tried again with the same result. Even rebooted OpenHAB3.

Please use code fences. The spaces are important. The type must be indented under config.

Or you use items files. Just for testing.
(I hate programming languages where spaces are importantā€¦)

:wink:

Sorry, I didnā€™t realize that was so important. I thought you accidentally indented it or something.
It starting working with no errors after I made that change. Hey, one more thing. I used the Time of Day Rule to update to update my Morning and Bed Time. Both of these are fixed times. When I look at the item in OpenHAB3 they both show the year as 1970. Is that OK? It really shouldnā€™t affect anything, I donā€™t think.
Thanks for your help.

Yes. When the Time of Day rule runs it will forward any of the Items that have a Date prior to today to today.

Iā€™ve seen it done well (YAML, Python, etc) and Iā€™ve seen it done really badly (TCL/TK or what we used to call it Fickle TK). Every language has itā€™s good parts and itā€™s bad parts. I personally like the way YAML is structured compared to alternatives like JSON and XML when it comes to being easy for a human to read and understand. Instead of using tags or brackets, YAML uses indentation. And thatā€™s something that the ā€œpretty printersā€ for JSON and XML will add too. So why have opening and closing tags or symbols and indentation when you can express the same thing with just the indentation?

A lot of programming languages use indentation (tabs, not spaces) mostly for human readability, youā€™re right, the code works fine without. YAML uses them as functional parameters, I see that. But Iā€™ve far more often hunted for errors because of that (yaml configuration files, for instance) than otherwise. With brackets, itā€™s a lot easier to see which parts of the code actually belong together, especially when that code stretches over many lines. But thatā€™s just me. I guess with yaml you then have to count spaces :slight_smile:

And JSON, well, I love it for parsing JSON outputs, but not for much more.

Hi,
as i still struggle with my Openhab 3.0 Upgrade, one function needs a rewrite.
Currently i get a
ā€œfailed: ā€˜getHourOfDayā€™ is not a member of ā€˜java.time.ZonedDateTimeā€™; line 16, column 19, length 18 in icloudā€
What i am doing?
Something like that:

var Number hour = now.getHourOfDay()
        if (hour>=6 && hour<=9) {
                sendCommand(Hue_Nachtmodus_Sensor_SensorState,"0")
        }

So nothing special, just get the current hour and compare it to my timeframe.
This now fails.
Can anyone write me a quick and dirty example how to get the current hour in openhab3.0?
I have read through many threads, but i cannot imagine, that i have to perform such complex coding as mentioned just for getting the hour :confused:

Thanks !
Der_Gute

The full ZonedDateTime docs are at ZonedDateTime (Java SE 11 & JDK 11 )

Use getHour().

1 Like

Please @rlkoshak update the rule for OH3 :pray:

It is already. There is a JavaScript UI generated rule linked to in the original post. Iā€™m probably going to remove the Rules DSL version as I do not intend to continue supporting it for Time of Day. I never liked how it had to be implemented in Rules DSL and am not inclined to keep maintaining it any longer. My time is better spent elsewhere, especially since there is a Python version for OH 2.5 and a JavaScript version for OH 3 that will let you implement Time of Day without ever needing to look at or edit the code, and they let you define a different set of times of day based on the type of day.

In short, there are far better and more capable implementations of Time of Day posted and described in the original post. Use those instead.

For DSL lovers, I adapted the DSL rule by @rlkoshak for OH3 (with help of this contribute).

val logName = "Time Of Day"

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:home:rise#event'    triggered START or
  Channel 'astro:sun:home: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 day...")

  val ZonedDateTime zdt = ZonedDateTime.now()
  val ZonedDateTime start_of_day = zdt.toLocalDate().atStartOfDay(zdt.getOffset())

  // 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 = start_of_day.plusDays(1).minusHours(18)
  vMorning_Time.postUpdate(morning_start.toString) 

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

  val bed_start = start_of_day
  vBed_Time.postUpdate(bed_start.toString)

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

  // 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

// Examples for use of vTimeOfDay
rule "Day time started"
when
  Item vTimeOfDay changed to "DAY" // does not work prior to OH 2.3 Release
then
  // do stuff when DAY starts
end
5 Likes

We already had a better implementation of the DSL rule than mine by Dan a while ago.
Post 572, I think.

I have just migrated to OH3 and most of my motion triggered rules have the vTimeOfDay in it. Thank you for making it work again.

1 Like

Is this still true in the Javascript version?
I canā€™t check it now because of time of the year, but based on viewing the code, I get the feeling that it wonā€™t look anymore to the state (MORNING,DAY,EVENING etc), but just which comes first based on time. So in Summer if I set my MORNING to 07:00h and DAY to the sunrise (eg 06:13h), the sequence of events will be DAY, MORNING, EVENING etc.

Is this intentionally changed versus the old DSL rule?

I have to admit that I currently also rely on the DSL rule. The JS rule works fine, but every time I restart OH3 it messes up the ephemeris settings and that obviously kills the JS rule.

I donā€™t know that Iā€™ve explicitly tested for it.

The JavaScript and Python versions do work differently by design so they might not work that way any more. Frankly, what I would do to handle this case is to adjust it in the Astro binding Thing where you can set a no-earlier than and no-later than properties to control when the times/events occur.

The Python and JavaScript versions of the rule are a complete rewrite and have almost nothing in common with the Rules DSL version.

Rules DSL JavaScript/Python
Rule triggers at each time of day transition Rule triggers once a day and sets timers for time of day transitions
Only works with Astro and cron times Supports any DateTime Item
Has a fixed set of times of day Supports a different set of times of day based on Ephemeris day type
Requires the rule code to be edited to change times of day Only requires creation and editing of Items to change times of day

In my opinion, the JavaScript/Python versions are significantly better and more flexible compared to the Rules DSL version and Iā€™m inclined to deprecate the Rules DSL version entirely.

Have you filed an issue?

1 Like