Time Based State Machine [4.0.0.0;4.1.0.0)

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.

This is a complete rewrite of the rule for OH 3.x using JS Scripting and the openhab_rules_tools library. The behavior is slightly different in that only the time portion of the DateTime Items is used to schedule the timers so there is no longer a need for the To Today rule template to drive static times. Also, there is a ton more validation of the config with meaningful error messages for how to correct it.

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. 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 “tsm”.

// Item metadata defined in .items files
tsm="<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 date time 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, link above) use custom for the type and the file parameter is required.
holiday When configured 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> with the custom named dayset defined in the Ephemeris config to use. This parameter is 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 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) { tsm="BED"[type="default"] }
DateTime Weekend_Evening (TimesOfDay { channel="astro:sun:local:set#start", tsm="EVENING"[type="weekend"] }
DateTime Trash_Morning (TimesOfDay) { tsm="MORNING"[type="dayset", set="trash"] }
DateTime Birthday_DAY (TimesOfDay) { tsm="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. A warning will appear in the logs if there is no “default” set but the rule will still try to run without them.

The states for each day type must be unique. If a state is repeated an error will be generated by the rule.

There must be a completely separate set of start times for each day type for which you want to have a state machine. 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.

What the Rule Does

Whenever one of the members of TimesOfDay changes its state, openHAB restarts, and a few minutes after midnight, the rule triggers.

First the rule waits for ten seconds before doing anything. The Astro binding calculates the new times for the celestial events a minute after midnight, updating all the linked Items. This can result in the rule triggering a bunch of times. This delay causes the rule to wait for the updates to stop before calculating the new state machine timers.

After the initial delay, the rule first validates the Item configs. After changing the Item configs for this rule, run it manually to validate and apply them immediately.

Next it determines what type of day it is and selects those DateTime Items that are for that day type (if no Items exists the “default” set is chosen, if no Items are found an error is logged).

Then it sorts the date times based on their time, skips those that have already passed, and creates a timer to command the “TimeOfDay” Item to the state in the metadata at that time.

Language: JS Scripting

Dependencies:

  • A “TimeOfDay” String Item
  • A “TimesOfDay” Group
  • Sets of DateTime Items who are members of the “TimesOfDay” Group and have valid Item metadata and states
  • openhab-js 4.1 or later
  • openhab_rules_tools 2.0.1 or later

Changelog

Version 0.2

  • now throws an exception if the openhab-js or openhab_rules_tools are not new enough

Version 0.1

  • initial release

Resources

https://raw.githubusercontent.com/rkoshak/openhab-rules-tools/main/rule-templates/ephemToD/time_state_machine.yaml

5 Likes