[Reactor] Variables not updating correctly in latest-25201-2aa18550
-
Clearly there's a lot of context you haven't posted, so I really don't have enough to go on.
I can tell you that if a rule is in mid-evaluation, the re-evaluation of variables and triggers in the same rule won't happen instantly or more than once -- infinite loops have to be prevented. What will happen is that a request for re-evaluation will be queued for later, but it's not deterministic when that runs (except that it won't run before the current evaluation completes). If there's already a pending request for re-evaluation queued, new requests are ignored. This is all to prevent infinite loops in rule evaluations where rules manipulate devices and rule-based variables in Reactions that are also part of the rule's dependencies.
And to be specific, the "Force re-evaluation" only queues a request to re-evaluate the rule's triggers and local variables at some point in the future. It does not instantly and immediately re-evaluate every dependent variable of the variable being set.
-
Ok, I was probably lucky in the past, I don't know. I could send you the rule's JSON if you want to take a look. Anyway, I'll try to move some logic into set variables for the time being. Thanks.
@therealdb I noticed a similar behaviour with build 25208, although the issue might have been present also in the earlier (25201) build.
In essence I have a rule with a global variable correctly triggering when it has a certain value, but in reactions it has a Telegram notification using a local variable as message (like this: ${{ msg }}). And this local variable "msg" is using the same global variable that triggered the rule, but its value is something totally different, i.e. seems that it's not updating.
I'm also sure this rule was working fine before, with variables correctly updating.
-
@therealdb I noticed a similar behaviour with build 25208, although the issue might have been present also in the earlier (25201) build.
In essence I have a rule with a global variable correctly triggering when it has a certain value, but in reactions it has a Telegram notification using a local variable as message (like this: ${{ msg }}). And this local variable "msg" is using the same global variable that triggered the rule, but its value is something totally different, i.e. seems that it's not updating.
I'm also sure this rule was working fine before, with variables correctly updating.
@tunnus said in [Reactor] Variables not updating correctly in latest-25201-2aa18550:
In essence I have a rule with a global variable correctly triggering when it has a certain value, but in reactions it has a Telegram notification using a local variable as message (like this: ${{ msg }}).
You know what to do (i.e. what I need to see). I can't do anything from just a post like this.
My simple test case:
- I have a global expression/variable
testVar
(expressionless) with a numeric value assigned. - I have a rule that triggers on
testVar
changing, and sends me a notification in its SET Reaction (shown below). - I have a Reaction that I can run manually to increment
testVar
by 1 using a Set Variable action. This triggers the rule.
This works as expected: when the Reaction is run,
testVar
is incremented by 1. The change is detected by the rule, which updates itslocaltest
variable and then uses that in a notification, which displays the correct value.To be clear here, the Rule triggers on the global variable changing, not the local variable.
- I have a global expression/variable
-
@tunnus said in [Reactor] Variables not updating correctly in latest-25201-2aa18550:
In essence I have a rule with a global variable correctly triggering when it has a certain value, but in reactions it has a Telegram notification using a local variable as message (like this: ${{ msg }}).
You know what to do (i.e. what I need to see). I can't do anything from just a post like this.
My simple test case:
- I have a global expression/variable
testVar
(expressionless) with a numeric value assigned. - I have a rule that triggers on
testVar
changing, and sends me a notification in its SET Reaction (shown below). - I have a Reaction that I can run manually to increment
testVar
by 1 using a Set Variable action. This triggers the rule.
This works as expected: when the Reaction is run,
testVar
is incremented by 1. The change is detected by the rule, which updates itslocaltest
variable and then uses that in a notification, which displays the correct value.To be clear here, the Rule triggers on the global variable changing, not the local variable.
@toggledbits I did a very similar testing arrangement and got the same results as you, i.e. working fine. I guess I have to monitor this more closely and if this update problem happens again, find a way to reproduce it consistently.
One notable difference between my production expression and the test expression is that the production one is a lot more complicated:
- I have a global expression/variable
-
@tunnus said in [Reactor] Variables not updating correctly in latest-25201-2aa18550:
In essence I have a rule with a global variable correctly triggering when it has a certain value, but in reactions it has a Telegram notification using a local variable as message (like this: ${{ msg }}).
You know what to do (i.e. what I need to see). I can't do anything from just a post like this.
My simple test case:
- I have a global expression/variable
testVar
(expressionless) with a numeric value assigned. - I have a rule that triggers on
testVar
changing, and sends me a notification in its SET Reaction (shown below). - I have a Reaction that I can run manually to increment
testVar
by 1 using a Set Variable action. This triggers the rule.
This works as expected: when the Reaction is run,
testVar
is incremented by 1. The change is detected by the rule, which updates itslocaltest
variable and then uses that in a notification, which displays the correct value.To be clear here, the Rule triggers on the global variable changing, not the local variable.
@toggledbits, some extra information that I hope will help solve this. I've noticed a few other instances where variables aren't updating. These happen to be Telegram notifications, although I don't think Telegram itself is the issue—it's just that I tend to notice notifications more easily than changes in the UI.
In all cases, a common denominator is that local variables (in my case, 'msg') that include other local or global variables also contain "if/else" and/or "case" statements.
Examples below:
msg = solar_last_day == "ERROR" ? "Error retrieving solar stats" : (solar_last_day > 1 ? "Daily solar stats are ready, total " + round(solar_last_day, 1) + " kWh, peak " + peak_array[0] + " W" + " @" + peak_array[1] : "NA") msg = case when success == true: "Export limit activated, sell price " + round(g_NordpoolCurrentPriceSellReal, 2) + " c/kWh (VAT 0%-mgin), grid balance " + round(g_FronPowerSum, 0) + " W" when success == false: "Export limit could not be activated?" else "Setting export limit failed" end
I'm not sure if it's related, but there was a recent bug involving global expressions not updating when certain functions were used (fixed in build 25082)
- I have a global expression/variable
-
I'd need a full picture of this... every variable and rule involved. This is a very complex area to look at.
Again, the key rule to understand here, is that the local variables in a Rule do not update every time a global or other local they refer to changes -- they only update when the Rule has been marked for evaluation. The recomputation of the local variable values occurs before trigger conditions are evaluated, and only then. That is very different from the way global variables are handled.
Also in your second example, the use of "==" is a "loose" comparison. The use of "===" is tighter and matches type. In your example, if
success
is 0 (numeric), that will satisfy the testsuccess == false
-- that's true because numeric 0 will cast to boolean false, so they are logically equal, although not exactly equal. That alone would explain unexpected results, if the values ofsuccess
can be other than true or false. -
I'd need a full picture of this... every variable and rule involved. This is a very complex area to look at.
Again, the key rule to understand here, is that the local variables in a Rule do not update every time a global or other local they refer to changes -- they only update when the Rule has been marked for evaluation. The recomputation of the local variable values occurs before trigger conditions are evaluated, and only then. That is very different from the way global variables are handled.
Also in your second example, the use of "==" is a "loose" comparison. The use of "===" is tighter and matches type. In your example, if
success
is 0 (numeric), that will satisfy the testsuccess == false
-- that's true because numeric 0 will cast to boolean false, so they are logically equal, although not exactly equal. That alone would explain unexpected results, if the values ofsuccess
can be other than true or false.@toggledbits "success" variable cannot be other than true or false, that I know.
But is it so that every time a rule is triggered, its local variables are evaluated (or should be evaluated) at least once?
Also, you wrote earlier: "If there's already a pending request for re-evaluation queued, new requests are ignored. This is all to prevent infinite loops in rule evaluations where rules manipulate devices and rule-based variables in Reactions that are also part of the rule's dependencies"
I was wondering if this could happen in cases where re-evaluation is queued but somehow gets stuck, and because new requests are ignored, updates won't occur?
-
@toggledbits "success" variable cannot be other than true or false, that I know.
But is it so that every time a rule is triggered, its local variables are evaluated (or should be evaluated) at least once?
Also, you wrote earlier: "If there's already a pending request for re-evaluation queued, new requests are ignored. This is all to prevent infinite loops in rule evaluations where rules manipulate devices and rule-based variables in Reactions that are also part of the rule's dependencies"
I was wondering if this could happen in cases where re-evaluation is queued but somehow gets stuck, and because new requests are ignored, updates won't occur?
@tunnus said in [Reactor] Variables not updating correctly in latest-25201-2aa18550:
I was wondering if this could happen in cases where re-evaluation is queued but somehow gets stuck, and because new requests are ignored, updates won't occur?
Well, they won't get stuck, but there is no guaranteed order to the re-evaluation. Other things waiting to execute can run before the re-evaluation happens, including things that could change the global variables or entity attributes on which the first Rule depends.
Here's something to try (it's the @therealdb solution he mentioned):
- Make
msg
an expressionless local variable. - Before your notification, use a Set Variable or Script Action to compute the value of
msg
that you want to send in the notification.
Would look something like this:
...or this, using a Script Action...
I personally prefer the Script Action because you can set several variables at once in the script, if that's what you need, and the syntax looks cleaner (you don't have to use the
${{ }}
substitution. - Make
-
@tunnus said in [Reactor] Variables not updating correctly in latest-25201-2aa18550:
I was wondering if this could happen in cases where re-evaluation is queued but somehow gets stuck, and because new requests are ignored, updates won't occur?
Well, they won't get stuck, but there is no guaranteed order to the re-evaluation. Other things waiting to execute can run before the re-evaluation happens, including things that could change the global variables or entity attributes on which the first Rule depends.
Here's something to try (it's the @therealdb solution he mentioned):
- Make
msg
an expressionless local variable. - Before your notification, use a Set Variable or Script Action to compute the value of
msg
that you want to send in the notification.
Would look something like this:
...or this, using a Script Action...
I personally prefer the Script Action because you can set several variables at once in the script, if that's what you need, and the syntax looks cleaner (you don't have to use the
${{ }}
substitution.@toggledbits ok, I'll have to try script action. Still, as @therealdb stated, I'm also sure the "old style" used to work with pre-252xx builds.
- Make
-
@toggledbits ok, I'll have to try script action. Still, as @therealdb stated, I'm also sure the "old style" used to work with pre-252xx builds.
Some strange results happened while I was experimenting with script action. I noticed that the order of local variables had an effect whether those variables did update or not.
If I had e.g. the following order:
"peak_power" did not update. But if I switched places of "ok_to_reset" and "peak_power", "peak_power" started to update in real-time:
-
Post your script. Based on the instructions given, your local variables should be expressionless, so that seems wrong and I want to see what your script is trying to do.
I can tell you right now, if
ok_to_reset
is expressionless and you are resetting it in the Script Action script, and expectingpeak_power
to see the updated value, it won't work. -
Post your script. Based on the instructions given, your local variables should be expressionless, so that seems wrong and I want to see what your script is trying to do.
I can tell you right now, if
ok_to_reset
is expressionless and you are resetting it in the Script Action script, and expectingpeak_power
to see the updated value, it won't work.@toggledbits that wasn’t what I was trying to convey here. Let’s forget script action for a moment as it has no relevance for my finding.
What I’m trying to say here is that by merely changing the order of variables (and to be clear, that setup has worked before), my rules are working again. Somehow new builds do not like if expressionless variables are in the middle of regular ones. If they are last in line, all is well. Sounds crazy, but please test.
-
I'll say again, local variables are not processed/evaluated in the same way as global variables. Local variables are only evaluated when the Rule to which they belong is being evaluated (i.e. its triggers are being checked). They are not evaluated when a dependent local variable is changed. When the Rule is evaluated, its local variables, if any, are evaluated before the triggers, and yes, they are evaluated in the order in which they are defined. That is known.
Combine this with using a Set Variable action... if you don't check the "Force re-evaluation" checkbox, any other local variables that use the variable being set will not be updated until the Rule is next evaluated. If you check the box, it forces a Rule evaluation, and it is the second evaluation that will update the dependent variables.
The Script Action is absolutely relevant in your case, at least from what you've posted, because you apparently still had local variables that are dependent on the local variable that the script was changing, and that was not consistent with my recommendation. The script will not cause the dependent variables to be updated, because there is no "Force re-evaluation" option for the script, and local variables are not dependency-scanned/triggered, as I said above. That means your script action will change the local variable
ok_to_reset
, but that won't makepeak_power
change immediately after. That is why I recommended that you make all local variables expressionless when using the Script Action, and do all of the work in the script, none of the work in the local variables' expressions.None of this is new. And again, no changes have been made to how variables (global or local) in any of these recent builds. The earlier changes you mentioned to make
isRuleSet()
andisRuleEnabled()
trigger with the rules they reference (build 25082 -- a long time ago) was a change to the implementation of those functions themselves , but was not in any way a change to the mechanism that handles changes in global expressions. -
I'll say again, local variables are not processed/evaluated in the same way as global variables. Local variables are only evaluated when the Rule to which they belong is being evaluated (i.e. its triggers are being checked). They are not evaluated when a dependent local variable is changed. When the Rule is evaluated, its local variables, if any, are evaluated before the triggers, and yes, they are evaluated in the order in which they are defined. That is known.
Combine this with using a Set Variable action... if you don't check the "Force re-evaluation" checkbox, any other local variables that use the variable being set will not be updated until the Rule is next evaluated. If you check the box, it forces a Rule evaluation, and it is the second evaluation that will update the dependent variables.
The Script Action is absolutely relevant in your case, at least from what you've posted, because you apparently still had local variables that are dependent on the local variable that the script was changing, and that was not consistent with my recommendation. The script will not cause the dependent variables to be updated, because there is no "Force re-evaluation" option for the script, and local variables are not dependency-scanned/triggered, as I said above. That means your script action will change the local variable
ok_to_reset
, but that won't makepeak_power
change immediately after. That is why I recommended that you make all local variables expressionless when using the Script Action, and do all of the work in the script, none of the work in the local variables' expressions.None of this is new. And again, no changes have been made to how variables (global or local) in any of these recent builds. The earlier changes you mentioned to make
isRuleSet()
andisRuleEnabled()
trigger with the rules they reference (build 25082 -- a long time ago) was a change to the implementation of those functions themselves , but was not in any way a change to the mechanism that handles changes in global expressions.@toggledbits I’m not using script action currently, and those screenshots were from a rule that uses set variable action.
But could you test my finding? Even rule triggers are not relevant when reproducing this finding. Just put a variable referencing an entity which frequently changes as a first one. Then make expressionless variable second, and as a third one make some kind of expression which uses first variable and does some calculation with it. Observe what happens and then swap second and third line and again watch what happens.