Retrigger Prevention

Evidently, I'm one of those weird people for whom RM normally just makes sense. Yet this one has me stumped.

I have a driveway sensor stitched together from a Mighty Mule and an old contact sensor I had laying around. It works like a charm to notify us whenever a car is coming or going on our fairly long driveway. Very reliable. Except for one thing--it usually fires off 4-5 open/close events (and therefore 4-5 notifications) for every car coming up or down the driveway. Annoying.

No problem, I thought. I'll just write a Rule to prevent the notification from re-firing for a few minutes after an initial notification has been issued. The rule is below. It doesn't work. It seems so simple. I must be overlooking something stupid or obvious. Help someone?

In case the above is not enough, here's the log. What has me specifically perplexed: note at 5:28:50, right before the rule correctly makes the initial announcement, the rule's private boolean is flipped to false (meaning, the initial notice has been given, so shut up rule for 5 mins until I flip the PB back to True). Then at 5:28:51, the rule fires again. Here, the check to see if private boolean is false resolves to false (oooh, that's a bad double negative). Meaning, the rule is acting like this is a virgin notice all over again. How can the condition at 5:28:51.302 be evaluated as False when the PB was set to false just a moment before? Stumped.

Maybe try inserting an End If before the Delay 0:05:00

Genuinely appreciate the idea, but the only IF statement (the one in the first line) is a simple conditional, which I understood does not use an END-IF. And there's no other conditional in the rule to "end". Logically, I want the actions from line two to the end to only process if PB is True (i.e., if it's a virgin event).

Am I not appreciating your point?

@Terk

Why? The first IF is a Simple Conditional, isn't it?

Oh, yeah I missed the exit rule and just took it for an if then

appreciate the attempt nonetheless!

I haven't used a private boolean before, will it survive multiple instances or do you need to use a global variable for that?

It should does.

1 Like

Here's a similar rule that I use to send notifications via TTS that makes use of a Private Boolean to prevent repeat messages.

30%20PM

I've never had repeat messages

One difference between your rule and mine is that I explicitly test if the private boolean is True.

I would actually restructure your rule thusly:

Make the trigger "If driveway sensor is OPEN"
Leave the trigger as is

The actions should be something like:

IF (Driveway sensor is closed) THEN
     Exit Rule
ELSE-IF (IF Private Boolean is TRUE) THEN
     Set Private Boolean False
     Notify Mark ....
     Set Private Boolean True --> delayed: 0:05:00
END-IF
1 Like

One of the challenges of my situation is that the sensor doesn't respect open versus closed. Every time the mighty mule fires, the sensor toggles N times. Sometimes N is an odd number and sometimes N is an even number. So, sometimes it stops on closed and sometimes it stops on open. Dunno. And I suppose I don't care because any sensor events mean a car is on the driveway. Which is why my trigger was "Driver Sensor Changed".

So @aaiyar I don't think I can use your suggestion as is, can I?

Any idea why my rule wouldn't work? Any idea why the log shows the apparent discrepancy? . Grasping for anything at this point....

The triggers are happening faster than Rule Machine executes. What sensor do you have the Mighty Mule connected to?

Try this contact debouncer App.

    definition(
    name: "Debounce contact",
    namespace: "hubitat",
    author: "Bruce Ravenel",
    description: "Debounce double reporting contact sensor",
    category: "Convenience",
    iconUrl: "",
    iconX2Url: "")

preferences {
	page(name: "mainPage")
}

def mainPage() {
	dynamicPage(name: "mainPage", title: " ", install: true, uninstall: true) {
		section {
			input "thisName", "text", title: "Name this debouncer; debounced contact device will have this name", submitOnChange: true
			if(thisName) app.updateLabel("$thisName") else app.updateSetting("thisName", "Debounce contact")
			input "contact", "capability.contactSensor", title: "Select Contact Sensor", submitOnChange: true, required: true
			input "delayTime", "number", title: "Enter number of milliseconds to delay for debounce", submitOnChange: true, defaultValue: 1000
		}
	}
}

def installed() {
	initialize()
}

def updated() {
	unsubscribe()
	unschedule()
	initialize()
}

def initialize() {
	def debounceDev = getChildDevice("debounceSwitch_${app.id}")
	if(!debounceDev) debounceDev = addChildDevice("hubitat", "Virtual Contact Sensor", "debounceSwitch_${app.id}", null, [label: thisName, name: thisName])
	subscribe(contact, "contact", handler)
}

def handler(evt) {
	runInMillis(delayTime, debounced, [data: [o: evt.value]])
	log.info "Contact $evt.device $evt.value, start delay of $delayTime milliseconds"
}

def debounced(data) {
	log.info "Debounced contact $data.o"
	def debounceDev = getChildDevice("debounceSwitch_${app.id}")
	if(data.o == "open") debounceDev.open() else debounceDev.close()
}
1 Like

Jon, thank you, I'll definitely give this a try when I get back home end of the week. With that said, I'm still keen to understand my rule doesn't work.

Wow, really, that's an intriguing theory! Here's what confuses me about it... See how the rule sets PB to false at 5:28:50.937? That's exactly as designed. Setting PB to false is the way my rule indicates that the initial notification has occurred so don't notify on other sensor events for the next five minutes.

Despite this, at 5:28:51.302 (a bit less than half a second later without any other intervening changes to the value of PB), the next firing of the rule evaluates the value of PB as NOT False. Which results in a duplicate notification.

How could this possibly be? Do you see the apparent contradiction?

I use the Ecolink contact sensors because they have external contacts for this purpose.

I suspect that this is because variables take time to be persisted to the database, your events are coming in fast so it's likely that when the subsequent instances of the rule fire, the variable hasn't yet been persisted. This means that the next instance of the rule reads the old value.

I don't use RM myself, but base this on similar issues I've seen when writing drivers that try to prevent duplicate messages.

You might be able to test this theory by logging the value of the variable at the top of the rule (so that you can see the current value that that instance of the rule sees when it executes).

My first thought is that it's the sensor reporting too fast issue. I had that with contact sensors and used Bruce's app and have not had any issues since. I'd set the rule to 5000 msec and then you can get rid of the delay in the rule itself.

Really interesting ideas guys. I'll give these ideas a try this weekend. Really appreciate the help!

I used the contact debouncer App, and can't get the debounced virtual device to fire with the length set at 500ms. The physical sensor is quadruple/quintuple firing every time, 8-10 times per day as I would expect. The virtual contact opened and closed one time the last couple days.

Couple theories

  • the app description says "Debounce double reporting...." My sensor is burst firing more than two times -- would that mess with the app somehow?
  • the way the physical contact sensor is setup with the Mighty Mule, there is no Open or Close, just a random number of events alternating between open and close. Where she stops, nobody knows!

Any ideas? I left a message with support a couple days ago. No word back yet.

The debounce app won’t work if if the mighty mule fires an odd number of times. You’ll miss the transition altogether, I believe. For example, a rapid open, closed, open would be debounced to just open.

Another option is to use a Local Boolean Variable instead of a Private Boolean. If I recall correctly, Bruce mentioned in another thread the RM Local Variables are the quickest to respond. I am not sure that this would even be quick enough. Might be worth a try, though.