Rule 5.1 Predicate and Repeat While/Until Rule

Bruce, (@bravenel), two questions about the new Rule 5.1 improvements. I looked, but couldn’t find the answer.

  1. Predicates:

If a Predicate is false, are trigger events dropped or, instead, are they queued, such that they fire the rule’s actions when the Predicate becomes True? I can imagine use cases for either design, but knowing the answer is helpful for designing complex Rules.

  1. Repeat While rule, Repeat Until rule:

If a succession of OR conditions becomes True, or a succession of AND conditions becomes False, does evaluation of the rule stop and execution of the actions begin without evaluation of the remaining conditions, or, instead, is the entire rule expression evaluated and then tested? Could be useful to know when ordering the rule expression. Also, is order of evaluation guaranteed to be the written order of the conditions (sub rules) in the rule?

Thanks in advance.

1 Like

They don't happen, no queuing. If Predicate is false, subscriptions to trigger events are removed, so the rule is not triggered at all. When the Predicate becomes true, the event subscriptions are recreated, and the rule will be triggered again. Even with subscriptions active, the last state of the Predicate is checked before any actions are run, and if false, the rule exits. Net: Predicate false means the rule is not triggered.

Correct, it is a strictly left to right evaluation, and once something to the left of OR is true, or the left of AND is false, it returns true or false and stops evaluating. Of course, you have to take into account parenthetical grouping, but this will hold true for any sub-rule as well.

3 Likes

As an expert user of @toggledbits Reactor logic engine, I'm just now embarking on my first set of RM rules involving variables, and eager to stir up a little discussion/feedback on the topic of the recently introduced "Predicates". (Reactor calls them "Restrictions".)

I know @bravenel pays extreme attention to detail in both his programming and choice of nomenclature, so it bears asking...

Could the phrase "Require preconditions" carry the same meaning as "Use predicate rule"? I ask this because:

(a) I see lots of HE users wondering what a "Predicate" is or does;
(b) Normally, "rule" describes a fully formed trigger-action pairing;
(c) Whereas in RM, a "Predicate rule" is neither of those things.

Unless I'm completely missing the mark, then I'd like to nominate "Require(d) Precondition(s)" as an alternative label for this feature, since it looks and acts like Conditions that are Required before a Rule proceeds.

Thanks for hearing me out. Thoughts?

  • Libra

P.S. Part of my motivation for exploring this alternative naming comes from the earlier dialogue you posed re: making Rules ◄► Triggers ◄► Triggers Rules more straightforward for casual users. Job well done on that, btw!

"Preconditions" is only part of what is happening, as what you can use there is a full logical expression, not just conditions.

As soon as you open the Predicate page it says:

The rule defined here must be true for the Triggers to fire Actions:

The use of the word "rule" here is consistent (now) with other parts of the UI. A "rule" is a logical expression made up of conditions, logical operators, and parenthetical grouping. It is called such in each context where this sort of thing can be used: IF THEN, WHILE, REPEAT, WAIT etc.

It's difficult to find words that succinctly describe "a logical expression". "Conditions" was found to be lacking...

1 Like

Thanks for explaining, and I follow your reasoning. Keep up the fine work!! :heart:

Next, while struggling to convert one of my more complex Reactor rules (which allow free-form expression entry and nested arithmetic) over to RM (which constrains expressions to a series of drop-down pickers), I think I've reached am impasse with Variable Math in this unusual example:

I currently evaluate the average temperature deviation among 4 devices in my home (an ecobee Thermostat plus 3 remote sensors), using the single expression declaration inside an MSR rule:

acTempVar = (abs(acTemp-senTempMBR) + abs(acTemp-senTempKitchen) + abs(acTemp-senTempHBath))/3

Is there a way to accomplish such a 'messy, nested expression' in RM without defining a bunch of (by my count, at least 8, possibly 12) intermediate variables? For instance,

senTempMBR = Bedroom Temp (decimal)
senTempKitchen = Kitchen Temp (decimal)
senTempHBath = Hall Bath Temp (decimal)
acTemp = Thermostat Temp (decimal)
[Insert: rule to set those values whenever any watched sensor changes]
acTempVar = 0 (decimal)
diffA = senTempMBR - acTemp
diffB = senTempKitchen - acTemp
diffC = senHBath - acTemp
absA = absolute diffA
absB = absolute diffB
absC = absolute diffC
sumABC = absA + absB + absC (NOTE: I believe this is currently impossible?)
acTempVar = sumABC / 3

If not, I'll live. Though I've scoured the Docs wiki, I'm unaware of an alternative context to perform variable math, seems I've heard mention of some place to insert code. Just looking for the best way to manage this MSR►HE exercise.

Guidance appreciated.

UPDATE: I refer others to this thread about the prospect of writing your own Groovy app in the Code Editor.

Given that you can add/subtract a variable to another variable, you only need a single 'temp' variable, that can be a local variable.

set temp to acTemp - senTempMBR
set acTempVar to abs(temp)
set temp to acTemp - senTempKitchen
set temp to abs(temp)
set acTempVar to acTempVar + temp
set temp to acTemp - senTempHBath
set temp to abs(temp)
set acTempVar to acTempVar + temp
set acTempVar to acTempVar / 3

These sort of things point towards writing your own custom app in Groovy.

2 Likes

Bruce, you inspired me to go minimal – using only the existing 5 variables, by modifying them all in-place – with the following sequence of 12 actions, which I leave here for others to contemplate should they run into the same mental roadblock:

Of course, this illustrates a couple of points which may deserve attention, namely:

(a) The NEW ("after") value of each variable is being displayed within each Set action, instead of the expected OLD ("before") or INTERMEDIATE value. e.g. the final action ought to read
Set acTempVar to (acTempVar(2.3) / 3.0)

(b) It would be nice to see the resultant of each step displayed on the right side; again, e.g.
Set acTempVar to (acTempVar(2.3) / 3.0) yields or = (0.766667)

Uh-oh, @bravenel while I had not anticipated my workflow to yield anything out of the ordinary, it seems to have done so anyway, to wit:

(a) I created a Hub Variable, called TempAvgVar, to receive the calculated value from the actions shown immediately above; (OK)
(b) I added a "Set" action which copies the value of acTempVar (a local RM variable) to TempAvgVar (the Hub var); (OK)
(c) Expected values would typically be in the range 0 to 4, and characteristically hover around 0.3 - 0.7; (OK)
var_value_before

(d) However, the very next time(s) that the Rule runs - upon a "change" to any of the watched sensor values - I'm noticing that TempAvgVar gets set to a value of 72.5 (seemingly equal to one of the sensors?!); (NOT OK)
var_value_after

(e) On subsequent refreshes the value of TempAvgVar will again increase, to 213.4 (seemingly the sum of all three sensors?!) and settle; (NOT OK)
var_value_later

Confoundingly, a check of the Logs (pasted below) for the last few iterations shows the value blowing up, but not always matching what I see in the Settings ► Hub Variables ► Refresh dialogue. Just wanted you to know:

