[SOLVED] How to create a rule that runs every other day?

Hello everyone, I’ve been looking for the last few days and I didn’t find anything similar, so I decided to create this topic.
My problem is create a rule that runs every other day, for example:

  • Run day 1, not run day 2, run day 3…

My first idea was to run every day with a cron-based rule and store it in a datetime item when it was last run, and the next day check if is 2 days after the last run and decide to run or not.

If anyone can help, I’ll be very grateful.

What about a cron that runs every 2nd day:

1 Like

Really for my case does not work, I wanted it to be exactly that run every other day. Because I need to apply a chemical automatically every two days

Set a virtual item with an expire for 48 hours (or some other amount of time), turn it on when you want it to be turned off 48 hours later and setup a rule based on that virtual switch changing; you could even set the rule to turn the switch back to ON for you.

Thank you, I had not thought of this alternative. I’ll test it right now.

A specific cron expression does not seem to be able to handle what you want to achieve. What about an approach like this:

var int DayCount = 0

rule "Run every other day"
when
	Time cron "0 0 0 ? * *"	// run every day at midnight
then
	DayCount += 1
	if (DayCount % 2 == 0) {
		logInfo("everyotherday.rules", "Doing nothing")
		return;
	}
	logInfo("everyotherday.rules", "Executing desired actions")
end

You can also think of persisting DayCount as a virtual item so that you can avoid unnecessary runs on two consecutive days when you need to restart openHAB.

You have not fully listed your requirements, because as you stated Sacha’s solution meets all the requirements you have stated. It runs a Rule exactly every other day. What is it about a cron trigger that runs every other day at 23:00 that doesn’t meet the requirement to “exactly run every other day”?

The Sasha’s solution wouldn’t work in my case, because when it was performed Saturday, Sunday was also executed. In my situation it would be a problem because I can’t perform in two days in a row.

The Michael solution looks like all what I need, thanks!

Ah, ok, there is a typo. The expression should be

0 0 23 ? * */2 *

There is still a problem, when it is the next month the rule will be executed on day 1, but for my case it should be on day 2 since in the previous month it was executed on day 31.
I don’t know if it’s possible with a crontab expression

Thanks Michael, it was a great idea.
And that’s my rule:

var Number day = MyDay.state

rule "Run Every Other Day"
when
    Time cron "0 0 19 1/1 * ? *" //Run every day at 7PM
then
    day += 1
    MyDay.postUpdate(day)
    
    if (day % 2 == 0) {
        logInfo("everyotherday.rules", "Do nothing")
        return;
    }
    
    say("Today is the day!")
    logInfo("everyotherday.rules", "Today is the day!")
    LastRun.postUpdate(new DateTimeType())
end

If anyone wants to do something similar, I hope this can help.

To survive an OH reboot, you will want to use persistence with restoreOnStartup on the MyDay and LastRun Items.

Also, MyDay will continue to grow. While I don’t think this will ever remotely be a problem (assuming it’s a BigDecimal it will be many many many years before it needs to use an extra byte of memory. But if you care about this sort of thing you can use something like:

day += 1 % 2
if(day == 0){

Thus day will never grow above 1.

Or because there are only two states you can just use a Switch.

    val newState = if(MyDay.state == OFF) ON else OFF
    MyDay.postUpdate(newState)
    if(newState == ON) {
        logInfo("everyotherday.rules", "Do nothing")
        return;
    }
    say("Today is the day!")
    logInfo("everyotherday.rules", "Today is the day!")
    LastRun.postUpdate(new DateTimeType())

It might be a bit clearer to split it into two Rules in that case:

rule "Today's the day?"
when
    Time cron "0 0 19 1/1 * ? *"
then
    MyDay.sendCommand(if(MyDay.state == OFF) ON else OFF)
end

rule "Every other day"
when
    Item MyDay receivedCommand ON
then
    say("Today is the day!")
    logInfo("everyotherday.rules", "Today is the day!")
    LastRun.postUpdate(new DateTimeType())
end

The Number mod approach is a bit more generic as it will work with 3, 4, 5, etc days between running.

2 Likes

You are welcome, @fmrenan! :blush:

I also really like @rlkoshak’s refinements! :+1:

1 Like

Thak you very very much guys @rlkoshak and @miba. I’m using the two rules by Rich, it’s perfect!
Yes, all of my items are persisted with mapdb to restore and influxdb to charts.

rule "Today's the day?"
when
    Time cron "0 0 19 1/1 * ? *"
then
    MyDay.sendCommand(if(MyDay.state == OFF) ON else OFF)
end

rule "Every other day"
when
    Item MyDay received command ON
then
    say("Today is the day!")
    logInfo("everyotherday.rules", "Today is the day!")
    LastRun.postUpdate(new DateTimeType())
end

@rlkoshak:

I was curious to try out this snippet

and found out that the day variable keeps growing instead of switching between 0 and 1. I suspect the modulo operation is being ignored here. Maybe the augmented assignment does not allow such an expression?

Nevertheless, this statement works:

day = (day + 1) % 2

Regardless of that, I find your solution with the 2 rules very straightforward.

That’s right.

I apparently wasn’t thinking when I wrote the original.

day += 1 % 2

Is exactly the same as

day += 1

Your statement is what I should have written in the first place. Thanks for posting as it will be needed by any future readers who want to do every 3 or more days.