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 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.
In MainUI open Settings → Automation
Browse through the list from the Marketplace and install the Alarm Clock Rule and To Today templates.
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.
|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.||
|DAY||Astro binding sunrise.||
|AFTERNOON||Astro binding dusk event with a -120 minute offset.||
|EVENING||Astro binding sunset without an offset.||
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
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.
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
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
Scroll up to the Sunrise section of Astro Channels and link the “Start Time” Channel to
Select the “Start Time” Channel from the Sunset section of Channels and link it to “ToD_EVENING”.
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_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.
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.
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.”
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.
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.
See below for an alternative.
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.
ToD_Morning for the “Alarm Time Item” and “Time of Day Morning” as the “Script to Call”.
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.
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_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.
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.
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.
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("_"); 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.
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.
|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.|