app:1172021-11-15 03:20:02.636 pm infoAction: Set TempAvgVar to acTempVar(73.1)
app:1172021-11-15 03:20:02.607 pm infoAction: Set acTempVar to (acTempVar(219.3) / 3.0)
app:1172021-11-15 03:20:02.561 pm infoAction: Set TempAvgVar to acTempVar(146.5)
app:1172021-11-15 03:20:02.539 pm infoAction: Set acTempVar to (acTempVar(146.5) + senTempMBR(72.8))
app:1172021-11-15 03:20:02.515 pm infoAction: Set TempAvgVar to acTempVar(73.1)
app:1172021-11-15 03:20:02.497 pm infoAction: Set acTempVar to (acTempVar(219.3) / 3.0)
app:1172021-11-15 03:20:02.481 pm infoAction: Set acTempVar to (senTempHBath(71.9) + senTempKitchen(74.6))
app:1172021-11-15 03:20:02.453 pm infoAction: Set acTempVar to (acTempVar(219.3) / 3.0)
app:1172021-11-15 03:20:02.436 pm infoAction: Set acTempVar to (acTempVar(146.5) + senTempMBR(72.8))
app:1172021-11-15 03:20:02.420 pm infoAction: Set acTempVar to (acTempVar(146.5) + senTempMBR(72.8))
app:1172021-11-15 03:20:02.395 pm infoAction: Set senTempMBR to absolute(senTempMBR(72.8))
app:1172021-11-15 03:20:02.374 pm infoAction: Set acTempVar to (senTempHBath(71.9) + senTempKitchen(74.6))
app:1172021-11-15 03:20:02.357 pm infoAction: Set acTempVar to (senTempHBath(71.9) + senTempKitchen(74.6))
app:1172021-11-15 03:20:02.295 pm infoAction: Set senTempKitchen to absolute(senTempKitchen(74.6))
app:1172021-11-15 03:20:02.276 pm infoAction: Set senTempMBR to absolute(senTempMBR(-72.8))
app:1172021-11-15 03:20:02.260 pm infoAction: Set senTempMBR to absolute(senTempMBR(-72.8))
app:1172021-11-15 03:20:02.243 pm infoAction: Set senTempHBath to absolute(senTempHBath(71.9))
app:1172021-11-15 03:20:02.227 pm infoAction: Set senTempKitchen to absolute(senTempKitchen(-74.6))
app:1172021-11-15 03:20:02.208 pm infoAction: Set senTempKitchen to absolute(senTempKitchen(-74.6))
app:1172021-11-15 03:20:02.195 pm infoAction: Set senTempMBR to (senTempMBR(0.2) - acTemp(73))
app:1172021-11-15 03:20:02.175 pm infoAction: Set senTempHBath to absolute(senTempHBath(-71.9))
app:1172021-11-15 03:20:02.160 pm infoAction: Set senTempHBath to absolute(senTempHBath(-71.9))
app:1172021-11-15 03:20:02.146 pm infoAction: Set senTempKitchen to (senTempKitchen(-1.6) - acTemp(73))
app:1172021-11-15 03:20:02.126 pm infoAction: Set senTempMBR to (senTempMBR(73.2) - acTemp(73))
app:1172021-11-15 03:20:02.107 pm infoAction: Set senTempMBR to (senTempMBR(73.2) - acTemp(73))
app:1172021-11-15 03:20:02.089 pm infoAction: Set senTempHBath to (senTempHBath(1.1) - acTemp(73))
app:1172021-11-15 03:20:02.072 pm infoAction: Set senTempKitchen to (senTempKitchen(71.4) - acTemp(73))
app:1172021-11-15 03:20:02.055 pm infoAction: Set senTempKitchen to (senTempKitchen(71.4) - acTemp(73))
app:1172021-11-15 03:20:02.035 pm infoAction: Set senTempMBR to Bedroom Temperature(73.2)
app:1172021-11-15 03:20:02.020 pm infoAction: Set senTempHBath to (senTempHBath(74.1) - acTemp(73))
app:1172021-11-15 03:20:02.004 pm infoAction: Set senTempHBath to (senTempHBath(74.1) - acTemp(73))
app:1172021-11-15 03:20:01.981 pm infoAction: Set senTempKitchen to Kitchen Temperature(71.4)
app:1172021-11-15 03:20:01.963 pm infoAction: Set senTempMBR to Bedroom Temperature(73.2)
app:1172021-11-15 03:20:01.946 pm infoAction: Set senTempMBR to Bedroom Temperature(73.2)
app:1172021-11-15 03:20:01.930 pm infoAction: Set senTempHBath to Hall Lav Temperature(74.1)
app:1172021-11-15 03:20:01.913 pm infoAction: Set senTempKitchen to Kitchen Temperature(71.4)
app:1172021-11-15 03:20:01.896 pm infoAction: Set senTempKitchen to Kitchen Temperature(71.4)
app:1172021-11-15 03:20:01.890 pm infoAction: Set acTemp to Thermostat Temperature(73)
app:1172021-11-15 03:20:01.881 pm infoAction: Set senTempHBath to Hall Lav Temperature(74.1)
app:1172021-11-15 03:20:01.806 pm infoAction: Set senTempHBath to Hall Lav Temperature(74.1)
app:1172021-11-15 03:20:01.791 pm infoAction: Set acTemp to Thermostat Temperature(73)
app:1172021-11-15 03:20:01.773 pm infoAction: Set acTemp to Thermostat Temperature(73)
app:1172021-11-15 03:20:01.415 pm infoAction: Set TempAvgVar to acTempVar(1.066667)
app:1172021-11-15 03:20:01.386 pm infoAction: Set acTempVar to (acTempVar(3.2) / 3.0)
app:1172021-11-15 03:20:01.355 pm infoAction: Set acTempVar to (acTempVar(2.8) + senTempMBR(0.4))
app:1172021-11-15 03:20:01.321 pm infoAction: Set acTempVar to (senTempHBath(1) + senTempKitchen(1.8))
app:1172021-11-15 03:20:01.290 pm infoAction: Set senTempMBR to absolute(senTempMBR(0.4))
app:1172021-11-15 03:20:01.262 pm infoAction: Set senTempKitchen to absolute(senTempKitchen(-1.8))
app:1172021-11-15 03:20:01.234 pm infoAction: Set senTempHBath to absolute(senTempHBath(1))
app:1172021-11-15 03:20:01.203 pm infoAction: Set senTempMBR to (senTempMBR(73.4) - acTemp(73))
app:1172021-11-15 03:20:01.130 pm infoAction: Set senTempKitchen to (senTempKitchen(71.2) - acTemp(73))
app:1172021-11-15 03:20:01.090 pm infoAction: Set senTempHBath to (senTempHBath(74) - acTemp(73))
app:1172021-11-15 03:20:01.061 pm infoAction: Set senTempMBR to Bedroom Temperature(73.4)
app:1172021-11-15 03:20:01.037 pm infoAction: Set senTempKitchen to Kitchen Temperature(71.2)
app:1172021-11-15 03:20:01.013 pm infoAction: Set senTempHBath to Hall Lav Temperature(74.0)
app:1172021-11-15 03:20:00.990 pm infoAction: Set acTemp to Thermostat Temperature(73)

