[SOLVED] Trying to avoid "debounce" in a rule

mmm … maybe this can explain a bit more:

let me check with rrd4j … but in any case this is not an expected behavior, right?


NOTE: rrd4j is for storing numerical data only.

Mmmm … better to avoid working with Persistence.

trying without:

var DateTime lastTrigger = null

// Send mail when rooby is unreachable

rule "rooby unreachable"
when
    Item RooWifi_Roomba871_Status changed
then
    //how to prevent flapping and check if rooby is unreachable even after system restart
    //if ((!RooWifi_Roomba871_Status.changedSince(now.minusMinutes(10))) && (RooWifi_Roomba871_Status.state ==OFF)) {
    if ((lastTrigger.isAfter(now.minusMinutes(1))) && (RooWifi_Roomba871_Status.state ==OFF)) {
    lastTrigger = now
    var String tmp = RooWifi_Roomba871_LastSeen.state.format("%1$td %1$tb %1$tl:%1$tM %1$tp")
    var message = "Description: rooby is unreachable starting from " + tmp
    sendMail("<myemailaddress>", "ATTENTION - rooby is unreachable", message)
    }
end

@hr3 now back with change and update question :slight_smile:
I’m thinking about this scenario:

  • interface wifi is going DOWN
  • the rule triggers and sends and email (t0)
  • the wifi interface is going UP after few seconds, and stays UP
  • lastTrigger is before now.minusMinutes(1), so I won’t receive any email saying the interface is UP
  • after 1 minute, the interface is UP, but RooWifi_Roomba871_Status didn’t receive any change or update right?

question is: how to receive that email after 1 minute?

Hi @ariela,

here is how I solved this to monitor all my network infrastructure (Items are in the group uSurvNet). Maybe this helps. It is not 100% save but works for me like a charm.

rule "SurvNetStatOff"
when
  Member of uSurvNet changed from ON to OFF
