Design Pattern - Timer Management

Tags: #<Tag:0x00007f617ec308c0>

Please see Design Pattern: What is a Design Pattern and How Do I Use Them for a description of DPs.

Problem Statement

Frequently, when attempting to write generic Rules, especially when applying Design Pattern: Associated Items, one may need to set a separate Timer for each Item.

Concept

Store the Timers into a Map<String, Timer> using the Item name as the key.

Example

Python

For Python I’ve written a timer_mgr library you can obtain from https://github.com/rkoshak/openhab-rules-helper. This library implements all the management of timers like this for you. All you need do is instantiate the class and call the methods. See the README at that location for usage and other details.

For example, to use the library to set a Timer to send an alert when a door has been left open for 60 minutes:

from core.rules import rule
from core.triggers import when
from community.timer_mgr import TimerMgr

tm = TimerMgr()

@rule("Send an alert if a door has been left open for 60 minutes")
@when("Member of Doors changed")
def door_reminder(event):
    if event.itemState == OPEN:
        tm.check(event.itemName, 
                 (60*60*1000), 
                 function=lambda: events.sendCommand("Alert", event.itemName + " is still open!"))
    elif event.itemState == CLOSED:
        tm.cancel(event.itemName)

def scriptUnloaded():
    tm.cancel_all()

The above rule will send a command to the Alert Item when the door remains open for more than 60 minutes. If the door closes before 60 minutes the Timer is cancelled. All the book keeping and checking whether the Timer exists and such is handled by the library. You can pass a reschedule=True argument to reschedule the Timer if it already exists and pass in a flapping_function that gets called if the Timer already exists when calling check.

Rules DSL

See the “Group findFirst” example at Design Pattern: Associated Items for another full example. Pay attention to the lines where the variable timers is used.

import java.util.Map

val Map<String, Timer> timers = newHashMap

rule "Send alert if a door has been open for more than 60 minutes"
when
    Member of Doors changed
then
    // Always cancel the existing Timer
    val timer = timers.get(triggeringItem.name)
    timer?.cancel
    timers.put(triggeringItem.name, null)

    // Create a Timer if the door opened
    if(triggeringItem.state == OPEN) {
        timer.put(timerItem.name, createTimer[ |
            Alert.sendCommand(triggeringItem.name + " is still open!")
        ])
    }
end

Advantages and Disadvantages

Managing Timers in this way makes it possible to write generic Rules that work with Timers. When using the Python library, it only takes a couple of lines of code.

Related Design Patterns

Design Pattern How It’s Used
Design Pattern: Associated Items Includes an example of this DP.
2 Likes

Dang Rich, I see you been busy! :slight_smile: Two of these (that I noticed) in two days!

I tried searching, but apparently could not put together the right combination of terms to get the most up to date information on the following, so forgive me for going offtopic and by all means please point me in direction of another thread where this is being discussed even semi-recently, as I have not been able to find it…

Anyway, I noticed you seem to be changing all your rules examples over to Python. I also note you are calling it Python and not Jython. I have sort of been re-doing my setup from scratch lately, and I have been thinking this might be a good time to change over, assuming the old Rules DSL is going to be deprecated, or anyway is not “the way” going forward. Or maybe you just chose Python because it is more expressive?

Anyway, this is probably not the place, but hoping maybe you could point me somewhere, I know you know these forums like the back of your hand. :slight_smile:

I use the word “Python” because the language is Python. Jython is the specific implementation of Python that OH currently supports. So for the most part, unless told otherwise, Python means “rules or modules written in Python run by the Jython interperter” or something like that. And they can be used interchangeably when discussing Rules (unless you are talking about pure Python not running within openHAB).

