Variable in cron

Tags: #<Tag:0x00007fc8fd195668>

In order to set an alarm from the GUI I would like to pass a variable as the argument to cron.

This works:

rule "Wake up"
when
  Time cron "00 00 06 * * ?"
then
  // ...
end

This does not work:

var morning = "00 00 06 * * ?"

rule "Wake up"
when
  Time cron morning
then
  // ...
end

Should this be possible to do?

You can’t do that. Triggers are static, you can’t define them with a variable.

There is no elegant way to do this. You can create a rule that triggers frequently (e.g. once per minute) and checks to see if now has just passed “morning”.

Yeah, kind of not-elegant but certainly a way forward.

The feature I’m trying to add is to change an alarm time from the GUI. Maybe there is another way (like an addon) that helps out with this?

You can do this type of thing with JSR223 (e.g., Jython) rules.

I guess this could also be done by using createTimer(). When you set an alarm time in the GUI, you need to trigger a rule that converts the alarm time to “a number of minutes into the future from now” and use this as input to the now.plusMinutes() in the call to createTimer().

In the same rule you would also have to take care of killing any existing timers, in case you need to change the alarm time.

I am sure this will not win an “elegant way to do this”-award, but at least it provides an alternative to the polling method.

1 Like

I’m afraid there isn’t one I’m aware of. This is not the first time someone
has asked for something like this but the problem is two fold. There really
isn’t a good way to enter the new date/time on the sitemap and there isn’t
really a good way to trigger a rule using a variable date/time.

The Astro binding’s way of triggering a switch could be used for
inspiration on a new binding. Though I would wait and see what new features
oh2 brings before starting something new.

Hey, this is really interesting for me. Not just for wake-up alarms but also boiler / heating rules. (i.e. ability to tweak heating times from sitemap).

Let me know if you ended up using solution posted by @rlkoshak above, and how you did it…

I may end up using Google Calendar to set my alarms, which I suppose provides a more simple and arguably more flexible solution

I like this approch the best. Though you will want some logic on System Started to recreate the timer in the event of an openHAB restart.

Sounds like a good reason to use the JSR223 rules engine. This gets asked often enough perhaps it is worth adding it as an example to the wiki.

I didn’t read the original question as carefully as I should have and I should clarify my response.

It’s easy with JSR223 to have a configurable rule that has the cron specification parameterized. For example, someone could have a reusable rule class that is parameterized with different cron specs for different contexts. I don’t think it is possible change the cron spec after a specifc rule instance is created. However, I think it could probably be supported without much difficulty.The timer trigger is an object so it’s API could be extended to support changing the cron spec (and updating the corresponding Quartz scheduler job).

But none of this solves the UI part of the problem.

I created a GUI of sorts for a similar problem. I simplified it by assuming that I can only set times in 15 minute increments, and I set the time as a number e.g. 0900 or 1245.

I used a setpoint to adjust them with a minvalue of 0 and a maxvalue of 2345, step 15, which forces the 15 minute increments.

I then wrote a rule that notices whether you’re going upwards or downwards when you adjust it, and moves 1245 up to 1300, and 1300 down to 1245.

The upshot of all this is that I get a setpoint that only accepts values from 00:00 to 23:45, only accepts values in 15 minute increments, and ticks up or down in 15 minute blocks including wrapping from 45->00 minutes on the way up, and 00->45 minutes on the way down.

The sitemap is something like:

Setpoint item=timeStart1Guest minValue=0 maxValue=2345 step=15

Then in the items we have something like:

Group:Number:SUM zoneSettingsTimes (All)
Number timeStart1Guest "Time Start [%04d]" <clock> (zoneSettingsTimes)

This means I can tell when any time has changed it’s setting, as the zoneSettingsTimes (which is a sum) will change. I run time normalisation rules any time any time field has changed:

import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.openhab.core.library.types.DecimalType

/*
  This set of rules normalise the time fields in each zone, so that minutes are always
  in 15 min blocks, and wrap around at 60, not at 99
*/

/*
  Function defined as a lambda.  Stupid function syntax if you ask me!!
  This looks at the minutes, if it's 85 then we went down, and should be 45, if it's 60 then
  we went up, and should be 00 plus add one to the hour
*/

val org.eclipse.xtext.xbase.lib.Functions$Function1 normaliseMinutes = [
    org.openhab.core.library.items.NumberItem timeStart |
  var int currentHours = (timeStart.state as DecimalType).intValue / 100
  var int currentMinutes = (timeStart.state as DecimalType).intValue % 100

  if( currentMinutes == 85 ) {
    currentMinutes = 45
  }

  if( currentMinutes == 60 ) {
    currentMinutes = 0
    currentHours = currentHours + 1
  }

  if( (timeStart.state as DecimalType).intValue != currentHours * 100 + currentMinutes ) {
    postUpdate( timeStart, currentHours * 100 + currentMinutes )
  }

]


/* 
  Time normalisers - call the time normaliser whenever a Time field gets changed
*/
rule "Modify Time - adjust minutes"
when
  Item zoneSettingsTimes changed
then
  zoneSettingsTimes.members.forEach( time | {
    normaliseMinutes.apply( time )
  })
end

This all works well enough, although the UI is quite laggy on my raspberry pi.

1 Like

This is a very neat solution.
For openHAB2 users, if the parameter is fully qualified like this:

the call to it passes in a null object.

The solution that worked for me was just to declare it as just
NumberItem timeStart