Please see Design Pattern: What is a Design Pattern and How Do I Use Them for details on how to work with DPs.
Problem Statement
Sometimes one wants to make sure that only one instance of a Rule is running at a given time. For example, when a rule is triggered by a Group Item’s receiving updates, the Rule gets triggered more than once per event. Another use is if one needs to implement debouncing where events that take place within a certain time are ignored…
Concept 1: Debounce
Use the existence of a time stamp to indicate whether or not the Rule is locked. If the timestamp is in the future, ignore the rule trigger.
OH 3.x JavaScript
See the rate_limit library at GitHub - rkoshak/openhab-rules-tools: Library functions, classes, and examples to reuse in the development of new Rules..
Usage:
var OPENHAB_CONF = java.lang.System.getenv("OPENHAB_CONF");
load(OPENHAB_CONF+'/automation/lib/javascript/community/rateLimit.js');
var runme = function() {
// latched code goes here
}
this.rl = (rl === undefined) ? new RateLimit() : this.rl;
this.rl.run(runme, "24h"); // after the first run will wait 24 hours before runme is allowed to run again
OH 2.x Python
See the rate_limit library at GitHub - rkoshak/openhab-rules-tools: Library functions, classes, and examples to reuse in the development of new Rules..
Usage:
import community.rate_limit import RateLimit
rl = RateLimit()
...
# Only alert once a day
if event.itemState < low:
rl.run(lambda: send_alert("Remember to fill the humidifiers, {} is "
"{}%".format(name, event.itemState),
low_hum.log),
days=1)
Rules DSL 3.x
var ZonedDateTime until = null
rule "Latched Rule"
when
Item MyItem received update
then
if(until !== null && until.isAfter(now)) return; // skip this event if the timer exists
until = now.plusDays(1)
// Rule's code
end
Rules DSL 2.5
var DateTime until = null
rule "Latched Rule"
when
Item MyItem received update
then
if(until !== null && until.isAfter(now)) return; // skip this event if the timer exists
until = now.plusDays(1)
// Rule's code
end
Theory of Operation
When the Rule triggers it checks to see if there is a time stamp and if so that the timestamp is for the future. If so exit the rule. If until is in the past or not yet set save the timestamp and run the code.
Concept 2: ReentrantLocks
Deprecated. Do not use ReentrantLocks in Rules DSL. See Why have my Rules stopped running? Why Thread::sleep is a bad idea for details. Use Design Pattern: Gate Keeper with a reasonable timeout instead.
If using JSR223 Rules in OH 2.x or any type of Rules in OH 3, it is safe to use a lock in the Rule because each rule has it’s own thread. However it’s pointless to do so as only one instance of a given rule can run at a time (i.e. the latching is done for you already).
Related Design Patterns
Design Pattern | How Used |
---|---|
Design Pattern: Gate Keeper | A way to prevent the same code |
from executing more than once at a time.
Update: Added JavaScript implementation, updated for OH 3.