mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 01:38:02 +00:00
Introduce Entity.async_write_ha_state() to not miss state transition (#21590)
* Copy state in schedule_update_ha_state * Lint * Fix broken test * Review comment, improve docstring * Preserve order of state updates * Rewrite * Break up async_update_ha_state * Update binary_sensor.py * Review comments * Update docstring * hass -> ha * Update entity.py * Update entity.py
This commit is contained in:
parent
458548daec
commit
fc81826763
@ -117,7 +117,7 @@ class MqttBinarySensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate,
|
||||
await self.availability_discovery_update(config)
|
||||
await self.device_info_discovery_update(config)
|
||||
await self._subscribe_topics()
|
||||
self.async_schedule_update_ha_state()
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def _subscribe_topics(self):
|
||||
"""(Re)Subscribe to topics."""
|
||||
@ -130,7 +130,7 @@ class MqttBinarySensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate,
|
||||
"""Switch device off after a delay."""
|
||||
self._delay_listener = None
|
||||
self._state = False
|
||||
self.async_schedule_update_ha_state()
|
||||
self.async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def state_message_received(_topic, payload, _qos):
|
||||
@ -159,7 +159,7 @@ class MqttBinarySensor(MqttAttributes, MqttAvailability, MqttDiscoveryUpdate,
|
||||
self._delay_listener = evt.async_call_later(
|
||||
self.hass, off_delay, off_delay_listener)
|
||||
|
||||
self.async_schedule_update_ha_state()
|
||||
self.async_write_ha_state()
|
||||
|
||||
self._sub_state = await subscription.async_subscribe_topics(
|
||||
self.hass, self._sub_state,
|
||||
|
@ -222,6 +222,23 @@ class Entity:
|
||||
_LOGGER.exception("Update for %s fails", self.entity_id)
|
||||
return
|
||||
|
||||
self._async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def async_write_ha_state(self):
|
||||
"""Write the state to the state machine."""
|
||||
if self.hass is None:
|
||||
raise RuntimeError("Attribute hass is None for {}".format(self))
|
||||
|
||||
if self.entity_id is None:
|
||||
raise NoEntitySpecifiedError(
|
||||
"No entity id specified for entity {}".format(self.name))
|
||||
|
||||
self._async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def _async_write_ha_state(self):
|
||||
"""Write the state to the state machine."""
|
||||
start = timer()
|
||||
|
||||
if not self.available:
|
||||
@ -311,13 +328,27 @@ class Entity:
|
||||
def schedule_update_ha_state(self, force_refresh=False):
|
||||
"""Schedule an update ha state change task.
|
||||
|
||||
That avoid executor dead looks.
|
||||
Scheduling the update avoids executor deadlocks.
|
||||
|
||||
Entity state and attributes are read when the update ha state change
|
||||
task is executed.
|
||||
If state is changed more than once before the ha state change task has
|
||||
been executed, the intermediate state transitions will be missed.
|
||||
"""
|
||||
self.hass.add_job(self.async_update_ha_state(force_refresh))
|
||||
|
||||
@callback
|
||||
def async_schedule_update_ha_state(self, force_refresh=False):
|
||||
"""Schedule an update ha state change task."""
|
||||
"""Schedule an update ha state change task.
|
||||
|
||||
This method must be run in the event loop.
|
||||
Scheduling the update avoids executor deadlocks.
|
||||
|
||||
Entity state and attributes are read when the update ha state change
|
||||
task is executed.
|
||||
If state is changed more than once before the ha state change task has
|
||||
been executed, the intermediate state transitions will be missed.
|
||||
"""
|
||||
self.hass.async_create_task(self.async_update_ha_state(force_refresh))
|
||||
|
||||
async def async_device_update(self, warning=True):
|
||||
|
@ -275,16 +275,16 @@ async def test_entity_media_states(hass: HomeAssistantType):
|
||||
state = hass.states.get('media_player.speaker')
|
||||
assert state.state == 'playing'
|
||||
|
||||
entity.new_media_status(media_status)
|
||||
media_status.player_is_playing = False
|
||||
media_status.player_is_paused = True
|
||||
entity.new_media_status(media_status)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get('media_player.speaker')
|
||||
assert state.state == 'paused'
|
||||
|
||||
entity.new_media_status(media_status)
|
||||
media_status.player_is_paused = False
|
||||
media_status.player_is_idle = True
|
||||
entity.new_media_status(media_status)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get('media_player.speaker')
|
||||
assert state.state == 'idle'
|
||||
|
Loading…
x
Reference in New Issue
Block a user