Debounce [3.2.0;3.4.9]

@rlkoshak thanks for your useful templates. I’m just about to finally migrate from OH 2.5 with jython rules to OH 3.2 with jsscripting. Since I used your jython implementation of debounce before and now wanted to use this rule template as a replacement, I stumbled over some differences:
It seems that the metadata configuration was on the “Debounce”-group for the jython implementation and now has to be set for every individual sensor of the group, correct? Is there any specific reason why this was changed? (I don’t really mind, which way is used, I was just wondering why my previous item configurations did not work with the “new template” and was figuring what has to be changed)

That’s not how it worked. In the Python version, there was no Debounce Group. You’ve always had to define debounce metadata on each Item. For this rule template, you need to create a Group and add all your Debounce Items to that Group. The Item metadata has not changed so your old Item metadata will still work.

In the text based files it made sense to have a rule that creates another rule. That’s how the old Jython rule was able to work using just the metadata on the Items. In this case it doesn’t make sense to have a rule template that creates a rule that creates yet another rule which needs to be recreated every time you change the debounce metadata on an Item. So I just use a Group.

Ah, sorry, I misinterpreted the old configuration then. Used your Generic Presence Detection by then and was a bit confused by the nested groups in my configuration (which I haven’t touched for quite some time now). I also somehow refused to accept that the Debounce Group is just a container for the debounce items and nothing more (despite being the rule trigger) :sweat_smile:. I should have re-read the presence detection topic …
(I remember now, that the jython rule built its own trigger using all items with corresponding metadata instead of a group)
Everything clear now, thanks for your efforts.

I’m a little bit lost on this.

Using OpenHab 3.2.0-1 on RaspberryOS completely on MainUI (i.e. no manual item definitions)

First of all I got nuts, because the debounce trigger didn’t work at all, until I figured out, that I had to define 1 rule from the debounce-template for each debounce group. Perhaps you should add this to the description for newbies like me.

Now I don’t get the expected results.

I defined

  • a Switch “PresenceProxyDebounced”
  • a Switch “PresenceSimulation” which I can switch manually form UI
    • “PresenceSimulation” is in the defined debounce group
    • has metadata
value: PresenceProxyDebounced
config:
  timeout: 30s
  command: "false"
  states: OFF

Here’s what I’m doing:

  • When I switch PresenceSimulation from OFF to ON, ON is propagated to PresenceProxyDebounced. Fine!
  • When I switch PresenceSimulation from ON to OFF and wait >30s, nothing happens at once and after 30s OFF is propagated to PresenceProxyDebounced. Fine!
  • When I switch PresenceSimulation from ON to OFF and back to ON after 10s, nothing happens at once and after 30s OFF is propagated to PresenceProxyDebounced. Which isn’t intended, is it?
    • Expected result to me was: PresenceProxyDebounced remains completely unchanged (immediately and after 30s)
    • it seems to me, that the ON event after 10s doesn’t cancel the running timer

Here is the corresponding event.log:

2022-03-26 15:44:00.812 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'PresenceSimulation' received command OFF
2022-03-26 15:44:00.819 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'PresenceSimulation' changed from ON to OFF
2022-03-26 15:44:10.775 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'PresenceSimulation' received command ON
2022-03-26 15:44:10.781 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'PresenceSimulation' changed from OFF to ON
2022-03-26 15:44:30.858 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'PresenceProxyDebounced' changed from ON to OFF

Here is the corresponding openhab.log (debug enabled):

2022-03-26 15:44:00.827 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Match = 30s
2022-03-26 15:44:00.830 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Days = 0 hours = 0 minutes = 0 seconds = 30 msec = 0
2022-03-26 15:44:00.833 [DEBUG] [el.script.Rules.rules_tools.Debounce] - Debouncing PresenceSimulation with proxy = PresenceProxyDebounced timeout = 30s and states = OFF
2022-03-26 15:44:00.835 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Timer manager check called
2022-03-26 15:44:00.838 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Match = 30s
2022-03-26 15:44:00.840 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Days = 0 hours = 0 minutes = 0 seconds = 30 msec = 0
2022-03-26 15:44:00.842 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Timer to be set for 2022-03-26T15:44:30.841984+01:00[Europe/Berlin]
2022-03-26 15:44:00.844 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Creating timer for PresenceSimulation
2022-03-26 15:44:00.846 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Timer created for PresenceSimulation
2022-03-26 15:44:10.792 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Match = 30s
2022-03-26 15:44:10.796 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Days = 0 hours = 0 minutes = 0 seconds = 30 msec = 0
2022-03-26 15:44:10.800 [DEBUG] [el.script.Rules.rules_tools.Debounce] - PresenceSimulation changed to ON which is not debouncing
2022-03-26 15:44:10.802 [DEBUG] [el.script.Rules.rules_tools.Debounce] - End debounce for PresenceProxyDebounced, new state = ON, curr state = ON, command = false
2022-03-26 15:44:30.842 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Timer expired for PresenceSimulation
2022-03-26 15:44:30.844 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Calling expired function function() {
        logger.debug("End debounce for " + proxy + ", new state = " + state + ", curr state = " + items[proxy] + ", command = " + isCommand);
        if(isCommand && items[proxy] != state) {
          logger.debug("Sending command " + state + " to " + proxy);
          events.sendCommand(proxy, state.toString());
        }
        else if (items[proxy] != state) {
          logger.debug("Posting update " + state + " to " + proxy);
          events.postUpdate(proxy, state.toString());
        }
      }
2022-03-26 15:44:30.847 [DEBUG] [el.script.Rules.rules_tools.Debounce] - End debounce for PresenceProxyDebounced, new state = OFF, curr state = ON, command = false
2022-03-26 15:44:30.851 [DEBUG] [el.script.Rules.rules_tools.Debounce] - Posting update OFF to PresenceProxyDebounced
2022-03-26 15:44:30.854 [DEBUG] [el.script.Rules.rules_tools.TimerMgr] - Deleting the expired timer

Is my expected result wrong?
Did I miss some necessary configuration?

…you are not the only one seeing “unexpected” behaviour… i tried do use debounce also but it seems to not propagate the on states correctly…

see one of my graphes for example (yellow is ON, blue is OFF):


(debounce time is set to 5 minutes)

It’s not feasible for all rule templates to document the core process for installing and using a template. It is covered in the draft for the rules section of Getting Started and likely will be covered in other sections of the docs too.

Correct, when it changes to ON any debounce should be canceled since the only state debounced is OFF.

I’ll have to look into this. The log is showing that the timer should have been cancelled. “End debounce for PresenceProxyDebounced …”. But I’m not seeing the debug logs indicating that the timer actually was cancelled.

That’s the root of the problem.

2 Likes

@DARqz, @krikk I think I have a fix which seems to be working for me but I’d like you to test it out too just in case I’m missing something.

Open the rule that was instantiated from the rule template and open the Action:

Insert the following on line 209: this.timers.cancel(event.itemName); // Cancel the timer if it exists. It should look like this:

else {
  logger.debug(event.itemName + " changed to " + event.itemState + " which is not debouncing");
  this.timers.cancel(event.itemName); // Cancel the timer if it exists
  end_debounce_generator(event.itemState, cfg["proxy"], cfg["command"])();
}

That will explicitly cancel the timer when the Item returns to a non-debounced state. This is one of those cases where I can’t imagine how it’s been working before now.

1 Like

Thanks for sharing this Rule Template. I have quite a few anti-flapping timers that I will (over time as I make other changes) replace with this. I converted a couple of them to begin with, and it works great.

i implemented you code change, but i still get strange behaviour… i have a test setup like described in your post " Generic Presence Detection and i have this logs:

