ruleDSL: If water level does not change within certain time

I am trying to add a safety feature to a working tank refill logic.

The system is running w/o fault for a few years now, however, today, a faulty valve (which did not open) presented the scenario that the pump would try to fill the tank, but couldn’t, because the tank level did not increase… hence, if this is not discovered by a human, the pump will run forever, eventually burning out.

My idea is to add a safety check, by checking every three minutes, whether the tank level has increased. If not, kill the whole tank filling process and send an email to that effect.

The rule would trigger on when Item Bore_Pump_Status changed to ON, set a timer to three minutes to then check if the new Tank_Irrigation_Level has changed, if not stop the tank fill process, and send email.

var Timer Timer_BorePumpSafety = null

rule "Bore pump safety"
        var int tank_level_old = (Tank_Irrigation_Level.state as Number).intValue

        Timer_BorePumpSafety = createTimer(now.plusMinutes(3), [|
            if ( (Tank_Irrigation_Level.state as Number).intValue - tank_level_old < 1 )
            {
                // stop re-fill process logic here
                Timer_BorePumpSafety?.cancel()
            }
            else
            {
                if (Timer_BorePumpSafety !== null)
                {
                    Timer_BorePumpSafety.reschedule(now.plusMinutes(3))
                }
            }
        ])
end    

rule "Bore Pump stopped"
  when
    Item Bore_Pump_Status changed to OFF
  then
    Timer_BorePumpSafety?.cancel()
end

The ON rule does not work; I get the error “Cannot refer to the non-final variable tank_level_old inside a lambda”.

Any hints appreciated. Maybe I am approaching this the wrong way?

The lambda is the timer code within the .
The non-final variable is about the var part.
The quick fix is to make it final, by using val instead.
You can do that here, because you don’t need to change that ‘old’ value later in this set up.

Having said that … I think there’s a snag here. What if you “pass ok” the first time period, but then the pipe blocks? Further checks will also “pass ok” because current level > start level.
I think you need to look at a rolling comparison? Is the level reading persisted?

The rule has evolved a bit…

rule "Alert when tank level does not increase and pump is running"
    when
        Item Bore_Pump_Status changed to ON
    then
        val BorePumpSafetyTriggerTime = 4
        g_tank_level_old = (Tank_Irrigation_Level.state as Number).intValue

        Timer_BorePumpSafety = createTimer(now.plusMinutes(BorePumpSafetyTriggerTime), [|

            if ( (Tank_Irrigation_Level.state as Number).intValue - g_tank_level_old <= 1 )
            {
                // stop re-fill process logic goes here
                
                if (Timer_BorePumpSafety !== null)
                {
			        logInfo(logPrefix + "1.1", "timer cancelled")
                    Timer_BorePumpSafety.cancel()
                }

            }
            else
            {
                if (Timer_BorePumpSafety !== null)
                {
			        logInfo(logPrefix + "1.2", "timer rescheduled")
                    Timer_BorePumpSafety.reschedule(now.plusMinutes(BorePumpSafetyTriggerTime))
                    g_tank_level_old = (Tank_Irrigation_Level.state as Number).intValue
                }
            }
        ])
end

I made the g_tank_level_old a global, which also removed the error.

Sounds like it… yes, level is persisted.