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

Hi folks,

I hope you can help me. I’ve included a new Roomba in my environment, and now I’m trying to be informed when the wifi interface is unreachable.

The wifi interface can be unreachable usually when:

  • The battery is completely empty
  • the device is out of wifi coverage

The basic rule is working. But now I would like to implement a policy to reduce flapping in case the device, cleaning my house, can be in/out of coverage multiple times in a very short period of time.

Consider Persistence is implemented, but for this switch item I have implemented only the default persistence (mapdb in my case, to restore on startup).

My try is:

// 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)) {
    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

// Send mail when rooby is back online

rule "rooby back online"
when
    Item RooWifi_Roomba871_Status changed from OFF to ON
then
    //how to prevent flapping
    if (!RooWifi_Roomba871_Status.changedSince(now.minusMinutes(10))) {
    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)
    }
end

the statement “(!RooWifi_Roomba871_Status.changedSince(now.minusMinutes(10))” is never triggered, and configuring UP/DOWN the wifi interface I receive all UP/DOWN emails :frowning:

Any clue?

off the book: what is the difference between “change” and “update”?

thanks all of you for the support here

Andrea


change = the state was changed
update = there was a update for the item, but the state could be the same as before

1 Like

thanks @hr3

So change is OK in my rule. Now I need to understand why this is not working as expected :thinking:

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