then
  createTimer(now.plusMinutes(5)) [|
    if (triggeringItem.state == OFF) {
      logWarn("Netzwerk", triggeringItem.name + " nicht erreichbar")    
    }
end

Greetings
Sebastian

@hannibal29

so idea is: when something wrong happens, I start the timer … if after 5 mins the status is still OFF, action is triggered.

Right?

I think, the logWarn is ever send, if the state once changed to OFF, no matter if the state switched once more in this time und how the state is after ending the timer.

Exactly.

Nope. My tests and my experience so far show that it is working. When I tried this the first time I had the same question or thoughts as you have. I don’t know how this is implemented but I can image that when the rule runs the implicit variable as substituted with the actual item. So when the timer fires the current state of the correct item is checked. For me it even works when 2 or more timers are running in parallel.

Only drawback is (that’s why I said it is not 100%) that if the item is flapping around and the state is OFF for just the millisecond the timer expires the logWarn will be send. If this matters or not is depending on the actual use case.

what about creating a double check with random time?

we are not hitting 100%, of course … but it seems reasonable. what do you think?

or maybe with Expire Binding should be clearer …

rule "rooby unreachable"
when
    Item RooWifi_Roomba871_Status changed from ON to OFF
then
    if (RooWifi_Roomba871_Status.state == OFF) {
        var int randomTime = (new java.util.Random).nextInt(10)
	    timer = createTimer(now.plusMinutes(randomTime)) [|
		    if (RooWifi_Roomba871_Status.state == OFF) {
				    var String tmp = RooWifi_Roomba871_LastSeen.state.format("%1$td %1$tb %1$tl:%1$tM %1$tp")
                    var message = "Description: rooby is unreachable starting from " + tmp
                    sendMail("<myemailaccount>", "ATTENTION - rooby is unreachable", message)
                    timer = null
			    } else {
                    var int randomTime2 = (new java.util.Random).nextInt(10)
				    timer.reschedule(now.plusMinutes(randomTime2))
                    if (RooWifi_Roomba871_Status.state == OFF) {
                             var String tmp = RooWifi_Roomba871_LastSeen.state.format("%1$td %1$tb %1$tl:%1$tM %1$tp")
                             var message = "Description: rooby is unreachable (FLAP) starting from " + tmp
                             sendMail("<myemailaccount>", "ATTENTION - rooby is unreachable", message)
                             timer = null
                         } else {
                             var String tmp = RooWifi_Roomba871_LastSeen.state.format("%1$td %1$tb %1$tl:%1$tM %1$tp")
                             var message = "Description: it was a problem but now rooby is back online starting from " + tmp
                             sendMail("<myemailaccount>", "SOLVED - rooby is now back online", message)
                             timer = null
                         }
			    }			
	    ]
    }
end

idea is:

  • if the device is unreachable (ON to OFF), start a random timer between 1 and 10 minutes
  • if after timer expired, the device is still OFF, send me an email
  • if the device is back ON, start again a new random timer between 1 and 10 minutes
  • if after second timer expired, the device is still OFF, send me an email. If not, send me an email saying there was an issue, but now everything’s fine

if we are unlucky, and there is a flap in the background that we didn’t hit with 2 random hold down timers, the rule will trigger again (device ON -> OFF)

What do you think?

Andrea

Mh, good question :wink:

I think this again depends on the use case and the behaviour of the device.

In my opinion the 1st random timer has no benefit compared to a fixed timer and can even have a negative effect. In my use case for example I know the milight bridge goes sometimes offline for about 1-3 minutes. That’s way I have 5 min as timer. If random time would be 1 minute a would get false positives.

If I got your use case right there are 2 scenarios

  1. robot out of wifi range -> unreachable for short time
  2. battery empty -> unreachable for long time

If it doen’t matter to know the battery is empty immediately I would just pick a fixed time (maybe 15 minutes) for the timer.

If you wanna make it even more fail-safe you can count how often the state changed in this 15 minutes (should be possible with persistence or a rule) and only send the message if it changed just 1 time.

WoW … interesting … any idea how to do that? or to point myself in the right direction?

thanks again for your great support

Andrea

If you want to get a status from your Roomba you could try this https://github.com/koalazak/dorita980
I use it to talk to my Roomba 980. Because iRobot kept breaking it by updating the firmware I blocked Roomba from the Internet, so I don’t know if it works with the current Roomba Firmware.
Be aware its not that straight forward to get working…

I know perfectly @kevin … but the problem here is not how to connect to my Roomba (871), I’ve already done it (struggling a bit at the starting point, you know).

But thanks for pointing me to dorita … quite interesting, thank you :slight_smile:

problem is how to count how often the state changed in x minutes, then only send the message if it changed just 1 time :slight_smile:
Andrea

To stop too many emails I usually check a variable isn’t set before sending the mail, after sending the email I set a variable that prevents further emails. I then reset the variable after a while using a cron statement.
Does that sound like what you need, or do you want nothing sending after the first email until after the state changes have stopped for a while?

Exactly the second scenario. But dunno how to do so.

Andrea

I can give you a few pointers in around 12 hours as it’s nighttime here.
Basically declare a timer at the top of the rules file as null,
Then when your item triggers, if the timer is null send the email before creating the timer, if timer isn’t null reschedule it. When the timer expires set it to null

Hope this makes sense, I use something similar for my PIR operated lights, and there should be an example of timer rescheduling on the site somewhere

First, a warning. I’m not a Rule DSL user. I use JSR223 Jython instead. However, one possible approach is to track the last change time using a variable in the rules file and then monitor the time period since the last state change using a periodic (cron) triggered rule (the variable and related rules must be in the same file). There’s also a lastUpdate property on items, but that may not give the correct results if there are a series of updates with the same state.

Idea -> Yes. But I have not tried if it really works …

One approach I can image is with persistence (not mapdb, but any other should work). For persisted items you can use the function sumSince(some time interval) to sum up all previous states in the given time period. See also

Problem here is that this works not directly for the Switch item type (except maybe with influxdb, but I’m not sure). So you need a second item (Number type) and a rule to update this item on every state changed event of the switch item. Add some logic and it should do the trick, of course you have to persist the number item.

I think you can also do this without persistence by using just a rule with timers. But as I use persistence anyway (jdbc with MariaDB) I would go this way. Many roads lead to Rome … :wink:

Greetings
Sebastian

All of this seems really complicated for the stated problem.

Let’s assume Expire binding. Create a new Item Switch Room_Timer {expire="10m,command=OFF"}

Then the Rules are simply:

rule "rooby wifi status changed"
when
    Item RooWifi_Roomba871_Status changed
then
    if(previousState == NULL) return; // ignore changes from NULL

    // Roomba is online
    if(RooWifi_Roomba871_Status.state == ON) {
        // If we have a Timer running it means Roomba is back online after being offline for less than 10 minutes
        // cancel the timer
        if(Roomba_Timer.state == ON)  Roomba_Timer.postUpdate(OFF) 

        // If the Timer isn't running it means the Roomba has been offline for at least 10 minutes and an alert email was sent
        // send a new alert informing that the roomba is back online
        else {
            var String tmp = RooWifi_Roomba871_LastSeen.state.format("%1$td %1$tb %1$tl:%1$tM %1$tp")
            var message = "Description: rooby is back online starting from " + tmp
            sendMail("<myemailaddress>", "SOLVED - rooby is now back online", message)
        }
    }

    // Roomba is offline, set a timer
    else if(RooWifi_Roomba871_Status.state == OFF) Roomba_Timer.sendCommand(ON) // start/reschedule the timer
end

rule "rooby offline"
when
    Item Roomba_Timer received command OFF
then
    // Rule only triggers when Roomba has been offline for 10 minutes
    var String tmp = RooWifi_Roomba871_LastSeen.state.format("%1$td %1$tb %1$tl:%1$tM %1$tp")
    var message = "Description: rooby is unreachable starting from " + tmp
    sendMail("<myemailaddress>", "ATTENTION - rooby is unreachable", message)
end

This is an implementation of Design Pattern: Motion Sensor Timer and is basically the Design Pattern: Expire Binding Based Timers implementation of Sebastian’s solution in post 7.

The above code will send the email only 10 minutes after the last time that the Roomba goes offline. Only if the Roomba has been offline for 10 minutes or more and an email was sent will a new email be sent when it comes back online.

Steve’s solution in post 19 is a good approach to implement this without the need for persistence. Instead of relying on lastUpdate and database queries. I’d recommend that over the persistence approaches. Those approaches end up being just too complicated to solve this particular problem. But I really do think that Timers is the best approach for this.

1 Like

@rikoshak beat me to it with an easier solution :slight_smile:
I forgot about the expire binding despite using it myself

2018-07-31 09:10:48.710 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'rooby wifi status changed': The name 'NULL' cannot be resolved to an item or type; line 77, column 25, length 4

it’s referring to

if(previousState == NULL) return;

edit: please ignore. After second reboot the log disappeared. If I well understood, it’s a known issue

THANK YOU all for your support!!! :slight_smile: