Irrigation Rule + multiple Timer

Hello,

I have a problem controlling my irrigation Rule.
The following rule is mostly from another forum and I have tried to adapt it to my environment.
I would like to be able to start three magnetic valves with a given running time.
If I turn the switches one by one, everything works. If the switches are activated simultaneously, the timers run for different lengths of time. Unfortunately I cannot explain why. I already used three separate timer
variables, but that didn’t really help either.

Openhab.log

2`020-07-14 20:39:16.253 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Regel ‘Irrigation3’: ‘cancel’ ist kein Mitglied von ‘java.lang.Object’; Zeile 84, Spalte 25, Länge 24

val String filename = “Irrigation.rules”

val IrrigationTimer = null

rule "Irrigation1"

when

        Item dummyMGV1_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer === null){

                        logInfo(filename,"Text")

                        IrrigationTimer = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV1_State.sendCommand(OFF)

                                Irrigation_R1_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer = null

                        ]

                }

                Irrigation_R1.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R1.sendCommand(OFF)

                Irrigation_R1_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer !== null){

                        IrrigationTimer = null

                }

                logInfo(filename,"Text")

        }

end

rule "Irrigation2"

when

        Item dummyMGV2_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer === null){

                        logInfo(filename,"Text")

                        IrrigationTimer = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV2_State.sendCommand(OFF)

                                Irrigation_R2_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer = null

                        ]

                }

                Irrigation_R2.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R2.sendCommand(OFF)

                Irrigation_R2_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer !== null){

                        IrrigationTimer = null

                }

                logInfo(filename,"Text")

        }

end

rule "Irrigation3"

when

        Item dummyMGV3_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer === null){

                        logInfo(filename,"Text")

                        IrrigationTimer = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV3_State.sendCommand(OFF)

                                Irrigation_R3_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer = null

                        ]

                }

                Irrigation_R3.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R3.sendCommand(OFF)

                Irrigation_R3_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer !== null){

                        IrrigationTimer = null

                }

                logInfo(filename,"Text")

        }

end

rule "Abort Irrigation"

        when

                Item dummyBeregnung_Disable received update ON

        then

              

        dummyMGV1_State.sendCommand(OFF)

        dummyMGV2_State.sendCommand(OFF)

        dummyMGV3_State.sendCommand(OFF)

end

Many thanks for the help!!

Every rule must have its own 'rule "blah"' header.
You’ve got

rule "Irrigation1"
when
then
end
when
then
end
etc.

That will probably be producing errors in your openhab.log at rules file load or refresh time.

I guess it got lost in the copy process.
In my rule I have the header :wink:
Corrected it above

The rule “Irrigation3” that you have shown us could not produce the error message relating to cancel, because there are no cancels in that rule.
(I think it would be a good idea if there were, though! Setting a timer handle variable to null does not stop or destroy a timer.)

It might be that you have another rule called “Irrigation3”, these names must be unique or they will overload each other.

or maybe you have an old rule version still in memory, and your edited file is not loading properly. You should always see an entry in your openhab.log about loading or refreshing a rules file.

If the “Irrigation3” rule shown was running, you would expect to see logInfos in your openhab.log, you haven’t shown those.
There would probably also be Item events to see in your events.log, you haven’t shown those.

You’re not going to get three different times without using three different timers.
It’s probably worth highlighting that when using
someVariable = createTimer (blah )
the variable is just a handle or pointer to the timer, which is running independently.
someVariable = null
does not stop an already running timer. The only way to do that is to instruct the timer using the handle
someVariable.cancel

i have now adjusted the rule as follows:

val String filename = "Irrigation.rules" 

val IrrigationTimer = null

rule "Irrigation1"

when

        Item dummyMGV1_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer === null){

                        logInfo(filename,"Text")

                        IrrigationTimer = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV1_State.sendCommand(OFF)

                                Irrigation_R1_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer = null

                        ]

                }

                Irrigation_R1.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R1.sendCommand(OFF)

                Irrigation_R1_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer !== null){

                        IrrigationTimer.cancel()

                        IrrigationTimer = null

                }

                logInfo(filename,"Text")

        }

end

rule "Irrigation2"

when

        Item dummyMGV2_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer === null){

                        logInfo(filename,"Text")

                        IrrigationTimer = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV2_State.sendCommand(OFF)

                                Irrigation_R2_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer = null

                        ]

                }

                Irrigation_R2.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R2.sendCommand(OFF)

                Irrigation_R2_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer !== null){

                        IrrigationTimer.cancel()

                        IrrigationTimer = null

                }

                logInfo(filename,"Text")

        }

end

rule "Irrigation3"

when

        Item dummyMGV3_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer === null){

                        logInfo(filename,"Text")

                        IrrigationTimer = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV3_State.sendCommand(OFF)

                                Irrigation_R3_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer = null

                        ]

                }

                Irrigation_R3.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R3.sendCommand(OFF)

                Irrigation_R3_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer !== null){

                        IrrigationTimer.cancel()

                        IrrigationTimer = null

                }

                logInfo(filename,"Text")

        }

end

rule "Abort Irrigation"

        when

                Item dummyBeregnung_Disable received update ON

        then

                // Beregnung abbrechen, wenn sie gestartet wurde

        dummyMGV1_State.sendCommand(OFF)

        dummyMGV2_State.sendCommand(OFF)

        dummyMGV3_State.sendCommand(OFF)

end

2020-07-15 12:58:04.184 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘Irrigation1’: ‘cancel’ is not a member of ‘java.lang.Object’; line 25, column 4, length 24

Does it work?

Looks to me that your shared timer handle will cause some odd interactions.
Example;
If you command valve 1 on, it turns it ON and sets up a timer to turn it OFF later.
If you now command valve 2 ON, it turns that ON but sets up no new timer at all.
If instead you command valve 2 OFF, it turns that OFF but cancels the running timer for valve 1, so valve 1 never gets turned off.

Not sure if that was intended.

I can confirm this. If only one valve is activated, the timer will fit.
If all valves are activated at the same time or more than one valve is activated, the timers are not correct.
If I activate all three at the same time, they should of course also go out at the same time, as the timer is identical.
The running time should actually be the same for all valves.

however I do not find the error or do not know how to adjust the rules

You’ve only got one timer handle variable.
Make a timer variable for each valve, amend your rules to use those. Each valve will do its own thing.

you mean like this?

if the var IrrigationTime is set to 5 sec. everything seems to work. if i set it a little higher 50 sec. not all timers run the same length. Very strange

val String filename = "Irrigation.rules" 

val IrrigationTimer1 = null

val IrrigationTimer2 = null

val IrrigationTimer3 = null

rule "Irrigation1"

when

        Item dummyMGV1_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer1 === null){

                        logInfo(filename,"Text")

                        IrrigationTimer1 = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV1_State.sendCommand(OFF)

                                Irrigation_R1_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer1 = null

                        ]

                }

                Irrigation_R1.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R1.sendCommand(OFF)

                Irrigation_R1_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer1 !== null){

                        IrrigationTimer1.cancel()

                        IrrigationTimer1 = null

                }

                logInfo(filename,"Text")

        }

end

rule "Irrigation2"

when

        Item dummyMGV2_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer2 === null){

                        logInfo(filename,"Text")

                        IrrigationTimer2 = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV2_State.sendCommand(OFF)

                                Irrigation_R2_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer2 = null

                        ]

                }

                Irrigation_R2.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R2.sendCommand(OFF)

                Irrigation_R2_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer !== null){

                        IrrigationTimer2.cancel()

                        IrrigationTimer2 = null

                }

                logInfo(filename,"Text")

        }

end

rule "Irrigation3"

when

        Item dummyMGV3_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer3 === null){

                        logInfo(filename,"Text")

                        IrrigationTimer3 = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|

                                dummyMGV3_State.sendCommand(OFF)

                                Irrigation_R3_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer3 = null

                        ]

                }

                Irrigation_R3.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R3.sendCommand(OFF)

                Irrigation_R3_lastRun.postUpdate(new DateTimeType())

                if (IrrigationTimer3 !== null){

                        IrrigationTimer3.cancel()

                        IrrigationTimer3 = null

                }

                logInfo(filename,"Text")

        }

end

rule "Abort Irrigation"

        when

                Item dummyBeregnung_Disable received update ON

        then

        

        dummyMGV1_State.sendCommand(OFF)

        dummyMGV2_State.sendCommand(OFF)

        dummyMGV3_State.sendCommand(OFF)

end

What makes you think that? You’ve got logInfo() in your rules, that would give you some idea of what is going on when, in your openhab.log. Taken with your events.log showing commands.
You could probably improve those diagnostics by not having all your logInfo() just say "text’.

I think now I’ve found the error.
i must have had a faulty configuration on the sonoff 4ch so not all outputs were deactivated at the same time. :fearful:
in addition the faulty timer… but now it seems to work

2020-07-15 22:46:03.010 [ome.event.ItemCommandEvent] - Item 'dummyMGV2_State' received command ON
2020-07-15 22:46:03.018 [ome.event.ItemCommandEvent] - Item 'dummyMGV1_State' received command ON
2020-07-15 22:46:03.020 [vent.ItemStateChangedEvent] - dummyMGV2_State changed from OFF to ON
2020-07-15 22:46:03.020 [vent.ItemStateChangedEvent] - dummyMGV1_State changed from OFF to ON
2020-07-15 22:46:03.163 [ome.event.ItemCommandEvent] - Item 'dummyMGV3_State' received command ON
....
....
2020-07-15 22:47:06.665 [ome.event.ItemCommandEvent] - Item 'Irrigation_R2' received command OFF
2020-07-15 22:47:06.679 [ome.event.ItemCommandEvent] - Item 'Irrigation_R3' received command OFF
2020-07-15 22:47:06.690 [ome.event.ItemCommandEvent] - Item 'Irrigation_R1' received command OFF

as you can see all valves get the off command at the same time.

many thanks for the support !!!

1 Like

Hi,

I’m currently still encountering new problems.
I would like my pump to be switched off about 10 seconds before the valve.
Can I check the remaining running time within the timer?

for eg
if (IrrigationTimer1 = “10 seconds remaining”’) {
pump .sendCommand(OFF)
}

when

        Item dummyMGV1_State received command

then

    if (receivedCommand == ON) {

                if (IrrigationTimer1 === null){

                        logInfo(filename,"Text")

                        IrrigationTimer1 = createTimer(now.plusSeconds(Integer::parseInt(IrrigationTime.state.toString)))[|
                                
                               if (IrrigationTimer1 = "10 seconds remaining"') {
                               pump .sendCommand(OFF)
                                 }
                          
                                dummyMGV1_State.sendCommand(OFF)

                                Irrigation_R1_lastRun.postUpdate(new DateTimeType())

                                logInfo(filename,"Text")

                IrrigationTimer1 = null

                        ]

                }

                Irrigation_R1.sendCommand(ON)

                logInfo(filename,"Text")

        } else {

                Irrigation_R1.sendCommand(OFF)

                Irrigation_R1_lastR
[details="Summary"]
This text will be hidden
[/details]
un.postUpdate(new DateTimeType())

                if (IrrigationTimer1 !== null){

                        IrrigationTimer1.cancel()

                        IrrigationTimer1 = null

                }

                logInfo(filename,"Text")

        }

end
....

No,not accessible.
You could set up two timers to begin with, with different durations.
Or you can use one timer that does task A, then itself sets up the timer for task B.

thanks a lot.
I have found a solution with two timers
Topic can be closed!