Perform wemo state update quickly after a timeout (#46702)
* Perform state update quickly after a timeout * with async_timeout.timeout(...) -> async with async_timeout.timeout(...)
This commit is contained in:
parent
8bee3cda37
commit
2ac075bb37
3 changed files with 35 additions and 15 deletions
|
@ -89,16 +89,28 @@ class WemoEntity(Entity):
|
|||
return
|
||||
|
||||
try:
|
||||
with async_timeout.timeout(self.platform.scan_interval.seconds - 0.1):
|
||||
await asyncio.shield(self._async_locked_update(True))
|
||||
async with async_timeout.timeout(
|
||||
self.platform.scan_interval.seconds - 0.1
|
||||
) as timeout:
|
||||
await asyncio.shield(self._async_locked_update(True, timeout))
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.warning("Lost connection to %s", self.name)
|
||||
self._available = False
|
||||
|
||||
async def _async_locked_update(self, force_update: bool) -> None:
|
||||
async def _async_locked_update(
|
||||
self, force_update: bool, timeout: Optional[async_timeout.timeout] = None
|
||||
) -> None:
|
||||
"""Try updating within an async lock."""
|
||||
async with self._update_lock:
|
||||
await self.hass.async_add_executor_job(self._update, force_update)
|
||||
# When the timeout expires HomeAssistant is no longer waiting for an
|
||||
# update from the device. Instead, the state needs to be updated
|
||||
# asynchronously. This also handles the case where an update came
|
||||
# directly from the device (device push). In that case no polling
|
||||
# update was involved and the state also needs to be updated
|
||||
# asynchronously.
|
||||
if not timeout or timeout.expired:
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class WemoSubscriptionEntity(WemoEntity):
|
||||
|
@ -152,4 +164,3 @@ class WemoSubscriptionEntity(WemoEntity):
|
|||
return
|
||||
|
||||
await self._async_locked_update(force_update)
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -6,6 +6,7 @@ import asyncio
|
|||
import threading
|
||||
from unittest.mock import patch
|
||||
|
||||
import async_timeout
|
||||
from pywemo.ouimeaux_device.api.service import ActionException
|
||||
|
||||
from homeassistant.components.homeassistant import (
|
||||
|
@ -146,7 +147,19 @@ async def test_async_update_with_timeout_and_recovery(hass, wemo_entity, pywemo_
|
|||
assert hass.states.get(wemo_entity.entity_id).state == STATE_OFF
|
||||
await async_setup_component(hass, HA_DOMAIN, {})
|
||||
|
||||
with patch("async_timeout.timeout", side_effect=asyncio.TimeoutError):
|
||||
event = threading.Event()
|
||||
|
||||
def get_state(*args):
|
||||
event.wait()
|
||||
return 0
|
||||
|
||||
if hasattr(pywemo_device, "bridge_update"):
|
||||
pywemo_device.bridge_update.side_effect = get_state
|
||||
else:
|
||||
pywemo_device.get_state.side_effect = get_state
|
||||
timeout = async_timeout.timeout(0)
|
||||
|
||||
with patch("async_timeout.timeout", return_value=timeout):
|
||||
await hass.services.async_call(
|
||||
HA_DOMAIN,
|
||||
SERVICE_UPDATE_ENTITY,
|
||||
|
@ -157,11 +170,6 @@ async def test_async_update_with_timeout_and_recovery(hass, wemo_entity, pywemo_
|
|||
assert hass.states.get(wemo_entity.entity_id).state == STATE_UNAVAILABLE
|
||||
|
||||
# Check that the entity recovers and is available after the update succeeds.
|
||||
await hass.services.async_call(
|
||||
HA_DOMAIN,
|
||||
SERVICE_UPDATE_ENTITY,
|
||||
{ATTR_ENTITY_ID: [wemo_entity.entity_id]},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
event.set()
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(wemo_entity.entity_id).state == STATE_OFF
|
||||
|
|
|
@ -69,6 +69,7 @@ async def test_async_update_with_timeout_and_recovery(
|
|||
hass, pywemo_bridge_light, wemo_entity, pywemo_device
|
||||
):
|
||||
"""Test that the entity becomes unavailable after a timeout, and that it recovers."""
|
||||
with _bypass_throttling():
|
||||
await entity_test_helpers.test_async_update_with_timeout_and_recovery(
|
||||
hass, wemo_entity, pywemo_device
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue