Debounce [4.0.0.0;4.9.9.9]

Debouncing is a technical term for the following behavior. After an initial event, ignore subsequent event for a certain amount of time to give it time to settle. For example, in electronics, pressing a button may result in an initial press event but after releasing the button it may physically bounce a little sending several pressed and released events until it settles.

In openHAB there are a number of use cases where this overall approach can be applied in a larger context. For example, when detecting presence one may want to only count a person as away if they have been away for five minutes to prevent the home from going into away mode when the person simply walks to the mailbox and back. Sometimes a network can be a little flakey and a service may appear offline for a minute when it’s actually running so we want to wait for a couple minutes before alerting that it’s gone offline. There are many more use cases of course.

While there are several Debounce Profiles posted here and there on the forum and elsewhere and an issue with a PR to implement it as part of OH itself, a Profile only applies to a Link between a Channel and an Item. It cannot be used with Items alone and therefore its use is limited.

This is a complete reimplementation of the Debounce rule template that works with OH 4.x using the JS Scripting add-on and the openhab-rules-tools library. It includes new OH 4 features so it is not backwards compatible. It also includes a few minor changes in behavior.

How it works:

Each Item to be debounced needs to have two Items, a raw Item and a proxy Item. The raw Item has the value that is to be debounced. The proxy Item is the Item that receives the debounced value and is the Item that represents the sensor in openHAB (e.g. put on the UI, used in a rule, etc.).

All of the raw Items must be added to a “Debounce” Group. This Group triggers the Debounce rule to run when the states of the raw Items change. The actual Group Item is chosen by the user when instantiating the rule. Do not include the proxy Items in this Group.

Each raw Item must also have “debounce” Item metadata. This tells the rule the name of the corresponding proxy Item and some configuration properties that tell the rule how long to debounce the state, an optional list of those states to debounce (e.g. one can debounce only the OFF state but immediately process the ON state), and whether the debounced state should be sent to the proxy Item as an update or a command. The actual name of the namespace is chosen by the user when instantiating the rule. By default the namespace is debounce.

In .items files an example would look something like:

Switch RawSensor (Debounce) { debounce="ProxySensor"[timeout="PT2M", states="OFF", command="False"] }
Switch ProxySensor

or in the UI

