How to implement timer with parameter

So if you are still on OH 1.x it is likely that your Rules are executing before your Items have been fully loaded and their states restored. You can see this in openhab.log. I solved this in the past by making changes to openhab.cfg to make the file polling time for rules be much longer than for everything else. This will give enough time for the Items to be fully loaded and populated with restoreOnStartup (if you are using that) before any rules start executing.

This is less of a problem on OH 2.x though some have reported it as a problem. In those there are a number of mitigations that could be applied, probably the simplest is a sleep for a second at the start of the System started rule.

The true source of the problem is that there are no members of gIrrigation that are ON when the Rule execites in which case the line val curr = gIrrigation.members.filter[v|v.state == ON].head will return null.

This could also be a bit of a bug because I think the rule will also fail any time the system started and the irrigation was not running (i.e. all members of gIrrigation were OFF). The System started Rule should be changed to:

    if(curr != null) {
        Irrigation_Curr.sendCommand(curr.name)
        logInfo("Irrigation.0", "Sys Start: ...")

        // retrigger the cascade rule to recreate the timer
        curr.sendCommand(ON)
        logInfo("Irrigation.0", "Sys Start: ....")
    }
    else {
        Irrigation_Curr.sendCommand("None")
    }

With this change if the irrigation was not running then Curr gets set to ā€œNoneā€.

NOTE: It has been years since Iā€™ve looked at this code and it has a lot of moving parts. There may be some subtle side effect I donā€™t remember that may require more to be done.

Edit: Fixed stupid mistake on my part in the else clause. We need to send ā€œNoneā€, not curr.name because curr is null.

1 Like

Thank Rich, I always appreciate your inputā€¦
BTW: did you upgrade to OH2 yet?

I was hoping that the posters (@sherif, @MikeH) who implemented this solution would reply and maybe even share their exact set-up, for others to simply copy, thus avoiding making the same mistakesā€¦

I made the change, same resultā€¦
All switches/valves are off;

val curr = gIrrigation.members.filter[v|v.state == ON].head

returns null, log registers:

[m.r.internal.engine.RuleEngine] - Error during the execution of startup rule 'System started': cannot invoke method public abstract java.lang.String org.openhab.core.items.Item.getName() on null

ā€¦ and execution seems to stop there, as it does not enter the if/else

Code listed for completeness:

rule "System started"
  when
    System started
  then
    logInfo("Irrigation.0", "Sys Start: .")
    // assumes no more than one ON at a time
    val curr = gIrrigation.members.filter[v|v.state == ON].head
    logInfo("Irrigation.0", "Sys Start: ..")
    logInfo("Irrigation.0", "Sys Start: {}", curr)
    
    if(curr != null) {
      Irrigation_Curr.sendCommand(curr.name)
      logInfo("Irrigation.0", "Sys Start: ...")

      // retrigger the cascade rule to recreate the timer
      curr.sendCommand(ON)
      logInfo("Irrigation.0", "Sys Start: ....")
    } else {
      Irrigation_Curr.sendCommand(curr.name)
      logInfo("Irrigation.0", "Sys Start: .....")
    }
    
    // does not take into account how long it has already been running
end

I wrote the Migration Tutorial and upgraded to write that. Iā€™ve been running OH2 since before the 2.0 release.

When this clause runs you already know that curr is null so you canā€™t call curr.name here. You need to send ā€œNoneā€ as the command indicating that no irrigation is running (i.e. all the valves are OFF). That was a dumb mistake on my posting above. Iā€™ve fixed it there too. Your rule should be:

rule "System started"
  when
    System started
  then
    logInfo("Irrigation.0", "Sys Start: .")
    // assumes no more than one ON at a time
    val curr = gIrrigation.members.filter[v|v.state == ON].head
    logInfo("Irrigation.0", "Sys Start: ..")
    logInfo("Irrigation.0", "Sys Start: {}", curr)
    
    if(curr != null) {
      Irrigation_Curr.sendCommand(curr.name)
      logInfo("Irrigation.0", "Sys Start: ...")

      // retrigger the cascade rule to recreate the timer
      curr.sendCommand(ON)
      logInfo("Irrigation.0", "Sys Start: ....")
    } else {
      Irrigation_Curr.sendCommand("None")
      logInfo("Irrigation.0", "Sys Start: .....")
    }
    
    // does not take into account how long it has already been running
end
1 Like

Thanksā€¦ all sorted now and working :slight_smile:
Have updated my revival post (Mar 9) to show a working solution.

1 Like

Want to back to Irrigation case.
Thanks to Rich I build irrigation rules 3 years ago and it was working fine, even after my OH1.8->2.4 upgrade, done a year ago.
Problem appeared suddenly without touching anything. I have recognised that my irrigation doesnā€™t stop :frowning:. There were no errors, just one cicuit was on ā€¦ like infinitive time.
General code of ā€œIrrigation switch cascadeā€ I have exactly same as above. I have removed (in the begging) rule start, since it gave an error, but it works over 2 years.
Now I have added it (as above) and it looks that I have some problem with pointers:

2019-06-12 23:02:14.091 [INFO ] [se.smarthome.model.script.Irrigation] - Irrigation is complete
2019-06-12 23:03:09.827 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.2019-06-12T23:03:09.819+02:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@1ceb54e
} ] threw an unhandled Exception: 
java.lang.NullPointerException: null
	at org.eclipse.smarthome.model.script.engine.ScriptError.<init>(ScriptError.java:66) ~[?:?]

Problem is that sometimes it works without any issues and sometime it stucks.
If problem occurred in ā€œcascadeā€ then irrigation is all time on.

Any ideas how to troubleshoot ?

Just to be sure, were you editing other rules or items files beforehand?
When you edit a rules file, any currently scheduled timers continue to wait until their appointed time, then usually throw a null error.
When you edit items files, Items will be reset to NULL states.

Before I will trigger/ test a rule I always wait to see ā€œRefreshing model ā€¦ā€ in the log.
Also I ensure that all irrigation are off and cascade rule with timers was stopped.

This is a several years old post. Iā€™ve long since moved the code to itā€™s own design pattern posting and have tried to maintain that. Please review Design Pattern: Cascading Timers and make any updates necessary.

The error is occurring in a lambda somewhere, most likely the Timer but it could be any of them. Usually, when you see a null exception it is because of a problem with a type conversion (e.g. trying to cast or use the state of a Number Item in a calculation but the Itemā€™s state is actually NULL).

I have concerns including the following.

  • The System started Rule was there for a reason. Removing it to solve an error breaks one of the assumptions the other Rules depend upon and besides, itā€™s always better to fix errors than to eliminate code that does something to get rid of an error.

  • The code above was written for OH 1.8. Over the years that code has had numerous bugs fixed and itā€™s been rewritten at least twice. I couldnā€™t even guarantee that that code above exactly as it is written would even be valid.

You will need to add logging to verify which lambda (i.e. which [ | ] chunk of code) is throwing the error. Then wrap the code in that lambda with a try/catch and log the actual error. Sometimes this is very informative.

In general, when Rules have worked for a long time and suddenly stop working the cause is almost always because for some reason an Item was changed, restoreOnStartup didnā€™t reset an Item on time or for some other reason an Item is NULL or UNDEF and the Rule doesnā€™t know how to handle it.

Donā€™t discount rossko57ā€™s observation also. If you have a Timer running and then reload a .rules file, the Timer keeps running. And when it finally goes off the error usually looks just like what you posted. Waiting for the ā€œRefreshing model ā€¦ā€ before triggering the rule again and all the rest does nothing to get rid of the orphaned Timer. Itā€™s still there and will still throw an error when it goes off.