From d8850758f143eb696bcc26432677be218f8166b7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 26 Feb 2023 20:08:20 -0600 Subject: [PATCH] Fix unifiprotect discovery running at shutdown (#88802) * Fix unifiprotect discovery running at shutdown Move the discovery start into `async_setup` so we only start discovery once reguardless of how many config entries for unifiprotect they have (or how many times they reload). Always make discovery a background task so it does not get to block shutdown * missing decorator --- .../components/unifiprotect/__init__.py | 10 ++++-- .../components/unifiprotect/discovery.py | 14 +++++--- .../unifiprotect/test_config_flow.py | 36 +++++++++++++++---- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/unifiprotect/__init__.py b/homeassistant/components/unifiprotect/__init__.py index 4e659d39cc5..96d31872d0b 100644 --- a/homeassistant/components/unifiprotect/__init__.py +++ b/homeassistant/components/unifiprotect/__init__.py @@ -14,6 +14,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers import device_registry as dr, issue_registry as ir from homeassistant.helpers.issue_registry import IssueSeverity +from homeassistant.helpers.typing import ConfigType from .const import ( CONF_ALLOW_EA, @@ -40,10 +41,15 @@ _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=DEFAULT_SCAN_INTERVAL) +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: + """Set up the UniFi Protect.""" + # Only start discovery once regardless of how many entries they have + async_start_discovery(hass) + return True + + async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up the UniFi Protect config entries.""" - - async_start_discovery(hass) protect = async_create_api_client(hass, entry) _LOGGER.debug("Connect to UniFi Protect") data_service = ProtectData(hass, protect, SCAN_INTERVAL, entry) diff --git a/homeassistant/components/unifiprotect/discovery.py b/homeassistant/components/unifiprotect/discovery.py index 1828687c0dd..ea3730fa3e3 100644 --- a/homeassistant/components/unifiprotect/discovery.py +++ b/homeassistant/components/unifiprotect/discovery.py @@ -29,13 +29,19 @@ def async_start_discovery(hass: HomeAssistant) -> None: return domain_data[DISCOVERY] = True - async def _async_discovery(*_: Any) -> None: + async def _async_discovery() -> None: async_trigger_discovery(hass, await async_discover_devices()) - # Do not block startup since discovery takes 31s or more - hass.async_create_background_task(_async_discovery(), "unifiprotect-discovery") + @callback + def _async_start_background_discovery(*_: Any) -> None: + """Run discovery in the background.""" + hass.async_create_background_task(_async_discovery(), "unifiprotect-discovery") - async_track_time_interval(hass, _async_discovery, DISCOVERY_INTERVAL) + # Do not block startup since discovery takes 31s or more + _async_start_background_discovery() + async_track_time_interval( + hass, _async_start_background_discovery, DISCOVERY_INTERVAL + ) async def async_discover_devices() -> list[UnifiDevice]: diff --git a/tests/components/unifiprotect/test_config_flow.py b/tests/components/unifiprotect/test_config_flow.py index 1c348fc0086..854109bee6d 100644 --- a/tests/components/unifiprotect/test_config_flow.py +++ b/tests/components/unifiprotect/test_config_flow.py @@ -71,7 +71,10 @@ async def test_form(hass: HomeAssistant, nvr: NVR) -> None: ), patch( "homeassistant.components.unifiprotect.async_setup_entry", return_value=True, - ) as mock_setup_entry: + ) as mock_setup_entry, patch( + "homeassistant.components.unifiprotect.async_setup", + return_value=True, + ) as mock_setup: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -93,6 +96,7 @@ async def test_form(hass: HomeAssistant, nvr: NVR) -> None: "verify_ssl": False, } assert len(mock_setup_entry.mock_calls) == 1 + assert len(mock_setup.mock_calls) == 1 async def test_form_version_too_old(hass: HomeAssistant, old_nvr: NVR) -> None: @@ -214,7 +218,10 @@ async def test_form_reauth_auth(hass: HomeAssistant, nvr: NVR) -> None: with patch( "homeassistant.components.unifiprotect.config_flow.ProtectApiClient.get_nvr", return_value=nvr, - ): + ), patch( + "homeassistant.components.unifiprotect.async_setup", + return_value=True, + ) as mock_setup: result3 = await hass.config_entries.flow.async_configure( result2["flow_id"], { @@ -225,6 +232,7 @@ async def test_form_reauth_auth(hass: HomeAssistant, nvr: NVR) -> None: assert result3["type"] == FlowResultType.ABORT assert result3["reason"] == "reauth_successful" + assert len(mock_setup.mock_calls) == 1 async def test_form_options(hass: HomeAssistant, ufp_client: ProtectApiClient) -> None: @@ -332,7 +340,10 @@ async def test_discovered_by_unifi_discovery_direct_connect( ), patch( "homeassistant.components.unifiprotect.async_setup_entry", return_value=True, - ) as mock_setup_entry: + ) as mock_setup_entry, patch( + "homeassistant.components.unifiprotect.async_setup", + return_value=True, + ) as mock_setup: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -353,6 +364,7 @@ async def test_discovered_by_unifi_discovery_direct_connect( "verify_ssl": True, } assert len(mock_setup_entry.mock_calls) == 1 + assert len(mock_setup.mock_calls) == 1 async def test_discovered_by_unifi_discovery_direct_connect_updated( @@ -515,7 +527,10 @@ async def test_discovered_by_unifi_discovery(hass: HomeAssistant, nvr: NVR) -> N ), patch( "homeassistant.components.unifiprotect.async_setup_entry", return_value=True, - ) as mock_setup_entry: + ) as mock_setup_entry, patch( + "homeassistant.components.unifiprotect.async_setup", + return_value=True, + ) as mock_setup: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -536,6 +551,7 @@ async def test_discovered_by_unifi_discovery(hass: HomeAssistant, nvr: NVR) -> N "verify_ssl": False, } assert len(mock_setup_entry.mock_calls) == 1 + assert len(mock_setup.mock_calls) == 1 async def test_discovered_by_unifi_discovery_partial( @@ -567,7 +583,10 @@ async def test_discovered_by_unifi_discovery_partial( ), patch( "homeassistant.components.unifiprotect.async_setup_entry", return_value=True, - ) as mock_setup_entry: + ) as mock_setup_entry, patch( + "homeassistant.components.unifiprotect.async_setup", + return_value=True, + ) as mock_setup: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -588,6 +607,7 @@ async def test_discovered_by_unifi_discovery_partial( "verify_ssl": False, } assert len(mock_setup_entry.mock_calls) == 1 + assert len(mock_setup.mock_calls) == 1 async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface( @@ -736,7 +756,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa ), patch( "homeassistant.components.unifiprotect.async_setup_entry", return_value=True, - ) as mock_setup_entry: + ) as mock_setup_entry, patch( + "homeassistant.components.unifiprotect.async_setup", + return_value=True, + ) as mock_setup: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -757,6 +780,7 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa "verify_ssl": True, } assert len(mock_setup_entry.mock_calls) == 1 + assert len(mock_setup.mock_calls) == 1 async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_resolver_no_result(