OH 2.x Timer Things

To summarize the discussion about Timers from https://community.openhab.org/t/what-are-possible-values-for-the-json-property-context-in-a-module-definition/55945/9:

The NGRE does not support global varaibles. This invalidates most of the use cases for Timers. Expire Binding is not a suitable replacement because it is a 1.x version binding and we cannot calculate the time in a Rule, it has to be hard coded.

Sort of but I’ve been struggling to think of how it would work. With Expire binding it is pretty clear. 1 Item to 1 binding config.

How would it work with the Things and Channels approach? If I want 5 timers, each representing a separate timer do I need 5 Channels? What if I don’t know ahead of time how many timers I need? How do I start the timer running and tell it how long to run from a Rule?

Maybe there is a “Create timer” Channel that we can link to an Item and post the time for the Timer to go off. But then how do I tie that newly created Timer with a Rule to trigger? If we use Channel triggers I would have to know ahead of time what the Channel ID is to set it up to trigger the Rule.

I’ve given it some thought and I’ve yet to come up with a way to replicate what we have now with Timers using Things and Channels. I’m definitely open to ideas though because this is going to be a major pain point for current Rules DSL users transitioning to the NGRE. And having a 2.x replacement for the Expire binding would be a boon as well as it won’t force users out of PaperUI for Items.

The requirements as I see them are:

  • indefinite number of timers, we don’t always know how many we need ahead of time (we might be able to live without this)
  • arbitrary timer times determined at runtime, not hard coded into the Thing/Channel definition
  • determine if a given timer is scheduled or expired
  • reschedule the timer
  • cancel the timer

Take away the last three and we can do this now with fire and forget Timers. It’s the last three requirements that necessitate something to replace the global variable.

Maybe we drop the first requirement and set up a Thing for each Timer we ant to use. The Timer has four Channels, a create timer that takes a DateTime (or maybe a Number that takes a milliseconds from now, or both), an isScheduled Channel that links to a Switch, sending OFF to this channel cancels the Timer, and a trigger Channel. The body of the Timer is a Rule that gets activated by the trigger Channel.

I think that could work. I don’t particularly like needing to predefine the Timers like this but I do think it can work.

Or perhaps we have have just one Thing that we pass an ID and a time to expire and it creates a Timer. The Channel trigger returns the passed in ID and we can create a rule that triggers on the one Channel trigger but on the returned ID.

:exploding_head:

I’m coming into this with zero knowledge of what came before, but wonder if something like this might work.

An indexed database of events consisting of say, a time, a pointer to a rule, a number of times left to repeat and how long before I repeat.

Then a global single timer only needs to trigger on the next event, follow the rules for that event and then prepare to wait for the next event. It’s essentially unlimited and only needs one small thread to handle all timed events. I only ever thought about this as it relates to appointment calendars which is where that came from but it seems like it might lead to something easy and workable. I guess there might be issues if to many things are queued at once, but I guess that’s always a problem. Maybe there needs to be a priority field so less important things can run a bit late.

Then again, I have no idea what the goal is so maybe that makes no sense. It would benefit from a whatever.timer file that had a list of repeating timers to implement along with a way to post a simple timer to the engine. It might also change the syntax of rules because you might end up with something like:

Post_timer(now.addseconds(5), GarageLight.sendcommand(“OFF”))

Which causes GarageLight.sendcommand(“OFF”) to be executed in the future out of the context of the rule that posted it.

Ira

Reading a bit more, I guess there would also need to be a way to add time to or delete a posted event so posting would have to return a handle in case such a thing might be needed.

Ira

1 Like

Use-cases

@rlkoshak
Rich, I think you are too much in an imperative way of thinking like
“I want to create a timer that does this”.

I propose to shift the perspective a bit and think from a declarative point of view:
“This rule need to be repeated 3 times”.

The following declarations came to my mind:

  • Repeat rule x times
  • Delay rule execution
  • Execute on date/time x

Of course, every of those scheduled events should be cancel-able.

You know the community quite good, what use-cases can not be realized with those declarations?

Does this really happen? If we can solve 99% of all use-cases with a simple design, let’s first go with that simple design. Some DSL rules would need a different (hopefully simpler) approach while being migrated.

Implementation of “Execute on date/time x”, “Repeat rule x times”

Yes exactly. The idea is that you have an overview of existing “timers”. Right now there is no way to tell how many timers are active in openHAB. Even worse: They all use a separate thread and that is like @Ira said not ideal. One thread should handle all timer executions, by managing a priority queue.

I propose a “Relative Timer trigger channel” that has this configuration:

  • “repeat times”. Empty means no restriction. The timer will only trigger repeat times.
  • “relative time”. The relative target time.
  • “relative time unit”. Default seconds. Can be milliseconds, seconds, minutes, hours, days".
  • “enable”: Default true. As soon as the configuration changes to enabled, the channel will trigger in “relative time in seconds”. As soon as “repeat times” reach 0, this configuration is updated to “disabled”.

A property with a “unique timer id” is added to the channel. A property “loops” tells how many times the timer got executed since the last (re)start.
Such a channel can be added to a channel group, for grouping specific timers together.

