This is why my Threashold Alert rule template is so complicated. But it can be used for this case. Once installed a rule can be instantiated with the following settings. Any property not listed should remain the default.
- create a Group and put OutletWasherInwall_WasherWatts into a Group or you can manually edit the trigger of the rule that will be created to only trigger on this Item instead of member of group.
- Create a rule to be called. Unfortunately Rules DSL doesn’t support being called from another rule with arguments so it must be any other language. In JS this rule’s action would look something like the following. If you create a file based rule, there are no triggers.
var currStatus = items.WasherStatus.state;
if(!isAlerting && currStatus == "POWEROFF") {
WasherStatus.postUpdate("WASHING");
}
else if(isAlerting && currStatus == "WASHING") {
actions.NotificationAction.sendBroadcastNotification("Washing Machine is DONE");
}
- Create a new rule in the UI and choose Threshold Alert as the template.
a. alertRule: select the rule created in 2
b. endAlertRule: select the rule created in 2
c. thresholdState: 3
d. operator: <
e. defaultAlertDelay: PT1M
f. group: Group created in 1
The rule created from the template will call the rule you created in step 2 when the reading of OutletWasherInWall_Washer_Watts remains below 3 for one minute with isAlerting
set to true
. When the value goes to or above 3 the rule gets called with isAlerting
set to false
and it will not call the rule again until it goes below 3 for one minute.
Or use the cache, though that wasn’t working in Rules DSL until very recently. I don’t know if that got backported to 4 or if it’s only available in 5.
One case of Rules DSL broken typing system.
Another example of Rules DSL’s broken typing system.
That’s a Rules DSL convention. If you want to call a function that doesn’t take any arguments, the parens are optional. If the function starts with “get” you can omit that too. So MyDateTimeType.getZonedDateTime()
can be rendered MyDateTypeType.zonedDateTime
.
If one didn’t want to use a rule template and code this themselves, in JS OHRT has a number of classes to help manage timers.
In a JS file using rule builder the rule would look something like:
var {TimerMgr} = require('openhab_rules_tools');
rules.when().item("OutletWasherInwall_WasherWatts").changed()
.then( (event) => {
const tMgr = cache.private.get("timerMgr", () => TimerMgr());
const status = items.WasherStatus;
const watts = parseFloat(events.newState); // I don't know if events.newState has a numeric version
if(status.state != "WASHING" && watts >= 3) {
status.postUpdate("WASHING");
console.info("Washing Machine is ON");
}
else if(status.state == "WASHING" && watts < 3) {
tMgr.check("mytimer",
() => {
logInfo("Washer", "Washing Machine is DONE");
status.postUpdate("POWEROFF"),
sendBroadcastNotification("Washing Machine is DONE");
},
"PT1M", false, null, "Washing Machine Timer");
}
else {
console.info("Stopping washing machine timer");
tMgr.cancel("mytimer");
}
}).build("Set Washing Machine State", "Send an alert when the washing machine stops", [], "washingMachineAlert");
Or just using a straight timer in the cache since TimerMgr doesn’t do a whole lot for you in cases where there’s only one timer created by the rule instead of, for example, one timer per Item that can trigger the rule with a member of trigger):
rules.when().item("OutletWasherInwall_WasherWatts").changed()
.then( (event) => {
const status = items.WasherStatus;
const watts = parseFloat(events.newState); // I don't know if events.newState has a numeric version
if(status.state != "WASHING" && watts >= 3) {
status.postUpdate("WASHING");
console.info("Washing Machine is ON");
}
else if(status.state == "WASHING" && watts < 3 && !cache.private.exists("timer")) {
cache.private.put("timer", actions.ScriptExecution.createTimer(time.toZDT("PT1M"), () => {
logInfo("Washer", "Washing Machine is DONE");
status.postUpdate("POWEROFF"),
sendBroadcastNotification("Washing Machine is DONE");
cache.private.remove("timer");
});
}
else {
console.info("Stopping washing machine timer");
cache.private.get("timer")?.cancel();
cache.private.remove("timer");
}
}).build("Set Washing Machine State", "Send an alert when the washing machine stops", [], "washingMachineAlert");
In Blockly it could look something like this:
Obviously "MyItem needs to be replaced with your actual Item name.