Skip to content

Commit

Permalink
Reload ZHA only a single time when the connection is lost multiple ti…
Browse files Browse the repository at this point in the history
…mes (#107963)

* Reload only a single time when the connection is lost multiple times

* Ignore when reset task finishes, allow only one reset per `ZHAGateway`
  • Loading branch information
puddly authored Jan 13, 2024
1 parent 6ada825 commit b0adaec
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
15 changes: 13 additions & 2 deletions homeassistant/components/zha/core/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ def __init__(
self._log_relay_handler = LogRelayHandler(hass, self)
self.config_entry = config_entry
self._unsubs: list[Callable[[], None]] = []

self.shutting_down = False
self._reload_task: asyncio.Task | None = None

def get_application_controller_data(self) -> tuple[ControllerApplication, dict]:
"""Get an uninitialized instance of a zigpy `ControllerApplication`."""
Expand Down Expand Up @@ -231,12 +233,17 @@ async def async_initialize(self) -> None:

def connection_lost(self, exc: Exception) -> None:
"""Handle connection lost event."""
_LOGGER.debug("Connection to the radio was lost: %r", exc)

if self.shutting_down:
return

_LOGGER.debug("Connection to the radio was lost: %r", exc)
# Ensure we do not queue up multiple resets
if self._reload_task is not None:
_LOGGER.debug("Ignoring reset, one is already running")
return

self.hass.async_create_task(
self._reload_task = self.hass.async_create_task(
self.hass.config_entries.async_reload(self.config_entry.entry_id)
)

Expand Down Expand Up @@ -760,6 +767,10 @@ async def async_remove_zigpy_group(self, group_id: int) -> None:

async def shutdown(self) -> None:
"""Stop ZHA Controller Application."""
if self.shutting_down:
_LOGGER.debug("Ignoring duplicate shutdown event")
return

_LOGGER.debug("Shutting down ZHA ControllerApplication")
self.shutting_down = True

Expand Down
30 changes: 30 additions & 0 deletions tests/components/zha/test_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,33 @@ async def test_gateway_force_multi_pan_channel(

_, config = zha_gateway.get_application_controller_data()
assert config["network"]["channel"] == expected_channel


async def test_single_reload_on_multiple_connection_loss(
hass: HomeAssistant,
zigpy_app_controller: ControllerApplication,
config_entry: MockConfigEntry,
):
"""Test that we only reload once when we lose the connection multiple times."""
config_entry.add_to_hass(hass)

zha_gateway = ZHAGateway(hass, {}, config_entry)

with patch(
"bellows.zigbee.application.ControllerApplication.new",
return_value=zigpy_app_controller,
):
await zha_gateway.async_initialize()

with patch.object(
hass.config_entries, "async_reload", wraps=hass.config_entries.async_reload
) as mock_reload:
zha_gateway.connection_lost(RuntimeError())
zha_gateway.connection_lost(RuntimeError())
zha_gateway.connection_lost(RuntimeError())
zha_gateway.connection_lost(RuntimeError())
zha_gateway.connection_lost(RuntimeError())

assert len(mock_reload.mock_calls) == 1

await hass.async_block_till_done()

0 comments on commit b0adaec

Please sign in to comment.