Time Based State Machine

logo

Home automation often follows a set cycle or states. In the morning the house needs to wake up and come alive as the inhabitants get ready for the day. Next the house should go to sleep a bit while everyone begins the work day. Later in the afternoon the house may wake up again to prepare for everyone’s return and so on.

There are a number of ways to define such states but a common approach is to use times of day. This rule template establishes a rule that uses DateTime Items to drive a state machine. A different set of DateTime Items can be defined for different types of days (e.g. one set for workdays, another for weekends, and a third for holidays) with Ephemeris used to choose between the sets of DateTime Items for a given day.

How it Works

Initial Setup

  • The user creates a String Item to hold the current time of day state. For this documentation we’ll call it “TimeOfDay” but you can choose any name.

  • The user creates a Group Item to hold all the DateTime Items that drive the state machine. For this documentation we’ll call it “TimesOfDay” but you can choose any name.

  • The user creates one or more sets of DateTime Items. Each Item is populated with the start time for the time of day state that Item represents. For example, a DateTime Item that represents MORNING might be populated from the Android App’s Alarm Clock feature or Astro’s sunrise time or hard coded to 07:00.

  • Each of those Items must have metadata defined on them. See below for details. This Item metadata is used to identify which type of day the Item belongs to and what time of day state it represents the start of.

  • Each of those Item are also made direct members of the TimesOfDay Group.

  • All the members of TimesOfDay need to be configured with Persistence for restoreOnStartup.

Metadata

Each DateTime Item requires Item metadata. The namespace can be defined by you. For this documentation we will use “tod_sm”.

// Item metadata defined in .items files
tod_sm="<STATE>"[type="<daytype>", set="<dayset>", file="<uri>"]

// Item metadata defined in the UI
value: <STATE>
config:
  type: <daytype>
  set: <dayset>
  file: <uri>

<STATE>
Replace this with the string you want sent to TimeOfDay at the DateTime held by this Item. The string will be sent as a command but only if it is different from the current state of TimeOfDay.

type
The rule supports six types of days as defined by Ephemeris.

Type Purpose
custom When custom holidays are defined in an XML file (see the Ephemeris docs) use custom for the type and the file parameter is required.
holiday When configure with country and region in MainUI (Settings → Ephemeris), Ephemeris will become preconfigured with the national holidays observed by that region.
dayset Ephemeris allows for the definition of a custom dayset, such as defining “trash_day” to occur every Monday. When used as the type, the set parameter is required.
weekend For the days defined as weekend in the Ephemeris configuration.
weekday For the days not defined as weekend in the Ephemeris configuration.
default If Ephemeris doesn’t match any of the above day types or if there is no set of DateTime Items defined for any of the above types this set of DateTime Items is used.

The day types are processed in the order presented above. For example, if Ephemeris says today is a holiday, that set of DateTimes will be used even if today is also a weekend and there is a set of DateTimes for that also.

set
Replace <dayset> withe the custom named dayset defined in the Ephemeris config to use. This parameter is only required when the type is dayset and should be absent in all other cases.

file
Replace <uri> with the full path to the custom Ephemeris XML file with the custom holidays defined. This parameter is only required when the type is custom and should be absent in all other cases.

Examples:
The following are for illustrative purposes, they must be customized for your configuration.

// .items files examples
DateTime Default_Bed (TimesOfDay) { tod_sm="BED"[type="default"] }
DateTime Weekend_Evening (TimesOfDay { channel="astro:sun:local:set#start", tod_sm="EVENING"[type="weekend"] }
DateTime Trash_Morning (TimesOfDay) { tod_sm="MORNING"[type="dayset", set="trash"] }
DateTime Birthday_DAY (TimesOfDay) { tod_sm="DAY"[type="custom", file="/etc/openhab/service/birthdays.xml"] }

// UI Metadata
value: BED
config:
  type: default

value: EVENING
config:
  type: weekend

value: MORNING
config:
  type: dayset
  set: trash

value: DAY
config:
  type: custom
  file: /etc/openhab/service/birthdays.xml

Item Sets

At a minimum there should be a set of DateTime Items defined for default type days. This will be the sets of states and times used when no other sets are found for the current day type. You might stop with just the default sets of Items. However, if that is your plan, see Creating Capabilities with Rule Templates: Time of Day for a simpler approach to this rule.

The states for each day type can be unique and there can be a completely separate set of start times for each day type.

The rule does not support reusing the same DateTime Item for more than one day type though.

Populating the DateTime Items

Actually populating and managing the DateTime states of the Items is outside the scope of this rule. Options include:

  • Astro binding based on solar or lunar events.
  • iCal and similar bindings that can define start times.
  • Android app’s Alarm Clock option that publishes the next scheduled Alarm to an Item.
  • Populated by hand via the REST API, the karaf console, or a widget (see DateTime Standalone Widget and DateTime List Item which can be installed from the marketplace)
  • A more advanced timeline picker widget such as Timeline which can be installed from the marketplace.
  • Populated from a Rule.

If using hand populated times, install and configure To Today to move those DateTime Item’s date to today at midnight.

NOTE: The rule triggers based on changes to these Items. If the Items are not changed to the current day the rule will not trigger and the state machine will stop.

What the Rule Does

Whenever one of the members of TimesOfDay changes its state or openHAB restarts the rule triggers.

The rule first determines what type of day it is. Then it selects those DateTime Items that are for that day type (if no Items exists the “default” set is chosen). Next it determines what the current time of day is based on the times defined on the selected Items, commanding TimeOfDay if the current state is different from the state in TimeOfDay. Finally, for any DateTimes that are in the future, a Timer is created to transition TimeOfDay to that state at that time.

DateTime Items with invalid metadata generate an error. Items with a NULL or UNDEF state are ignored.

Language: Nashorn JavaScript or JSScripting

Dependencies:

  • A TimeOfDay String Item
  • A TimesOfDay Group
  • Sets of DateTime Items who are members of the TimesOfDay Group and have valid Item metadata.

Changelog

Version 0.3

  • adjusted for breaking change, will no longer work for versions of OH prior to December 15th

Version 0.2

  • Made compatible with both Nashorn and JSScripting
  • NOTE: Sometime after the release of OH 3.2 I will make this template only work with JSScripting so I can take advantage of the helper library.

Version 0.1

  • initial release

Resources

https://raw.githubusercontent.com/rkoshak/openhab-rules-tools/main/ephem_tod/template/time_of_day.yaml

3 Likes