I also propose a few rule actions in that timer binding:

  • Create a “Relative Timer trigger channel”.
  • Enable/disable/restart a “Relative Timer trigger channel” by its “unique timer id” or by channel group.

Implementation of “Delay rule execution”

Right now there exists the “Execute rule” action. I propose to add an optional time input, that delay execution of the rule by that time.

Cheers,
David

1 Like

I’d suggest to select a start time instead of just starting at configuration enabling.

So let’s say I want to repeat an action every 15 Minutes:

  • Repeat time would be at no restriction
  • Relative time would be 15
  • Relative time unit would be minutes
  • Start time could be any value, but would make sense to put at 00.00., so it triggers at 00.00, 00.15, 00.30 etc.

If i want it to execute at 12.00 12.15 and 12.30, i would set

  • Repeat time at 3
  • Start Time at 12.00

WIth start time it knows exactly at which times it should trigger and therefore there doesnt need to be any enabling/disabling the whole configuration.

@David_Graeff, @Eseraz

What about absolute times:

Every night I calculate the different Islamic prayer times and I assign each of them to a timer that triggers at the time specified

I think for times that need dynamic calculation every day, it would be more useful to create a separate binding. For example the Astro Binding provides Channels for nearly every dynamic time of day like sunset, sunrise etc…

This discussion has already happened and the astro binding is not usable for this purpose. These calculate relate to the sun position but depend on a number of other cultural parameters.

I can’t write a binding. I am allergic to java.

I would like to keep absolute time timers, please.

Yes, I didn’t mean that you should use the Astro Binding for that purpose, I meant that it would be necessary to write another Binding for that purpose.

Imho what you want is a dynamic time which is automatically calculated every day. Right now I can’t think of a way to make this happen with statically given values. Imho you always need some kind of script to calculate these values dynamically.

Just to add to the wish list, since it crops up as “how do I…” from to time -

Ability for a rule to read back unexpired time (or target timestamp, since one can be calculated from the other) from an active timer umm Thing.

I wonder how exploitable the discvery mechanism is, which allows bindings to create new Things. This would require the invention of a rules-based means to prompt the creation. Perhaps that would take the form of -
I want to use a timer Thing named XXX. If you haven’t got one, make one.

There is a cron binding for absolute times. Off course someone has to port it to OH2, but it falls into the responsibility of the cron binding, not the proposed one.

Ok, never hear of it. Could you point me to it, please. It is not in the PaperUI.

I’m confused, in what I talked about and what everyone else seems to be talking about solving the islamic prayer time problem involves one repeating timer and a triggered rule. The repeating timer fires every morning before first possible prayer time and repeats every day. It triggers a rule that calculates and creates single event timers for each prayer time. How is that complicated?

I also realized after I said it that the idea of returning handles is a bit alien to this project and so probably there needs to be a way to pass a name while creating a times so it can be accessed again in the future. that seems to be a better fit for this project.

Ira

It is complicated because there is no such think as a timer of any type right now thus this thread to discuss different proposals of how to introduce timers.

That is why my proposal wants the user to create timers beforehand (as channels so they have a unique channel id).

This isn’t too far from my understanding of how the Quartz scheduler in Rules DSL, which is how Timers work there is implemented. There is also a thread pool though because you can and will have multiple Timers that expire at the same time or while another Timer is actually executing (as opposed to waiting to execute) so when it comes time to execute the body of a Timer that happens in another thread.

Look at some of the links I have below for common uses of Timers.

Perhaps. But I’m coming at it honestly. There are a whole bunch of common problems users need to solve and I’m coming at this from the perspective of “today I solve problem x using a Timer to do y, how do I solve the same problem in NGRE without a Timer that persists?” which leads to “how do I create a Timer that does this.”

I’m very open to alternatives, so long as all the problems that we can currently solve using Timers have a solution and that solution is not significantly more work than what we can do today.

Some example uses for Timers in Rules DSL include:

There are more but these are the ones based on DPs I’ve written.

I would add a “Repeat rule with y delay until z condition is met” though I suspect rules will be involved to achieve that.

As long as these scheduled events can be cancelled and rescheduled from a rule I think that covers it.

I think that would cover the what. It’s the how that I’m more concerned about though which may be me getting too far ahead.

Yes, it comes up from time to time. Though we can probably work around it.

One thing I want to be careful of though is we don’t want to make decisions that will make it harder for developers to write Rule templates and libraries. Ultimately, we want to get to a point where non-technical users are not writing Rules at all but installing pre-written ones from PaperUI. And in that case, the code inside the Rules will not be able to know ahead of time how many Timers are needed or potentially what they are called.

Ever, on each run of OH, or each time it is executed? I think I need more to understand what you are thinking with the repeat times. This isn’t actually a use case that I’ve seen come up before. Usually when one wants to repeat a timer’s execution it is until some condition is met. I’m intrigued by the idea of a repeat times but I’m not sure how it could be used just yet.

So are all of these configurations Channels I can link to Items? Otherwise how do I kick off a Timer in response to some event? If enable is a Channel I can link to an Item, are the rest of the configuration parameters also Channels I can link to Items?

