Value changes too fast and rule keep executed at half

Hi,
i have this rule that read the value of how much energy i’m using (read from a modbus module every 2 seconds) and sent notification to my Google Nest Mini. Another rule should let me know when power levels are back to safe level again.

The problem is: the rules seems to have no time to be completed that the rules get triggered again.
My aim is to “delay” the rule for 5 seconds to check that is not a consume spike (ex: trigger the rule when power levels are over 3300 Watts for 5 seconds) and then delay execution for a minute after the first notification.

Here is my code, that i don’t know why but i can’t reach the debug 4 point: the rule start again before getting to the condition that delay the execution for 1 minute, producing an infinite loop.

var Timer timer_on = null
var over_soglia = false

rule "SuperataSogliaEnergia"

when
Item L1P changed

then
if (L1P.state > 3300){
	logInfo("notica_superamento_soglia_energia.rules", "DEBUG - 1, we have reach 3300 watt")
	Thread::sleep(5000)
	logInfo("notica_superamento_soglia_energia.rules", "DEBUG - 2, we hav waited 5 seconds)
	if((timer_on == null || timer_on.hasTerminated) && L1P.state > 3300) {
		logInfo("notica_superamento_soglia_energia.rules", "DEBUG - 3, after 5 seconds power consume is over 3000, launching messages")
		val Messaggio = String::format("Attenzione! Soglia di prelievo superata! Consumo attuale: %.1f kW. ", (L1P.state as DecimalType).floatValue)
		sendNotification("xxxxxxxx.xxxxxxxx@xxxxxxxx.com", ""
			+Messaggio
			)
		val volume_inizale = GoogleHome_Volume.state as Number
		Thread::sleep(1000)
		GoogleHome_Volume.sendCommand(new PercentType(75))
		say("Attenzione! Superata la soglia di sicurezza di prelievo energia. Spegnere alcuni dispositivi.","googletts:itITWavenetA", "chromecast:chromecast:xxxxxxxx")
		Thread::sleep(6700)
		GoogleHome_Volume.sendCommand(volume_inizale)
		timer_on = createTimer(now.pusMinutes(1), [|
			timer_on = null
		])
		over_soglia = true
		logInfo("notica_superamento_soglia_energia.rules", "DEBUG - 4, timer created and messages sent")
	}
}
end

rule "Soglia energia tornata sotto livelli di guardia"

when
 Item L1P changed

then
if (L1P.state < 2990 && over_soglia == true ){
	val Messaggio = String::format("Consumi rientrati. Consumo attuale: %.1f kW. ", (L1P.state as DecimalType).floatValue)
	sendNotification("xxxxxxxx.xxxxxxxxx@xxxxxx.com", ""
		+Messaggio
		)
	val volume_inizale = GoogleHome_Volume.state as Number
	Thread::sleep(1000)
	GoogleHome_Volume.sendCommand(new PercentType(50))
	say("Prelievo di energia rientrato nei limiti della fornitura!.","googletts:itITWavenetA", "chromecast:chromecast:XXXXXXXXXXXX")
	Thread::sleep(5000)
	GoogleHome_Volume.sendCommand(volume_inizale)
	over_soglia = false
	}
end

This is an example of the log:

2020-07-04 18:04:35.287 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 1, we have     reach 3300 watt
2020-07-04 18:04:39.208 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 1, we have reach 3300 watt
2020-07-04 18:04:40.295 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 2, we hav waited 5 seconds
2020-07-04 18:04:40.309 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 3, after 5 seconds power consume is over 3000, launching messages
2020-07-04 18:04:44.219 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 2, we hav waited 5 seconds
2020-07-04 18:04:44.243 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 3, after 5 seconds power consume is over 3000, launching messages
2020-07-04 18:04:44.245 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 1, we have reach 3300 watt
2020-07-04 18:04:49.256 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 2, we hav waited 5 seconds
2020-07-04 18:04:49.257 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 1, we have reach 3300 watt
2020-07-04 18:04:49.291 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 3, after 5 seconds power consume is over 3000, launching messages
2020-07-04 18:04:54.284 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 2, we hav waited 5 seconds
2020-07-04 18:04:54.309 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 1, we have reach 3300 watt
2020-07-04 18:04:54.333 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 3, after 5 seconds power consume is over 3000, launching messages
2020-07-04 18:04:59.315 [INFO ] [ica_superamento_soglia_energia.rules] - DEBUG - 2, we hav waited 5 seconds

As you can see i cannot reach point 4 of my debug.

This line should be giving you an error in your openhab.log
timer_on = createTimer(now.pusMinutes(1), [|
typo for plusMinutes

DSL rules are multi threading. That means it doesn’t start again, a “new” version of the rule can start alongside the first one if it is still running.

It’s the same kind of thing as you having two rules with the same trigger anyway. They’ll be running alongside each other, even before you get any repeat trigger effects.

Always a bad idea where you know you’ll get frequent triggers. it will just block up available rule threads so nothing can run, queue will get bigger and bigger.

I can’t really see what you’re trying to do with two rules instead of one, but can offer a suggestion for your objective -

var Timer timer_wait = null

rule "check for sustained power load"
when
   Item L1P changed
then
   if (L1P.state > 3300) {
        // over threshold
      if (timer_wait == null) {
            // no timer yet, start threshold timer
         timer_wait = createTimer(now.plusSeconds(5), [|
               // here do whatever you need to do for power over 5 secs
            timer_wait = null  // finished with timer
         ])
      } else {
         // timer already running, still over threshold, just let it run
      }
   } else {
         // under threshold
      // cancel any running timer
      timer_wait?.cancel
      timer_wait = null
   )
end

Note that if you are polling data every two seconds, a five second “wait” timer will only see two readings.

2 Likes

when testing if null, please use === instead of ==:

if (timer_wait === null) {