mirror of
https://github.com/home-assistant/core.git
synced 2025-07-08 13:57:10 +00:00
Prevent Shelly raising in a task (#116355)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
8ac493fcf4
commit
d1f88ffd1e
@ -154,24 +154,27 @@ class ShellyCoordinatorBase(DataUpdateCoordinator[None], Generic[_DeviceT]):
|
|||||||
)
|
)
|
||||||
self.device_id = device_entry.id
|
self.device_id = device_entry.id
|
||||||
|
|
||||||
async def _async_device_connect(self) -> None:
|
async def _async_device_connect_task(self) -> bool:
|
||||||
"""Connect to a Shelly Block device."""
|
"""Connect to a Shelly device task."""
|
||||||
LOGGER.debug("Connecting to Shelly Device - %s", self.name)
|
LOGGER.debug("Connecting to Shelly Device - %s", self.name)
|
||||||
try:
|
try:
|
||||||
await self.device.initialize()
|
await self.device.initialize()
|
||||||
update_device_fw_info(self.hass, self.device, self.entry)
|
update_device_fw_info(self.hass, self.device, self.entry)
|
||||||
except DeviceConnectionError as err:
|
except DeviceConnectionError as err:
|
||||||
raise UpdateFailed(f"Device disconnected: {repr(err)}") from err
|
LOGGER.debug(
|
||||||
|
"Error connecting to Shelly device %s, error: %r", self.name, err
|
||||||
|
)
|
||||||
|
return False
|
||||||
except InvalidAuthError:
|
except InvalidAuthError:
|
||||||
self.entry.async_start_reauth(self.hass)
|
self.entry.async_start_reauth(self.hass)
|
||||||
return
|
return False
|
||||||
|
|
||||||
if not self.device.firmware_supported:
|
if not self.device.firmware_supported:
|
||||||
async_create_issue_unsupported_firmware(self.hass, self.entry)
|
async_create_issue_unsupported_firmware(self.hass, self.entry)
|
||||||
return
|
return False
|
||||||
|
|
||||||
if not self._pending_platforms:
|
if not self._pending_platforms:
|
||||||
return
|
return True
|
||||||
|
|
||||||
LOGGER.debug("Device %s is online, resuming setup", self.entry.title)
|
LOGGER.debug("Device %s is online, resuming setup", self.entry.title)
|
||||||
platforms = self._pending_platforms
|
platforms = self._pending_platforms
|
||||||
@ -193,6 +196,8 @@ class ShellyCoordinatorBase(DataUpdateCoordinator[None], Generic[_DeviceT]):
|
|||||||
# Resume platform setup
|
# Resume platform setup
|
||||||
await self.hass.config_entries.async_forward_entry_setups(self.entry, platforms)
|
await self.hass.config_entries.async_forward_entry_setups(self.entry, platforms)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
async def _async_reload_entry(self) -> None:
|
async def _async_reload_entry(self) -> None:
|
||||||
"""Reload entry."""
|
"""Reload entry."""
|
||||||
self._debounced_reload.async_cancel()
|
self._debounced_reload.async_cancel()
|
||||||
@ -363,7 +368,7 @@ class ShellyBlockCoordinator(ShellyCoordinatorBase[BlockDevice]):
|
|||||||
if update_type is BlockUpdateType.ONLINE:
|
if update_type is BlockUpdateType.ONLINE:
|
||||||
self.entry.async_create_background_task(
|
self.entry.async_create_background_task(
|
||||||
self.hass,
|
self.hass,
|
||||||
self._async_device_connect(),
|
self._async_device_connect_task(),
|
||||||
"block device online",
|
"block device online",
|
||||||
eager_start=True,
|
eager_start=True,
|
||||||
)
|
)
|
||||||
@ -591,7 +596,8 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
|
|||||||
if self.device.connected:
|
if self.device.connected:
|
||||||
return
|
return
|
||||||
|
|
||||||
await self._async_device_connect()
|
if not await self._async_device_connect_task():
|
||||||
|
raise UpdateFailed("Device reconnect error")
|
||||||
|
|
||||||
async def _async_disconnected(self) -> None:
|
async def _async_disconnected(self) -> None:
|
||||||
"""Handle device disconnected."""
|
"""Handle device disconnected."""
|
||||||
@ -661,7 +667,7 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
|
|||||||
if update_type is RpcUpdateType.ONLINE:
|
if update_type is RpcUpdateType.ONLINE:
|
||||||
self.entry.async_create_background_task(
|
self.entry.async_create_background_task(
|
||||||
self.hass,
|
self.hass,
|
||||||
self._async_device_connect(),
|
self._async_device_connect_task(),
|
||||||
"rpc device online",
|
"rpc device online",
|
||||||
eager_start=True,
|
eager_start=True,
|
||||||
)
|
)
|
||||||
|
@ -24,10 +24,11 @@ from homeassistant.components.shelly.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
||||||
from homeassistant.const import ATTR_DEVICE_ID, STATE_ON, STATE_UNAVAILABLE
|
from homeassistant.const import ATTR_DEVICE_ID, STATE_ON, STATE_UNAVAILABLE
|
||||||
from homeassistant.core import Event, HomeAssistant
|
from homeassistant.core import Event, HomeAssistant, State
|
||||||
from homeassistant.helpers import issue_registry as ir
|
from homeassistant.helpers import issue_registry as ir
|
||||||
from homeassistant.helpers.device_registry import (
|
from homeassistant.helpers.device_registry import (
|
||||||
CONNECTION_NETWORK_MAC,
|
CONNECTION_NETWORK_MAC,
|
||||||
|
DeviceRegistry,
|
||||||
async_entries_for_config_entry,
|
async_entries_for_config_entry,
|
||||||
async_get as async_get_dev_reg,
|
async_get as async_get_dev_reg,
|
||||||
format_mac,
|
format_mac,
|
||||||
@ -40,10 +41,11 @@ from . import (
|
|||||||
inject_rpc_device_event,
|
inject_rpc_device_event,
|
||||||
mock_polling_rpc_update,
|
mock_polling_rpc_update,
|
||||||
mock_rest_update,
|
mock_rest_update,
|
||||||
|
register_device,
|
||||||
register_entity,
|
register_entity,
|
||||||
)
|
)
|
||||||
|
|
||||||
from tests.common import async_fire_time_changed
|
from tests.common import async_fire_time_changed, mock_restore_cache
|
||||||
|
|
||||||
RELAY_BLOCK_ID = 0
|
RELAY_BLOCK_ID = 0
|
||||||
LIGHT_BLOCK_ID = 2
|
LIGHT_BLOCK_ID = 2
|
||||||
@ -806,3 +808,93 @@ async def test_rpc_runs_connected_events_when_initialized(
|
|||||||
|
|
||||||
# BLE script list is called during connected events
|
# BLE script list is called during connected events
|
||||||
assert call.script_list() in mock_rpc_device.mock_calls
|
assert call.script_list() in mock_rpc_device.mock_calls
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_sleeping_device_connection_error(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
mock_block_device: Mock,
|
||||||
|
device_reg: DeviceRegistry,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
) -> None:
|
||||||
|
"""Test block sleeping device connection error during initialize."""
|
||||||
|
sleep_period = 1000
|
||||||
|
entry = await init_integration(hass, 1, sleep_period=sleep_period, skip_setup=True)
|
||||||
|
register_device(device_reg, entry)
|
||||||
|
entity_id = register_entity(
|
||||||
|
hass, BINARY_SENSOR_DOMAIN, "test_name_motion", "sensor_0-motion", entry
|
||||||
|
)
|
||||||
|
mock_restore_cache(hass, [State(entity_id, STATE_ON)])
|
||||||
|
monkeypatch.setattr(mock_block_device, "initialized", False)
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert get_entity_state(hass, entity_id) == STATE_ON
|
||||||
|
|
||||||
|
# Make device online event with connection error
|
||||||
|
monkeypatch.setattr(
|
||||||
|
mock_block_device,
|
||||||
|
"initialize",
|
||||||
|
AsyncMock(
|
||||||
|
side_effect=DeviceConnectionError,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
mock_block_device.mock_online()
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
|
assert "Error connecting to Shelly device" in caplog.text
|
||||||
|
assert get_entity_state(hass, entity_id) == STATE_ON
|
||||||
|
|
||||||
|
# Move time to generate sleep period update
|
||||||
|
freezer.tick(timedelta(seconds=sleep_period * SLEEP_PERIOD_MULTIPLIER))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
|
assert "Sleeping device did not update" in caplog.text
|
||||||
|
assert get_entity_state(hass, entity_id) == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_sleeping_device_connection_error(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
mock_rpc_device: Mock,
|
||||||
|
device_reg: DeviceRegistry,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
) -> None:
|
||||||
|
"""Test RPC sleeping device connection error during initialize."""
|
||||||
|
sleep_period = 1000
|
||||||
|
entry = await init_integration(hass, 2, sleep_period=1000, skip_setup=True)
|
||||||
|
register_device(device_reg, entry)
|
||||||
|
entity_id = register_entity(
|
||||||
|
hass, BINARY_SENSOR_DOMAIN, "test_name_cloud", "cloud-cloud", entry
|
||||||
|
)
|
||||||
|
mock_restore_cache(hass, [State(entity_id, STATE_ON)])
|
||||||
|
monkeypatch.setattr(mock_rpc_device, "initialized", False)
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert get_entity_state(hass, entity_id) == STATE_ON
|
||||||
|
|
||||||
|
# Make device online event with connection error
|
||||||
|
monkeypatch.setattr(
|
||||||
|
mock_rpc_device,
|
||||||
|
"initialize",
|
||||||
|
AsyncMock(
|
||||||
|
side_effect=DeviceConnectionError,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
mock_rpc_device.mock_online()
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
|
assert "Error connecting to Shelly device" in caplog.text
|
||||||
|
assert get_entity_state(hass, entity_id) == STATE_ON
|
||||||
|
|
||||||
|
# Move time to generate sleep period update
|
||||||
|
freezer.tick(timedelta(seconds=sleep_period * SLEEP_PERIOD_MULTIPLIER))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
|
assert "Sleeping device did not update" in caplog.text
|
||||||
|
assert get_entity_state(hass, entity_id) == STATE_UNAVAILABLE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user