-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce Entity.async_write_ha_state() to not miss state transition #21590
Introduce Entity.async_write_ha_state() to not miss state transition #21590
Conversation
Related: #10498 |
homeassistant/helpers/entity.py
Outdated
_LOGGER.exception("Update for %s fails", self.entity_id) | ||
return | ||
|
||
state, attr = stateattr or self._get_state_and_attributes() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that stateattr
is passed in as None
when force refresh, but it is still confusing to read the code as such. Please put an explicit state, attr = self._get_state_and_attributes()
inside the if force_refresh
. You probably also want to safe guard and check if stateattr is None
too. I know you do all that now, but it's hard to follow and this is important code for people to understand.
A quick state change should most likely really be an event in Home Assistant. As usual MQTT is pushing our infra to it's limits 😉 I think that this is an ok change. Had one comment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I never managed to find a reference that it is safe to assume that tasks are executed round-robin in the order they are added. Lacking that, it seems like this change has the potential to set states in the wrong order (though I don't believe it can happen with current Python).
homeassistant/helpers/entity.py
Outdated
@@ -281,6 +261,32 @@ def async_set_context(self, context): | |||
"https://goo.gl/Nvioub", self.entity_id, | |||
type(self), end - start) | |||
|
|||
return (state, attr) | |||
|
|||
async def async_update_ha_state(self, force_refresh=False, stateattr=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want stateattr
to be a part of the external interface? It seems like it would only be used internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
We're changing what we mean with a state update with this PR. Currently we mean that it's current state that will be used in the update. With this PR it will be the passed state, which might be old, that will be used in the update. I think this makes the state update unpredictable. |
@amelchio Thanks for review, now updated such that the order is preserved. |
My take is the state update is more predictable with this change. Without change:
After change:
For the case where
|
I think it's more important to preserve the integrity of the state, ie that the state value and time are true, than ensuring that the update generates a state change event. If we can't trust the state, the state change event is useless. Automations that need the very short time resolution should use events and not states changes. Integrations should follow this when implementing support for devices and services. |
In which way can't we trust the state with this change, are you worried about processing a long backlog of old states? |
After thinking about it more, I agree with @MartinHjelmare . We schedule a state update, and when that update happens, that's when we write the current state. Otherwise the name of the function no longer covers what it does. |
I think I am mainly worried about state changes no longer representing the current state. If we say that at time X the state was Y, it should be Y. It should not have been Y between previous state change and now. |
OK, but it means the
Yes, it means we would replay instead of discard state changes if we for whichever reason can't keep up. Is replaying really worse than discarding? |
How about making sure we generate a Not sure how to do that though.. |
That's impossible because state change events are fired by the state machine, the entity is not responsible for that. |
The only thing I can think of, is to consider if we should allow async entities to call CC @pvizeli |
Do you mean to make a non coroutine version? |
66070ae
to
02ff5e7
Compare
I've updated your PR @emontnemery with what I think would be ok. It's a lot simpler, and should not be confusing. |
@balloob That's much cleaner! I still think it wouldn't hurt to update the docstrings for the |
Speaking of confusing, should these methods be named |
@balloob well, the changes on If we want to go away from that pratic to old slow one that records any state change in any time, we should change |
I recall inconsistent naming being quite a barrier to entry for a new developer and these things have a tendency to get worse over time because there is not a single right way to copy. Anyway, this is not the place for an extended discussion about this – just thought I would mention it. |
@pvizeli @MartinHjelmare @amelchio I am fine with the PR in its current state. Any objects on merging this? |
I have not really formed an opinion, so no objections from me. |
Description:
Introduce
Entity.async_write_ha_state()
which can be called instead ofEntity.schedule_update_ha_state
/Entity.async_schedule_update_ha_state
to immediately update hass state and thus make sure state transitions are never missed.By calling
Entity.async_write_ha_state()
, state triggers have a deterministic behavior.As an example, if an
open
event from a door sensor is delayed and arrives to HA at the same time as theclosed
event, the state may be back toclosed
once Entity.async_update_ha_state() is called. In such a case, any automation triggering on anopen
state event from the door sensor will never be executed.Checklist:
tox
. Your PR cannot be merged unless tests pass