Cron time in a rule with multiple timers and timer types?

Hi guys,

I already screened some posts regarding cron for a timed rule but I cannot get it together in my rule which needs sequential processing of the items, hence I have used cases and in them seperate timers because I need sequential processing plus different timer lengths in the cases.
Is this the best option for such a case?
So far this rule is working but how can I integrate cron and executed only once with a timer?

var Timer tAutoOff = null
var int iAutoOff = 0
var Timer t1 = null
var Timer t2 = null

rule "Morgenroutine "
when
Item LobbyMotionSensor changed from OFF to ON
then
if(tAutoOff !== null)                       // timer already scheduled, so leave rule
    return;
iAutoOff = 0                              // initialize counter
tAutoOff = createTimer(now, [|
    iAutoOff ++
    switch(iAutoOff) {
        case  1 : {
                AlexaTTS.sendCommand('XYZ') 
                broadlink_rm3_78_0f_77_5a_be_d1_command.sendCommand("NUBERTON")
                AllLightsSwitchGroup.sendCommand("ON") 
                Receiver.sendCommand("ON") 
                LivingRoomLoungeLight.sendCommand("ON")
                BedroomLoungeLight.sendCommand("ON")     
                }
        case  2 : {
                t1 = createTimer(now.plusSeconds(10), [|
                AlexaTraffic.sendCommand("Traffic") 
                AlexaTraffic.sendCommand("Weather") 
                ])
                 }
        case  3 : {
                Sonos_Master_Bedroom_Add.sendCommand("RINCON_000E582AC07601400")
                Sonos_Master_Bedroom_Add.sendCommand("RINCON_000E582AC07E01400")
                Sonos_Master_Bedroom_Add.sendCommand("RINCON_B8E93783325201400")
                Sonos_Master_Bedroom_Add.sendCommand("RINCON_B8E9375835EC01400")
                LivingRoomSonosVolume.sendCommand("89")
                SonosShuffle.sendCommand("ON")
                SonosPlaylist.sendCommand("Fluid")
                 }
        case 4  : DenonInput.sendCommand('MPLAY')
        case 5  : {
                t2 = createTimer(now.plusSeconds(10), [|
                NubertSelect.sendCommand("NUBERTCHANOPTICAL") ])
                 } 
        default : {
            tAutoOff = null
            return;
        }
    }
    tAutoOff.reschedule(now.plusSeconds(3))
])
end

Meaning two new features in this rule:

  1. Execute only on weekdays
  2. Only execute once (between 6 and 9 AM) and then let a timer run for x amount of hours to prevent 2nd execution.

I was trying to do multiple WHEN and AND clauses but this doesnt work.
Thank you for ideas and examples.

Happy holidays.
Cheers,
Henning

Hi, is there anybody that can help? Thank you :slight_smile:

Not sure we understand your problem. You’re obviously capable of writing fairly complex rules.

Which part of this are you having trouble with, finding out what day it is perhaps?

Think I’d use an on/off flag for this, not a timer.
At each rule trigger, check to see if now is 6-9am.
Check if flag is not-on, if ok then set flag on and carry on to do stuff.
Separate rule, at 09:01 each day or system startup, set flag off.

Maybe this will help

Look at Ephemeris. When configured you can use

if(isWeekend()){
  return;
}

and the rule will exit immediately on weekends.

I don’t understand the current approach. It appears the only purpose of the Timer is to provide an indication that the rule has run or not. But you schedule the timer for now so it immediately runs and exist so tAutoOff will only exist for a few milliseconds.

Often, trying to do too much all at once leads to more complicated and more difficult to read code. So maybe separate the timer that will indicated whether or not the rule has run from the code that does stuff. Create a global variable or use an Item like rossko57 suggests. Set the variable to true when the rule first runs. Create a Timer to turn it back to false at 09:00 today. Or you can forego the variable and just use the existence of the timer as the flag. But the only thing the lambda passed to the timer would do is tAutoOff = null.

Then move your switch statement and all the rest to the body of your rule. You’ll have checks to exit if it’s not between 06:00-09:00 or if tAutoOff exists and therefore the rule has already run once.

If writing rules in JavaScript or Jython I’ve some tools I’ve written that would be applicable here as well. For example, you can centralize the “is between 06:00 and 09:00” to a separate rule that calculates all your time of day periods. Then in a rule like this you can just check to see if TimeOfDate.state == "MORNING". With the Jython and JavaScript versions you can have different times of day per day type (as defined by Ephemeris) and you don’t need to mess with the code, just define Items with metadata.

Another useful utility is rate_limit. This is a little utility that lets you issue a command and prevent issuing another one for a defined period of time. For example the following Python:

rl.run(morgenroutine,  days=1)

will only allow you to call the function morgenroutine once a day. subsequent calls will be ignored. The JavaScript equivalent will be (I’ve implemented it but not yet committed it to the library:

rl.run(morgenroutine, "1d")

I need to port the change over to the Jython version that uses my timeUtils library that can convert all sorts of things to a ZonedDateTime, such as “1d5h15s” for example. That’s what the JavaScript version uses.

Great idea @rossko57 , I will try something like this :wink:

Hi Rich,

thank you for the detailed analysis :slight_smile: I will rework this code again based on your comments, lets see where it ends up. Just out of curiosity, I wonder why within the OH rule engine, there is no easy implementation for setting up rules and onetime execution? I mean cron is often used but I still wonder why there is no easier way, especially for users who only work with GUI/paperUI

Anyway, keep up the good work here, you are really helping us :slight_smile:

Happy holidays,
Henning

I’m not sure what you mean. If you create the rules through the UI you can first
heart click the play button to run it. This works in OH 2 5 and OH 3.

But one time execution isn’t what you are trying to do here. Remember that all rules in openHAB are event based, not be state based. You are trying to set up a time that ignores events for a given amount of time.