NOTE: As of OH 3.3 the Alarm Clock rule template is replaced with a native DateTime Trigger which will trigger a rule based on the state of a DateTime Item.
With the introduction of the Marketplace for rule templates I thought it might be a good time to show how one would use rule templates, not just by themselves but together to build up a fairly complex automation without needing to code anything at all, or minimal coding.
In this case we will implement a simple version of [Deprecated] Design Pattern: Time Of Day using Alarm Clock Rule and To Today.
In short, we will create a time based state machine that commands an Item at the beginning of a given time of day with the name of that time of day. This Item can then be used to drive other rules and or provide an easy way to test what time of day it is to control the behavior of automations.
The Alarm Clock Rule template create a rule that will run a given Rule based on a change in a DateTime Itemâs state. The To Today rule template will create a rule to move all DateTime Items with a given tag to todayâs date, keeping the time the same.
First steps
Install the Templates
In MainUI open Settings â Automation
Browse through the list from the Marketplace and install the Alarm Clock Rule and To Today templates.
Define the Items
We will have five times of day. We will use an Design Pattern: Associated Items naming scheme which will make some of the next steps easier.
State | Time | Item name |
---|---|---|
MORNING | Based on a time published to an Item by the Android app that indicates when the next alarm set on the phone will go off. | ToD_MORNING |
DAY | Astro binding sunrise. | ToD_DAY |
AFTERNOON | Astro binding dusk event with a -120 minute offset. | ToD_AFTERNOON |
EVENING | Astro binding sunset without an offset. | ToD_EVENING |
NIGHT | 10:00 pm | ToD_NIGHT |
BED | 11:45 pm | ToD_BED |
There is a mix of Items hard coded to a specific time and Items that are populated from a binding or externally. These are just examples. You must choose your own times of day and where those times of day get their date times from.
Create all of the above Items using your approach of choice. Just make sure they are DateTime Items.
There is one more Item to create, the TimeOfDay
Item. This Item needs to be a String Item. In my screenshots this will be called TimeOfDay_Example
.
NOTE: The rule templates assume that the DateTime Items are persisted and restored on startup. If you are running a default OH 3 instance this is already configured for you.
Configure Android App
Skip if you are not using the Android App to drive one of your Items.
In the openHAB Android app open the app settings.
Scroll down to âSend device information to serverâ and tap âAlarm timeâ.
Tap to toggle this feature to on and enter âToD_MORNINGâ as the Item name.
Note, when there is no alarm scheduled the Item will be set to NULL
.
Configure the Astro Binding
Skip if you are not using the Astro binding to drive one or more of your Items.
Install and configure the Astro Binding. Accept the Thing discovered from the inbox. Weâll use astro:local:sun
for the Thing ID in these examples. Use your Thing ID in your Item configs.
Navigate to the Astro Thing, open the Channels tab and scroll down to the Dusk section. Select the âStart Timeâ channel and click on âConfigure Channelâ. Set the offset to -120. Link this Channel to ToD_AFTERNOON
.
Scroll up to the Sunrise section of Astro Channels and link the âStart Timeâ Channel to ToD_DAY
.
Select the âStart Timeâ Channel from the Sunset section of Channels and link it to âToD_EVENINGâ.
Widgets to Set Hard Coded DateTime Items
Navigate to Settings in MainUI and click on âUser Interfacesâ. Browse though the list of Marketplace offerings to find the âDateTime Stand Alone Widgetâ. You may need to click on âShow Allâ. Install it.
If you plan on putting these Items into your model, also find and install the DateTime List Item widget.
Navigate to the DateTime Items youâve defined that have hard coded times. In our case thatâs ToD_NIGHT
and ToD_BED
. Under âMetadataâ click âAdd Metadataâ . Select âDefault Standalone Widgetâ.
For the widget field choose ârlk_datetime_standaloneâ from the list under âPersonal Widgetsâ. Enter a label to identify the Item in the widget and if necessary select the Item. Save.
Optionally repeat for the âDefault List Item Widgetâ only this time choose ârlk_datetime_listâ from the list under âPersonal Widgetsâ.
Now by default where ever this Item is shown, a nice date and time selection widget will be used. Use the widget to set the date and time for your hard coded Items. Clicking on the calendar icon of the widget will open a nice date picker widget.
Clicking the check will post that date time to the Item. The current state of the Item is shown at the bottom of the widget.
You can set the Itemâs date and time from any of your pages with these widgets or from the Itemâs setting page. If you semantically tag the Item, make sure to set the âDefault List Item Widgetâ do you have the same ability on the cards shown on the Overview page.
Once the widgets are applied to an Item, go ahead and set the date time for those Items. Note that the new state may not always show up immediately under the widget when setting the state from the Itemâs settings page.
Now when you look at the Items in the Items settings you should see that all of them have a non-NULL state except for MORNING if you donât have an alarm scheduled.
No Code Solution
In this approach we will not be using any code at all, only the UI. This means no Script Conditions or Script Actions. But we will be instantiating some rules.
Create the Transition Rules
In the Rules section of MainUI click on the + icon to create a new rule.
Give it a reasonable Unique ID, name and description.
Skip down to the âThenâ section and add an Action. Choose âItem Action.â
Pick the TimeOfDay
Item from the list. Check âshow non-semantic itemsâ if youâve not tagged your Items.
Leave âsend a command toâ selected and for the âCommand to sendâ enter âMORNINGâ.
Click Done and Save.
Repeat for the remaining times of day Items, always choosing the TimeOfDay
Item to send the command to and the name of the time of day as the command to send. See the Advanced section below for a way to make this easier.
Advanced
Now that youâve created the one rule for MORNING, click on the âCodeâ tab and copy the YAML presented there to the clipboard.
Return to the Rules page and click the + icon to create a new rule. Once again enter reasonable values for the Unique ID, Name, and Description for the rule.
Now click on the âCodeâ tab and paste the YAML into the form, replacing what ever is there already.
Change the âcommandâ field to the time of day this rule is for (e.g. change from âMORNINGâ to âDAYâ).
Save and repeat for the rest of the times of day.
Once you are done you should have one rule for each time of day Item.
Note that there is nothing preventing you from adding anything to these rules. Instead of driving a time of day state machine, you can just code your time of day automations right here in these rules. Or this can drive some other deviceâs state, such as an HVAC system.
Too Many Rules!
See below for an alternative.
Instantiate Time of Day Alarm Clock Rules
We now have a rule for each time of day to transition. Now we need to instantiation a rule for each time of day that will call the transition rules at the time indicated by the DateTime Itemâs state.
Since weâve already installed the template we just need to create a new rule by clicking the +. Once again enter something reasonable for the Unique ID, Name, and Description.
This time instead of build the rule itself we will select âSchedules a timer to run a scriptâ from the list of Templates.
Select ToD_Morning
for the âAlarm Time Itemâ and âTime of Day Morningâ as the âScript to Callâ.
Save.
You will see now that the template has turned into a complete rule. You can click around to see how itâs built and look at the code if you want but you donât have to. The rule has been tested and is known to work as is.
Click âBackâ and repeat for all the other times of day.
Unfortunately there isnât a short cut for this but I was able to set up all the rules from the template in about 8 minutes.
Last Step, To Today
We have one final step. Some of our Items are hard coded which means that every day they need to be moved to the next day to cause the Time of Day X Manager rule to trigger which will schedule the time when the Time of Day X rule will run. The rest of the Items are handled by the external things that populate those Items.
From the Rules page in MainUI once again click the + icon. Enter reasonable identifying information once again.
This time select âMove tagged DateTime Items to todayâs dateâ from the list of Templates. Enter an Item tag that will be used by this rule to identify those Items that the rule needs to process. In this case Iâve chosen âtotdâ.
Now navigate to the Items that have hard coded times. In our case thatâs ToD_NIGHT
and ToD_BED
. Click on âEditâ in the upper right corner. Under âNon-Semantic Tagsâ type in âtotdâ and be sure to press Enter. It should show up with a little tag icon.
Repeat for all hard coded Items.
Get Everything Running
Navigate to the Time of Day To Today Rule and run it by clicking the play icon. This ensures that the Items all have todayâs date. Watch the logs for errors.
Navigate to all the Time of Day X Manager rules and run those by by clicking the play icon. This will cause the rules to start timers for today. Alternatively restart openHAB which will cause them all to run.
Fewer Rules Example
The no code example creates a ton of rules: 2N+1 where N is the number of times of day. While the number of rules is not a problem necessarily, it does clutter up the list of rules in MainUI. If you are willing to write just a little bit of code we can reduce that down to N+1 rules. We can do this by taking advantage of a feature of the Alarm Clock Rule to collapse the Time of Day X rules into one single rule.
Instead of creating one Time of Day X rule for each time of day, we will just create one and use some string parsing to extract the time of day from the Itemâs name that triggered the rule to be called.
Click the + icon from the Rules page to create a new rule. Enter reasonable information in the top section.
Click on âAdd Actionâ under âThenâ and select âRun Scriptâ.
You can choose any language of choice. However, I donât think that Blockly has access to the variable passed to this rule by the Alarm Clock Rule. Iâll choose ECMAScript 5.1 for this example.
When one rule calls another rule, it can pass data to the called rule. This data is available in context
and can be accessed by name using context.getAttribute("name");
. The Alarm Clock Rule will pass a value named âtriggeringItemâ which contains the name of the Item that triggered the Alarm Clock Rule. Using this we can know which Alarm Clock Rule called the script and parse the time of day out of the Item name. I told you Associated Items naming would come in handy.
The following can be pasted into the code tab of a rule if you want to use it.
configuration: {}
triggers: []
conditions: []
actions:
- inputs: {}
id: "1"
configuration:
type: application/javascript
script: >-
var logger = (logger === undefined) ?
Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.rules_tools.Time
of Day") : logger;
var timeOfDay = context.getAttribute("triggeringItem").toString().split("_")[1];
logger.info("Transitioning to " + timeOfDay);
events.sendCommand("TimeOfDay_Example", timeOfDay);
type: script.ScriptAction
The JavaScript is
var logger = (logger === undefined) ? Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.rules_tools.Time of Day") : logger;
var timeOfDay = context.getAttribute("triggeringItem").toString().split("_")[1];
logger.info("Transitioning to " + timeOfDay);
events.sendCommand("TimeOfDay_Example", timeOfDay);
Now when creating the Alarm Clock rules, choose the âTime of Day Transitionâ rule as the âScript to Callâ.
Not only does this eliminate N-1 of the total number of rules, itâs pretty simple, being only four lines of code and you get a log statement too boot.
Whatâs the Point?
Why did I write this tutorial? There are a number of reasons which amount to the key take aways.
-
Especially in the UI rules, often it is easier to have lots of rules than it is to figure out how to write one more generic rule. This can particularly be the case when using rules from the Marketplace.
-
For Marketplace rules writers, consider making simple rules which can interact with each other in interesting ways. In this example, we have a simple rule that schedules a timer to call another rule based on a DateTime Item and another rule to move a DateTime Item to today. Individually and independently each rule is useful in its own right. But by combining them we can achieve something as complex as the Time of Day Design Pattern.
-
When you are ready, donât be afraid of a little bit of code. It can save you a lot of work in the long run.
-
Even though you are using a rule template, you end up with a full rule that can be edited. Donât be afraid to look at the code that results from a template and customize it to meet your own needs.
-
For Marketplace rules writers, notice how the To Today rule uses Item tags to identify those tags it needs to operate with. Semantic tags, Item metadata and other Item properties can be used as well. A Group is not always required and might be more of a pain for the end users to set up than other alternatives.
Exercises for the Student
Feature | A way to achieve it |
---|---|
Different times of day for weekends | Add a separate set of Items and rules for the weekend. Add conditions to the rules so one set of rules are only running on weekdays and the other set only on weekends. |
Fewer rules | Add the ability to set a Group with a Member of trigger on the Alarm Clock Rule. Modify the code so the one instance of the rule can handle all the time of day Items. (this is on my todo but I want to use a library so am waiting for a better way to handle that). |
Instead of time of day drive a different time based behavior | Change the implementation of the Time of Day X rule(s) to do something beyond just commanding a Time of Day Item. |