2022-04-03 22:08:20.833 [DEBUG] [el.script.Rules.rules_tools.Debounce] - Sending command OFF to Person1Presence
2022-04-03 22:08:20.857 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'Person1Presence' received command OFF
2022-04-03 22:08:20.862 [INFO ] [hab.event.GroupItemStateChangedEvent] - Item 'Presence' changed from ON to OFF through Person1Presence
2022-04-03 22:08:20.865 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Person1Presence' changed from ON to OFF
2022-04-03 22:17:52.339 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'Person1Sensor1' received command ON
2022-04-03 22:17:52.349 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'Person1Sensor1' changed from OFF to ON
2022-04-03 22:17:52.352 [INFO ] [hab.event.GroupItemStateChangedEvent] - Item 'Person1Presence_Raw' changed from OFF to ON through Person1Sensor1
2022-04-03 22:17:52.360 [DEBUG] [el.script.Rules.rules_tools.Debounce] - Debouncing Person1Presence_Raw with proxy = Person1Presence timeout = 5m and states =
2022-04-03 22:22:52.374 [DEBUG] [el.script.Rules.rules_tools.Debounce] - End debounce for Person1Presence, new state = ON, curr state = OFF, command = true
2022-04-03 22:22:52.391 [DEBUG] [el.script.Rules.rules_tools.Debounce] - Sending command ON to Person1Presence

in this log i do not understand why the line

Item 'Person1Presence_Raw' changed from OFF to ON

does not trigger a change of Person1Presence… if the item Person1Presence_Raw goes to ON, shouldn’t this immediatly trigger Person1Presence to ON??

…i just have seen that Person1Presence goes to ON, exactly 5 minutes later (my debounce time!)… is this a bug? …or do i have a wrong understandig what debounce should do…? or do a miss something??

If that’s how the metadata is configured. Assuming you’ve not changed the metadata from above where “states” only lists OFF, then it should immediately go to ON and the timer become cancelled.

That’s how it’s working for me with the change from above.

And the logs do indicate that the rule did send the ON command to Person1Presence. Those last two lines show that happening immediately in response to Person1Presence_Raw changing from OFF to ON.

You do not show any logs after that. You should see in events.log Person1Presence receiving that ON command and it changing to ON (assuming it wasn’t already ON). You shouldn’t see anything else in openhab.log after the “Sending command ON…” statement because the timer was in fact cancelled. The Debounce rule has nothing left to do for that Item change.

You’ve not posted enough logs to see what’s going on. From what’s posted above it’s working as expected.

i am not sure you noticed the 5 minutes delay, so i reformated the logs:

22:08:20.833 Sending command OFF to Person1Presence
22:08:20.857 Item ‘Person1Presence’ received command OFF
22:08:20.862 Item ‘Presence’ changed from ON to OFF through Person1Presence
22:08:20.865 Item ‘Person1Presence’ changed from ON to OFF
22:17:52.339 Item ‘Person1Sensor1’ received command ON
22:17:52.349 Item ‘Person1Sensor1’ changed from OFF to ON
22:17:52.352 Item ‘Person1Presence_Raw’ changed from OFF to ON through Person1Sensor1
22:17:52.360 Debouncing Person1Presence_Raw with proxy = Person1Presence timeout = 5m and states =
22:22:52.374 End debounce for Person1Presence, new state = ON, curr state = OFF, command = true
22:22:52.391 Sending command ON to Person1Presence

…but if i understand you correctly, the event should pass immediatly and not with 5 minutes (the debounce time) delay… but thx for the clarification, will try to to another test to reproduce it again…

PS: the debounce config of Person1Presence_Raw:

value: Person1Presence
config:
  command: "True"
  state: OFF
  timeout: 5m

I didn’t see the five minute delay. It’s hard to line thing up on a small screen.

The relevant code is as follows:

if(cfg["states"].length == 0 || 
  (cfg["states"].length > 0 && cfg["states"].indexOf(event.itemState.toString()) >= 0)) {
  logger.debug("Debouncing " + event.itemName + " with proxy = " + cfg["proxy"] 
               + " timeout = " + cfg["timeout"] + " and states = " + cfg["states"]);
  this.timers.check(event.itemName, cfg["timeout"], 
                    end_debounce_generator(event.itemState, cfg["proxy"], cfg["command"]));    
}
else {
  logger.debug(event.itemName + " changed to " + event.itemState + " which is not debouncing");
  this.timers.cancel(event.itemName); // Cancel the timer if it exists
  end_debounce_generator(event.itemState, cfg["proxy"], cfg["command"])();
}

In prose: If there is no “states” entry in the Item’s metadata or the item’s new state is among the comma separated list of states in the “states” entry in the Item’s metadata, create a Timer to call the function created by end_debounce_generator at the configured time.

If there is a “states” entry in the Item’s metadata but the Item’s new state is not among the comma separated list of states, immediately cancel the timer (if there was one) and immediately call the function created by end_debounce_generator.