From a usability perspective though this is starting to look like a lot more work. Right now from one Rule I just need:

myTimerMap.put(triggeringItem.name, createTimer(now.plusMinutes(5), [ | // do stuff ]))

My best understanding of the proposal means I now need to:

  • Create a Thing for every Timer I may ever need
  • Create 2-4 Items that link to the various channels of the Timer so I can enable/disable/reschedule/adjust parameters from a Rule
  • Create a new Rule triggered by the Timer’s trigger Channel which is where I put // do stuff. Of course, the context that I would normally have in the timer body (i.e. all the variables that existed when the lambda was create gets persisted in the lambda so I can, for example, reference triggeringItem inside the timer’s lambda) and all that will be lost in this separate Rule

It feels like a lot more work clicking together a bunch of Items and Things and I’m losing just a little bit of capability. But I think this might get us 75%-80% there.

This is an area that needs some more exploration. How do I keep track of these IDs? If I’m going to enable/disable/reschedule the timer by ID from a Rule then I need some way to associate the Timer ID with events from a given Item in a Rule. If I’m going to write generic Rules, I can’t hard code this ID into the Rule. So how would that work?

How many of the parameters can be configured through the create timer Action? All of them or only create one with the already preconfigured parameters on the Thing?

I guess I’m just a little confused how this all would work together. I like all the ideas independently but as I think about how I would go about using it I can’t figure it out. I’m sure I’m just missing something.

I can see a couple of usage scenarios:

  • Create a new Timer channel for each Timer you will need and set all the configurations for each, including the ID. In a Rule, when it is time to trigger a Timer, I sendCommand to an Item linked to the enabled Channel for that Timer. I have another Rule that gets triggered by the trigger channel when the timer expires. How does the Action work in this usage?

  • In a Rule I know I need to create a Timer. I use the create a timer Action to configure and schedule the Timer. I have a Rule that gets triggered by the trigger channel. How do I know what the trigger channel is to create this Rule?

I love this, but one thing I haven’t figured out yet is how to execute another Rule from inside the Script of a Rule? Sometimes deciding whether or not you need a timer, and especially to cancel a timer depends on the results of a bunch of other calculations.

One concern I’m having with the NGRE over all is the logic is becoming dispersed all over the place. There won’t be any way to just look and see everything all in one place. I’ll have at least two Rules with logic split between but only if and actions. If the only way I can use Delay rule is by the Execute rule Action and I can’t use if from inside my Script Action I worry about maintainability. Perhaps with Yannick’s UI this won’t be as big of a deal but with PaperUI I have real concerns.

I think that is what David’s Execute on date/time x is for. In that case it would repeat exactly once at the specified date and time.

Wouldn’t one do this through a Rule trigger instead of a Timer?

In my mind Timers are used to schedule something to occur in the future based on some event, like a door opening. It seems awkward and out of place to implement cron type expressions using Timers. Though perhaps there can be synergies reached if both types of scheduling are merged…

But the “separate binding” is actually what we are talking about here. Essentially we are talking about a 2.x replacement for Timers in Rules DSL and the 1.x Expire Binding. I think you are talking about Time cron "..." Rule triggers.

That is also something that is mostly missing from the NGRE and needs to be addressed but not what we are discussing in this thread.

That is what we are working through.

And actually so long as you don’t have to reaccess the Timers to reschedule or cancel them from some other Rule the NGRE handles this now. The missing part is that there is no way to persist any variables from one run of a rule to the next or across rules. So we can create Timers but as soon as the Rule exits so do the references to the created Timers. But the Timers are still there scheduled in the background.

In short, I don’t think you have anything to worry about. And this thread is to make sure you have nothing to worry about going forward.

Correct, which is what Vincent currently uses. He executes a perl script to calculate the times (IIRC) then creates a Rules DSL Timer to execute a function at the calculated times. In this thread we are trying to come up with an OH 2.x NGRE approach that preserves the ability to continue doing this (and other Timer use cases).

Shouldn’t be hard to get that from a Channel on the Thing.

I was not clear enough, I guess. The trigger channel is THE one and only available channel but it has multiple configurations, like Thing configurations. You are not creating a single item at all. Trigger channels are directly supported by the rule engine.

To modify a timer, you would alter the configuration value of the destination timer. It is not possible with the currently available actions of the NRE.

Just trying to understand. Is the trigger channel the same as a trigger in the new rule engine? And can’t these timer kinds be implemented as different new trigger classes and as such become available for the user?

If I’m understanding you correctly, this means from a Script Action I cannot enable or schedule or cancel or reschedule a Timer?

I don’t like that at all.

Maybe I’m jumping the gun, but how would I implement, for example Motion Sensor Timer DP above?

In this case the motion sensor generates an event, I schedule a timer, subsequent events reschedule the timer further into the future, and only after X minutes after the last motion event does the timer go off. To add a wrinkle, let’s say I want to use a different X minutes for the timer during the day and at night.

Maybe a concrete set by step would help me see how this could work.

1 Like

I have created an issue:

1 Like