Replies: 2 comments 2 replies
-
Hello @jlkermit 👋 Maybe you can try the following to rely more on a pyscriptive approach using decorators to check whether to run or not: state.set("pyscript.ignore_me", false)
@time_trigger("once(now)")
def set_value():
state.set("pyscript.ignore_me", true)
...
state.set("pyscript.ignore_me", false)
@state_trigger(TEST_ENTITY_ID)
@state_active("pyscript.ignore_me == false")
def state_monitor_factory(**kwargs):
...
|
Beta Was this translation helpful? Give feedback.
-
Trigger functions run asynchronously after they are triggered. There's no guarantee that the statements inside one trigger function will be executed before or after another function's statements when triggered at almost the same time. Statements could even be interleaved between functions (actually, the granularity is finer than that: one function could give up control in the middle of evaluating an expression, and execution of the other function could continue next). This means you can suffer from various race conditions if you don't make your code robust to indeterminate relative order of execution. As you saw, when you change the state variable in one function, it takes a bit of time for HASS to generate the state changed event, which means the 2nd function actually gets triggered after the first one finishes, so your flag is already reset. But that's not guaranteed. @IgnusG's solution is more robust, but is still not guaranteed - the state trigger might not be evaluated until after the first function finishes. There are several solutions I can think of. One is to use an async queue to communicate state updates that should be ignored. The function that is updating the state which wants to skip the state monitor function writes the new state value to the queue. The state monitor function checks the queue, and if the values match then it ignores the update. Here's some untested pseudo code:
However, there's an unlikely but still potential race condition that the state triggers happen out of order, so the ignore values in the queue could be extracted in the wrong order. So this isn't a 100% robust solution. You could use a map to count the number of times each state set should be ignored. You'll need a lock to prevent race conditions while it is updated in each function.
The simplest solution would be to set an attribute of the state variable, assuming that doesn't break anything that uses the state variable:
This is robust since the information about what to ignore is part of the state update, so is immune to any order-of-execution issues. These are all untested. |
Beta Was this translation helpful? Give feedback.
-
Is there a way to allow a function with a state decorator to be called while another function that is running is manipulating the state of the entity that is in the state decorator. I tried using task.wait_until(state_trigger='entity id'), but it didn't work, for obvious reasons I think.
What I'm asking is there a function available similar to 'DoEvents' found in the non-async language VBA?
Consider the following code:
Here is the log:
Beta Was this translation helpful? Give feedback.
All reactions