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.
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.
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.