Fire for TIME IS Rule

Hello,

the simple question but i did not found it in specification.
There is a fire rule like

Time is midnight 
or Time is noon

Here are some specs https://www.openhab.org/docs/configuration/rules-dsl.html#time-based-triggers

So the question - how can i use this rule to Fire at some time from varialbe?
Like this

var timeVariable = "20:22:54"

And a rule above do not fires

Time is timeVariable

I am sure i can fire it if i use correct time format.
But which one?

Thanks a lot!

That is not a cron expression. Many people use the astro binding to get local sunrise & sunset times.

I know that it is not cron.
I do not need cron, i need time from variable
I have edited example to make it more clear

As state in the documentation, except for their predefined expressions, time is uses cron expressions.

U mean that there must be cron formatted time?

Like this in for example “54 22 20 ? * * *” ?

so rule will be

var timeVariable = "54 22 20 ? * * *"
time cron timeVariable

Here is a topic that you may find helpful with dates and times. DateTime Conversion

Here is a rule example for certain times of the day:

//Rule for using time events
rule "Calculate time of day state"
when
    Time cron "0 * * ? * *" 
//    System started or
//    Time cron "0 30 8 * * ? *" or
//    Time cron "0 0 0 * * ? *" or
//    Channel 'astro:sun:local:civilDawn#event' triggered START or
//    Channel 'astro:sun:local:civilDusk#event' triggered END 
then
    val String curr_time = now.toString("HH:mm")
    val String night_start = "00:00"
    var String morning_start = "06:00"
    val String day_start = (Sun_Dawn_Start.state as DateTimeType).format("%1$tH:%1$tM")
    val String evening_start = (Sun_Dusk_End.state as DateTimeType).format("%1$tH:%1$tM")
    val String midnight_time = "24:00"

    var new_val = "UNKNOWN"

    if (day_start < morning_start) {
        morning_start = day_start
    }
    switch true {
        case night_start <= curr_time && curr_time < morning_start:   new_val = "NIGHT"
        case morning_start <= curr_time && curr_time < day_start:     new_val = "MORNING"
        case day_start <= curr_time && curr_time < evening_start:     new_val = "DAY"
        case evening_start <= curr_time && curr_time < midnight_time: new_val = "EVENING"
    }
//  logInfo("Time_Of_Day", "curr_time=" + curr_time + ", night_start=" + night_start + ", morning_start=" + morning_start
//      + ", day_start=" + day_start + ", evening_start=" + evening_start + ", midnight_time=" + midnight_time
//      + ", new_val=" + new_val)


    if (Time_Of_Day.state.toString != new_val) {
        logInfo("Time_Of_Day", "Current time of day is now " + new_val)
        Time_Of_Day.sendCommand(new_val)
    }
    
end

And this is a rule to control a light using the Astro binding to turn it on and a cron time to turn it off.

rule "Front Porch Lights ON"

when

Channel 'astro:sun:5ed19d26:civilDusk#event' triggered START

then

	FrontPorch_Light.sendCommand(ON)

end


rule "Front Porch light OFF"

when

	Time cron "0 30 21 ? * *"             //OFF at 9:30 pm everyday

then

	FrontPorch_Light.sendCommand(OFF)

end

Between the link and both rule examples I hope you found something that helps.

2 Likes

You can’t.

All you can do is create a cron expression. See Rules | openHAB

No. You cannot use a variable in a Rule trigger.

What you can do is construct a rule that processes your “variable” for use in a createTimer() action, which is set to “go off” and run some code at a fixed future time.
You might trigger your rule when the “variable” changes, or at midnight, if you want to set up a time for the coming day.

Or you trigger a rule every minute and check within the rule if it’s time to execute some code.

It would be far better to set a Timer to expire at the right time than to set up a polling rule like that. But that isn’t what the OP asked. OP was presented with alternatives but want to know specifically how to use a variable in a trigger.

An every minute rule that checks a time to see if it’s time to run is an antipattern.

I see your point Rich. But, where in the code do you start the timer? You can set it by triggering a rule when the content of the variable changes, but this is going to work only for specific date/time settings. What about if you want to schedule something to run every day at a specific time contained in a variable? How do we avoid the polling?
thx

There are a few “alarm clock” threads. A general principle is that some fixed start-of-day time, say midnight, you run a rule that decides what fixed timers to set up for the coming day.

I’ve an example that I use to put down my blinds:

var Timer RSTimerUp = null
var Timer RSTimerDown = null

rule "Auto Rollershutter based on time"
when
	Member of RollerShutters_Auto_Timer received update
then
	val tdir = triggeringItem.name.split("_").get(3)
	val tstate = triggeringItem.state
	val timer_time = RollerShutters_Auto_Timer_Time.allMembers.findFirst[i|i.name.contains(tdir)]
	val timer_hour = (RollerShutters_Auto_Timer_HoursMinutes.allMembers.findFirst[i|i.name.contains(tdir+"_Hour")].state as Number).intValue
	val timer_minute = (RollerShutters_Auto_Timer_HoursMinutes.allMembers.findFirst[i|i.name.contains(tdir+"_Minute")].state as Number).intValue
	if (now.isBefore(now.withTime(timer_hour,timer_minute,0,0)) ){
		timer_time.postUpdate(now.withTime(timer_hour,timer_minute,0,0).toString)
	}else{
		timer_time.postUpdate(now.withTime(timer_hour,timer_minute,0,0).plusHours(24).toString)
	}
	if (tstate==ON){
		switch tdir{
			case "Down" :{
				if (RSTimerDown === null){
					logInfo("RSTimerDown","start Timer Down")
					RSTimerDown = createTimer(new DateTime(RollerShutters_Auto_Timer_Down_Time.state.toString), [|
						logInfo("RSTimerDown","Timer wordt uitgevoerd")
						RollerShutters_Auto_Timer_Down.allMembers.filter[i|i.state==ON].forEach[i|
							checkFirstRS.apply(RollerShutters.members.findFirst[j|j.name.contains(i.name.split("_").get(1))] as GenericItem, DOWN)
						]
						RollerShutters_Auto_Timer_Down_Time.postUpdate(now.plusDays(1).toString)
						RSTimerDown.reschedule(now.plusDays(1))
					])
				}
			}
			case "Up" :{
				if (RSTimerUp === null){
					logInfo("RSTimerUp","start Timer Up")
					RSTimerUp = createTimer(new DateTime(RollerShutters_Auto_Timer_Up_Time.state.toString), [|
						logInfo("RSTimerUp","Timer wordt uitgevoerd")
						RollerShutters_Auto_Timer_Up.allMembers.filter[i|i.state==ON].forEach[i|
							checkFirstRS.apply(RollerShutters.members.findFirst[j|j.name.contains(i.name.split("_").get(1))] as GenericItem, UP)
						]
						RollerShutters_Auto_Timer_Up_Time.postUpdate(now.plusDays(1).toString)
						RSTimerUp.reschedule(now.plusDays(1))
					])
				}
			}
		}
	}else{
		switch tdir{
			case "Down": {
				if (RollerShutters_Auto_Timer_Down.state == OFF){
					logInfo("RSTimerDown","stop Timer Down")
					RSTimerDown?.cancel
					RSTimerDown = null
				}	
			}
			case "Up": {
				if (RollerShutters_Auto_Timer_Up.state == OFF){
					logInfo("RSTimerUp","stop Timer Up")
					RSTimerUp?.cancel
					RSTimerUp = null
				}	
			}
		}
	}
end

In a sitemap I can set a time (hours/minutes) and a on/off that will start/stop de timer. The timer itself will restart everyday.