IMPORTANT OBSERVATION: If I go back into the RM rule and manually click "Run Actions", then "Done" and return to Settings > Hub Variables to inspect the value of TempAvgVar, it is (as expected) back to a nominal value of 0.96667! And from all appearances, it has remained nominal since. Bizarro.

Any insights? Do RM actions run in sequential order? (Log suggests otherwise.) Are variable assignments possibly being passed by reference** instead of contained value? Potential bug? Is computing local RM variables in-place like this a risky practice??

Hopefully this feedback makes sense. Didn't know where else to post.

  • Libra

**This could explain why intermediate values listed in the Log don't match what's shown in the RM UI.

You can use log actions to show step by step what is happening as the app runs. Those acceptable %variable-name% as a way to show variable values.

At first blush, the Log seems to indicate that the RM actions are being run in a non-deterministic fashion. For example, hub var TempAvgVar gets set multiple times in quick succession, rather than just once at the end of the Actions list. First few lines...

app:1172021-11-15 03:20:02.636 pm infoAction: Set TempAvgVar to acTempVar(73.1)
app:1172021-11-15 03:20:02.607 pm infoAction: Set acTempVar to (acTempVar(219.3) / 3.0)
app:1172021-11-15 03:20:02.561 pm infoAction: Set TempAvgVar to acTempVar(146.5)
app:1172021-11-15 03:20:02.539 pm infoAction: Set acTempVar to (acTempVar(146.5) + senTempMBR(72.8))
app:1172021-11-15 03:20:02.515 pm infoAction: Set TempAvgVar to acTempVar(73.1)

I'm talking about doing your own logging directly from the rule, using the log action. Those logs you are showing are pulling information from the UI of the rule creation, and it is not updated in realtime as the rule runs, hence can be misleading as to what is actually happening.

1 Like

Roger that and understood. Will examine. Note that I've had Logging... Actions set throughout in the RM.

Maddeningly, yet happily, the situation seems to have settled, as the value of my hub variable remains nominal since I first observed the anomalies 90 minutes ago. Perhaps we'll never know what that was about.

If you put in your own logging with log actions, I would suggest you turn that off.

2 Likes