That first part of the if ran, which means either there was no “states” entry or ON was among the list. And indeed, looking back at the metadata you don’t have a “states” entry. You have “state”.

yes, you found the error… big thanks, i did not see this… plz can you update your post because i think i copied the error from there :slight_smile:

Done. That post is very old and in an initial implementation it was called “state” instead of “states”.

Thx for the fast reply, works for me perfectly.

For my rule I added some debug logging:

else {
  logger.debug(event.itemName + " changed to " + event.itemState + " which is not debouncing");
  if (this.timers.hasTimer(event.itemName)) {
    logger.debug("cancelling timer for " + event.itemName);
    this.timers.cancel(event.itemName);
  }
  end_debounce_generator(event.itemState, cfg["proxy"], cfg["command"])();
}

Thx again!

Two minor suggestions:

  1. Step-by-step clarification

Should probably be

In the UI, navigate to the “raw” Item, click on “Add Metadata”, click “Enter Custom Namespace…” (under “Custom namespaces” section) and enter “debounce” as the namespace.


  1. Stylistic suggestion: separate the two config examples code blocks
Switch RawSensor (Debounce) { debounce="ProxySensor"[timeout="2m", states="OFF", command="False"] }
Switch ProxySensor

or in the UI

value: ProxySensor
config:
  states: OFF
  timeout: 2m
  command: "True"

Hmm I would like to several debounce rules configured, many of them operating on a single “raw” item.

I am thinking of I really need several “debounce group items” or could I simply slap all the raw items into single group?

I have actually currently pointed the rules towards the raw items (instead of a group). Getting some funky behavior…Now I realize that will not obviously work since “member of a group” trigger has been used in the rule.

I’m OK with that and will change it in the OP.

I agree with the suggestion but the code that imports it and shows it in MainUI wasn’t able to handle two code blocks so they are combined into one.

Not that there’s any problem with that approach but is there is a reason why?

You are freely able to modify the rule generated by the template in any way you need to. It’d only take a minor edit to the rule to change the trigger to an Item based trigger instead of Member of trigger.

1 Like

Simply…just trying to avoid having so many items, it makes it harder to understand the system later on (like 1y later when I have forgotten all this).

Similarly, I avoid modifying templated rules so I can update them without worrying what changes to make where.

For what it’s worth, having single debounce group seems to work fine based on quick testing. Quick code review suggests that rule uses member item name and member item state, and the actual group acts almost as filter mechanism for events only. The group name and group state (if any) does not seem play a rule, at least with the current version.

This is great as I also avoid having multiple debounce rules, making it easier to update the rule when needed.


Thanks for this, I find it very useful. I use this to debounce raw status that has been formed from item state (looking at undef) and thing status (online/offline) (Device status online monitor). With “expire” I can pick up nonupdating zwave items.

I had setup alerting first without debounce but that is suspect to some transient unnecessary alerts since my modbus device is sometimes unable to respond to requests (like, for 20 seconds). Debounce will resolve this kind of online/offline flakiness and alert only if the issue remains.

Correct. The Group name serves only configure the trigger for the rule. The event is used to get the Item’s name and state which will be the same whether the rule is triggered by Member of or Item received triggers.

As you’ve seen you really only need the one Group Item in addition to your already existing Items and that Group’s sole purpose is to trigger the rule.

Perhaps someday if a rule’s triggers are easier to modify at runtime I’ll change it so the rule automatically gets triggered by Items with the debounce metadata (that’s how my original Jython version worked) but there are weird limitations with rules creating rules in the UI that makes that challenging.

I use it for my persistence (have to be away for five minutes before I actually count it as away) and for a few wired reed sensors that go crazy periodically when the temp gets below 10 degrees F. Even just a half second debounce on those is enough to go for dozens of alerts to none (because the door never actually opened in the first place.

There was a PR and issue opened to create a Debounce profile but I don’t know that it’s ever been completed or merged. That wouldn’t completely replace this rule template since profiles only work with Links and not all Items one may want to debounce have a Link (e.g. the Item that is debounced for my presence detection is actually a Group Item with an aggregation function).

I’m glad you find it useful.

Thanks!

1 Like