As for why did I switch? Rules work much better using the new rules engine (it will just be *the rules engine" in OH 3). A lot of issues go away. OH 3 has support for .rules files in the new rules engine but it remains to be seen how many, if any, of the issues with the old rules engine go away.

It’s more expressive to use a more fully capable language like Python or JavaScript which supports stuff like libraries, functions, classes, etc. You can’t just import a library and use it in Rules DSL.

It’s much easier to share working and generic code (like my recent posts and other code you will find in the repo above). With Rules DSL copy/paste/edit is about the only option.

It’s faster, though that hardly matters in home automation.

Why did I choose Python/Jython over JavaScript or Groovy?

The Helper Libraries are far more mature for Python than the other languages. That’s pretty much it. Given my druthers, I’d use JavaScript as it doesn’t require installing anything extra into openHAB to use.

But even these Rules I’ve converted to Python are mostly just a bridge until the new UI for building rules becomes available in OH 3. At that point I’ll likely move all my rules again to be stored in JSONDB and distribute rule templates to import and use rather than .py files like that above. At that point I might choose JavaScript instead assuming that OH 3 doesn’t require the installation of anything else to use them.

In the mean time, after I converted my .rules to Python I came up with a bunch of libraries and reusable Rules that should make it easier for others to create Python rules. I submitted them to the Helper Libraries but the PRs still sit unreviewed and I want a way to share them more easily and continue development on them until such time that reviewing such PRs becomes a higher priority. It’s also possible that my “build tools to help users solve common problems in rules” is not what was intended or expected for the Community libraries section of the Helper Libraries and instead they want full capabilities. So I’m moving them to their own repo so I can continue working on them and share them more widely and easily.

1 Like

Thanks, as ever, for the detailed and thoughtful reply.

I had assumed such discussion on rules engines and languages to exist already, but since you answered in here maybe such thread does not exist? If so, maybe we should split these posts off into such a new thread, with more appropriate title? I leave it up to you as you are Mod anyway…

Thanks for clearing this up. Just reading the word “Jython” always induced anxiety for me as I wondered what sort of subtle issues might be introduced simply by virtue of such an abomination. :smile:

So, just to clarify, we might as well just think of it as regular Python? If that’s the case, I do like your choice of using “Python” as it immediately conveys to me the notion that it is just the same old familiar Python. In fact this usage of the term is one thing that immediately made me more comfortable in thinking about moving towards it. Perhaps this is all intentional on your part.

I won’t go quote by quote, but suffice it to say that I am aware of the benefits of using a “real” language as you so eloquently detail. But it will be good for others reading later, as I know is your intention.

It is also always good to hear your take on “the direction” of things in OpenHAB as well, as I know you seem to keep very on top of things around here, and with a much broader focus than whatever few things I come here to look up sporadically. So, cheers. :beers:

Good for you man. Good luck with your little project! I am sure it will help a lot of people (myself included).

EDIT:
One final question(s). Are there plans to eventually deprecate the Rules DSL? Or is all this other stuff supposed to exist in parallell to it? Forever? Or at least the foreseeable future?

Sometimes it’s easier to just answer than find a post. I think I discussed my reasoning somewhere in the Journey to JSR223 Python 1 of 9 or maybe in the Experimental Next-Gen Rules Engine Documentation 1 of : Introduction but didn’t want to scan through them to find. Some of those posts are old too and a lot has changed since posting.

As with anything, there might be quirks or odd differences. I’ve not encountered any but that doesn’t mean they are there. Zulu and OpenJDK are two implementation of Java and there are little differences in behavior and such between those too.

Think of it like differences between compiling with gcc verses xlc. They both compile C++ but there are differences.

All I can say for certain is that Rules DSL has been ported to and is available to run on the OH 3 Rules Engine (called the Next Gen Rules Engine, NGRE, Experimental Rules Engine, etc. in OH 2.). The current Rules DSL Rules Engine is gone but the language remains supported. For how long remains to be seen but I would expect the language to be supported for a good long time.

Rules DSL still has support in OH 3. But there will be subtle differences in how they run. I don’t know the extent of the differences yet.

1 Like