Run a rule in a given time range only once a day

I got a rule that starts my favorite radio station in the morning. It is triggered by a motion event and active only in between 7 and 8 am:

rule "Breakfast radio"
	when 
		Item HueMotionEvent changed from OFF to ON
	then
		if(now.getHourOfDay() >= 7 && now.getHourOfDay() < 9){
			if(sonosplay3_state.state == "STOPPED"){
				sendCommand(sonosplay3_radio, "radio")						
			}	
		}		
end 

This works fine, but the problem is that the rule is triggered every time the motion event is fired in that time range. So if I decide to turn off the radio, it will promptly be turned on again with the next motion event.

I think one way solve that is to run that action (the then part of the rule) only once a day. Perhaps by storing the last execution day in persistent storage (MapDB)?

Can you help a beginner? I have no idea how to express that in code…

2 Likes

Create an Item that holds the information, for example a number item which is normally 0 . When the rule is fired within the timeframe and this item.value is 0 turn on the radio AND set the item to 1.
When the rule is fired again it should the timeframe and the value of the item. Switch on the radio only within the timeframe AND if the item is 0.
Additionally create a Cron triggered rule that resets the item to 0 once a day after the timeframe of the other rule.

2 Likes

Hi Jürgen,

thanks for your feedback.

Do I have to have a persistence service like MapDB installed for your solution to work?

Regards

Horst

My solution needs only the item, the Cron rule and the change of your rule (additional if clause ).
No persistence for that neded.

…but persisting the new item would help if you restart openhab within your time range and the rule was already triggered.
Then the persistence (with restoreOnStartup) will set the new item to 1 again.
Without persistence, it would stay at 0 (or NULL) after a restart.

1 Like

Correct, however for the feature requested itself, persistence was not needed.

If you didn’t want to have a second from rule you could also just install a 2 hour timer in your current rule to reset the state of your lockout item.

1 Like

This is an example with the code that solves my problem. Thanks for your help! :+1:

Item definition
Number RunToday

Rule

var ruleName = "test rule"
rule "test rule"
	when 
		Item ManualTrigger changed
	then
		if(RunToday.state==1){
			logWarn(ruleName, "Job already done")
		}
		else{
			logWarn(ruleName, "Trigger!")

                        // remember we already did our job	
			postUpdate(RunToday, 1) 

                        // reset the flag after some time
			createTimer(now.plusHours(3), [|postUpdate(RunToday, 0)])	
		}
                // optionally persist the flag
		RunToday.persist
end
1 Like

Actually, since it’s a single rule you could use a variable rather than an item. That way if your statement goes down before the timer finishes it will reset.

But a variable will loose its value from one trigger/run to the next, won’t it?

So with every trigger the variable will have its start value 0. Did I miss something?

No, you would set it to null outside the rule (which is what would clear it on a restart), then in the rule you’d have the same if/else logic and set the variable value in place of your postUpdate’s

Just dawned on me this morning that you can use the timer status and skip any variables.

var Timer tRun = null
rule "test rule"
	when 
		Item ManualTrigger changed
	then
		if(tRun == null){
			logWarn(ruleName, "Trigger!")
			tRun = createTimer(now.plusHours(3), [|logWarn(ruleName,"Timer Off"]	
		}
		else{
			logWarn(ruleName, "Job already done")
		}
end
2 Likes