value: ProxySensor
config:
  states: OFF
  timeout: PT2M
  command: "True"

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 (where “debounce” is what ever you chose as the namespace property.

Property Purpose Allowed values
value Name of the proxy Item Valid Item name, should not be the same as the Item with the metadata.
states List of states that are to be debounced. Leaving this option out or setting it to empty string will debounce all Item states. Comma separated list of Item states or empty string.
timeout How long to debounce the value for. Anything supported by time.toZDT() in the openhab-js libray (see JavaScript Scripting - Automation | openHAB)
command An optional boolean indicating whether the proxy should be commanded or updated. “true” or “false”, defaults to “false”.

See Generic Presence Detection for an example using this for debouncing presence detection.

When this rule is triggered by any event that is not an Item event (e.g. manually) it will validate your Item configs (i.e. make sure all Item with “debounce” metadata are members of the “Debounce” group and make sure that metadata is usable). Watch the logs for potential problems.

When the “Initial Proxies” option is toggled on, when triggered by a non-Item event, in addition to validating the Item’s debounce configs, the rule will initialize the proxy Items to the current state of the raw Item (if they are different). This can be used with a “system run level” trigger or manually triggered to synchronize the proxy and raw Items in cases where the event was missed (e.g. restoreOnStartup).

Language: JS Scripting

Dependencies:

  • A “Debounce” Group created
  • All the raw Items added to the Debounce Group
  • All the raw Items have valid “debounce” Item metadata
  • OH 4.0+
  • openhab-js 4.5+
  • openhab_rules_tools 2.0.3+

TODOs:

  • determine if it’s feasible to expand this template to also be a threshold filter or if that’s best implemented as a separate template (this would only forward an update if it is different enough from the current state, smoothing out the events from chatty sensors)

Change Log

Version 0.4

  • adjustments to changes in OHRT
  • run on GroupItemStateChangedEvent

Version 0.3

  • fixed bug caused by a change to the way the openhab-js API interacts with Item metadata
  • fixed bug where any Group named other than “Debounce” would not be used in the script action

Version 0.2

  • moved to new openhab-js metadata calls and access to items
  • added check that thows an exception if the openhab-js or openhab_rules_tools versions installed are too old to work with the template

Version 0.1

  • initial release

Sponsorship

If you want to send a tip my way or sponsor my work you can through Sponsor @rkoshak on GitHub or PayPal. It won’t change what I contribute to OH but it might keep me in coffee or let me buy hardware to test out new things.

Resources

https://raw.githubusercontent.com/rkoshak/openhab-rules-tools/main/rule-templates/debounce/debounce2.yaml

5 Likes

upgrade to OH 4.0.1 the last days, now tried to upgrade debounce rule template…

but i always geth this error when the rule runs:

2023-08-07 23:02:52.889 [INFO ] [nhab.automation.rules_tools.Debounce] - Validating Item metadata, group membership, and initializing the proxies
2023-08-07 23:02:52.904 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: TypeError: item.getMetadataValue is not a function
        at <js>.:=>(<eval>:125) ~[?:?]
        at <js>.init(<eval>:125) ~[?:?]
        at <js>.:program(<eval>:181) ~[?:?]
        at org.graalvm.polyglot.Context.eval(Context.java:399) ~[?:?]
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:458) ~[?:?]
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:426) ~[?:?]
        at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:262) ~[java.scripting:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocableAndAutocloseable.eval(DelegatingScriptEngineWithInvocableAndAutocloseable.ja
va:53) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.eval(InvocationInterceptingScriptEngineWithInvo
cableAndAutoCloseable.java:78) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocableAndAutocloseable.eval(DelegatingScriptEngineWithInvocableAndAutocloseable.ja
va:53) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.eval(InvocationInterceptingScriptEngineWithInvo
cableAndAutoCloseable.java:78) ~[?:?]
        at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.lambda$0(ScriptActionHandler.java:71) ~[?:?]
        at java.util.Optional.ifPresent(Optional.java:178) ~[?:?]
        at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.execute(ScriptActionHandler.java:68) ~[?:?]
        at org.openhab.core.automation.internal.RuleEngineImpl.executeActions(RuleEngineImpl.java:1188) ~[?:?]
        at org.openhab.core.automation.internal.RuleEngineImpl.runRule(RuleEngineImpl.java:997) ~[?:?]
        at org.openhab.core.automation.internal.TriggerHandlerCallbackImpl$TriggerData.run(TriggerHandlerCallbackImpl.java:87) ~[?:?]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[?:?]
        at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
        at java.lang.Thread.run(Thread.java:833) ~[?:?]
2023-08-07 23:02:52.917 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'GenericDebounce' failed: org.graalvm.polyglot.PolyglotException: TypeError: item.getMetadataValue is not a function

Dependencies are fullfilled…any clue what i am missing?

I thought I had updated this template. openhab-js changed the metadata API and apparently this template is still using the old API. Give me a sec to update (there’s just four lines that need to be changed).

Fixes are in place. Remove the rule template, refresh the page, and readd it and reinstantiate the Debounce rule with the new template to pick up the changes.

While fixing this I discovered another bug where the Debounce Group property wasn’t being used in the script action. The Group had to be named “Debounce” for the rule to work.

1 Like

thanks for promptly fixing the last issue… its working now… :+1:

but one more suggestion, plz update the first post, the debounce config for the raw item in the Main UI has to look like this:

value: MotionPresence
config:
  command: true
  timeout: PT2M
  states: OFF

your given example of “timeout: 2m” does not work :slight_smile:

1 Like

Done. Thanks for telling me. I had intended to submit a PR to openhab-js so time.toZDT() would handle both types of duration strings but never got around to it.

@rlkoshak FYI

The debounce will not work correctly (it won’t apply the configured timeout value) until I add GroupItemStateChangedEvent to the event switch.

  switch(event.type) {
    case 'GroupItemStateChangedEvent':
    case 'ItemStateEvent':
    case 'ItemStateChangedEvent':
    case 'ItemCommandEvent':
      debounce();
      break;
    default:
      init();
  }

Perhaps I’m wrong, but I would imagine this event.type to always be the trigger for items in the debounce group? At least it is in my use case.

1 Like

Good catch! GroupItemStateChangedEvent is a new event introduced in OH 4.

But what’s weird is it’s working for me. I’m not sure why but GroupItemStateChanged event definitely needs to be there anyway so that might just be a mystery that never gets solved. It wasn’t working. I saw that the rule was running when it was triggered but didn’t pay attention to whether or not it was actually doing what it was supposed to. :anguished: I’ll have a new version posted shortly. Watch for the update to the original post.

1 Like

Hi,
Please, update also the textual item definition example. Instead of “2m” it should be “PT2M”.
Thanks, Rich, got it to work!

Hi Rich,

Thanks for the great work as always!

I’ve finally got around to migrating to openHAB 4.

I’m using the text based configuration, I think I’ve followed your guide correctly…my main Switch item (gPresence) is toggling between on and off based on the proxy items (in this case phones). However, the debounce item (Presence) isn’t debouncing as expected instead, always null.

Please see my setup below:

Group:Switch:OR(ON,OFF) gPresence (Debounce) { debounce="Presence"[timeout="PT2M", states="OFF", command="True"] }

// Master Presence Switch
Switch      Presence            "Home/Away [MAP(presence.map):%s]"

As always any help would be greatly appreciated.

Many thanks,

Jeevs

This config will only debounce the OFF state, not the ON state.

Run the rule manually and watch the logs for errors. When run manually it checks your config.

Put the rule into debug logging by setting the logger org.openhab.automation.rules_tools.Debounce to DEBUG level. You can do that all the usual ways from the karaf console, REST API, editing log4j2.xml or you can edit the rule created from the template. At the top of the Script Action there is a commented out line of code that will put the rule into debug level logging.

Ignore me @rlkoshak - being an absolute noob! Sorry and thank you!

After upgrade to OH 4.1 I just configure the Generic Presence Detection based on this concept. Following the documentation I installed JavaScript Scripting, afterwards the folder $OH_CONF/automation/js remained empty, obviously due to the add-on parameter “Cache Library Injection” set to ON. In my understanding the openHAB Javascript Library needed for the Debounce solution is therefore cached, but available in my OH4 installation.

My question: Does the openHAB Rules Tools will work properly with the cached version of the openHAB Javascript Library or do I have to install both locally in $OH_CONF/automation/js with help of npm (Node.js package manager)?

That’s expected but not for that reason. You’ll only see something there if you put it there either by editing files there (file based rules) or install libraries using npm.

That is correct. The JS Scripting add-on comes with the openhab-js library and therefore it does not need to be installed separately.

Yes, it works with the cached add-on version of the library for OH 4.1 forward. You do not need to install openhab-js using npm. You only need to install openhab-rules-tools via npm.

Note, if you are using openHABian, you can install OHRT through openhabian-config. Otherwise follow the instructions you can find at openHAB Rules Tools Announcements (i.e. sudo -u openhab npm i openhab_rules_tools).

Thank you very much for your quick response - and for this great tools library! Now I can go on with my presence detection implementation.

And just so you know, most of the OHRT library can now be used from Blockly rules too. See: openHAB Rules Tools [4.1.0.0;4.9.9.9]. I think they are particularly powerful in Blockly.

1 Like