Switcher - use single_config_entry and register_discovery_flow in con… (#118000)

This commit is contained in:
Shay Levy 2024-05-24 10:15:17 +03:00 committed by GitHub
parent ad90ecef3f
commit cb59eb183d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 48 additions and 94 deletions

View File

@ -10,7 +10,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
from homeassistant.core import Event, HomeAssistant, callback from homeassistant.core import Event, HomeAssistant, callback
from .const import DATA_DEVICE, DATA_DISCOVERY, DOMAIN from .const import DATA_DEVICE, DOMAIN
from .coordinator import SwitcherDataUpdateCoordinator from .coordinator import SwitcherDataUpdateCoordinator
from .utils import async_start_bridge, async_stop_bridge from .utils import async_start_bridge, async_stop_bridge
@ -60,12 +60,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# Must be ready before dispatcher is called # Must be ready before dispatcher is called
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
discovery_task = hass.data[DOMAIN].pop(DATA_DISCOVERY, None)
if discovery_task is not None:
discovered_devices = await discovery_task
for device in discovered_devices.values():
on_device_data_callback(device)
await async_start_bridge(hass, on_device_data_callback) await async_start_bridge(hass, on_device_data_callback)
async def stop_bridge(event: Event) -> None: async def stop_bridge(event: Event) -> None:

View File

@ -2,40 +2,9 @@
from __future__ import annotations from __future__ import annotations
from typing import Any from homeassistant.helpers import config_entry_flow
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from .const import DOMAIN
from .utils import async_has_devices
from .const import DATA_DISCOVERY, DOMAIN config_entry_flow.register_discovery_flow(DOMAIN, "Switcher", async_has_devices)
from .utils import async_discover_devices
class SwitcherFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle Switcher config flow."""
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the start of the config flow."""
if self._async_current_entries(True):
return self.async_abort(reason="single_instance_allowed")
self.hass.data.setdefault(DOMAIN, {})
if DATA_DISCOVERY not in self.hass.data[DOMAIN]:
self.hass.data[DOMAIN][DATA_DISCOVERY] = self.hass.async_create_task(
async_discover_devices()
)
return self.async_show_form(step_id="confirm")
async def async_step_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle user-confirmation of the config flow."""
discovered_devices = await self.hass.data[DOMAIN][DATA_DISCOVERY]
if len(discovered_devices) == 0:
self.hass.data[DOMAIN].pop(DATA_DISCOVERY)
return self.async_abort(reason="no_devices_found")
return self.async_create_entry(title="Switcher", data={})

View File

@ -4,7 +4,6 @@ DOMAIN = "switcher_kis"
DATA_BRIDGE = "bridge" DATA_BRIDGE = "bridge"
DATA_DEVICE = "device" DATA_DEVICE = "device"
DATA_DISCOVERY = "discovery"
DISCOVERY_TIME_SEC = 12 DISCOVERY_TIME_SEC = 12

View File

@ -7,5 +7,6 @@
"iot_class": "local_push", "iot_class": "local_push",
"loggers": ["aioswitcher"], "loggers": ["aioswitcher"],
"quality_scale": "platinum", "quality_scale": "platinum",
"requirements": ["aioswitcher==3.4.1"] "requirements": ["aioswitcher==3.4.1"],
"single_config_entry": true
} }

View File

@ -36,7 +36,7 @@ async def async_stop_bridge(hass: HomeAssistant) -> None:
hass.data[DOMAIN].pop(DATA_BRIDGE) hass.data[DOMAIN].pop(DATA_BRIDGE)
async def async_discover_devices() -> dict[str, SwitcherBase]: async def async_has_devices(hass: HomeAssistant) -> bool:
"""Discover Switcher devices.""" """Discover Switcher devices."""
_LOGGER.debug("Starting discovery") _LOGGER.debug("Starting discovery")
discovered_devices = {} discovered_devices = {}
@ -55,7 +55,7 @@ async def async_discover_devices() -> dict[str, SwitcherBase]:
await bridge.stop() await bridge.stop()
_LOGGER.debug("Finished discovery, discovered devices: %s", len(discovered_devices)) _LOGGER.debug("Finished discovery, discovered devices: %s", len(discovered_devices))
return discovered_devices return len(discovered_devices) > 0
@singleton.singleton("switcher_breeze_remote_manager") @singleton.singleton("switcher_breeze_remote_manager")

View File

@ -5894,7 +5894,8 @@
"name": "Switcher", "name": "Switcher",
"integration_type": "hub", "integration_type": "hub",
"config_flow": true, "config_flow": true,
"iot_class": "local_push" "iot_class": "local_push",
"single_config_entry": true
}, },
"switchmate": { "switchmate": {
"name": "Switchmate SimplySmart Home", "name": "Switchmate SimplySmart Home",

View File

@ -1,10 +1,20 @@
"""Common fixtures and objects for the Switcher integration tests.""" """Common fixtures and objects for the Switcher integration tests."""
from collections.abc import Generator
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, Mock, patch
import pytest import pytest
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.switcher_kis.async_setup_entry", return_value=True
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture @pytest.fixture
def mock_bridge(request): def mock_bridge(request):
"""Return a mocked SwitcherBridge.""" """Return a mocked SwitcherBridge."""

View File

@ -1,11 +1,11 @@
"""Test the Switcher config flow.""" """Test the Switcher config flow."""
from unittest.mock import patch from unittest.mock import AsyncMock, patch
import pytest import pytest
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.switcher_kis.const import DATA_DISCOVERY, DOMAIN from homeassistant.components.switcher_kis.const import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
@ -26,52 +26,51 @@ from tests.common import MockConfigEntry
], ],
indirect=True, indirect=True,
) )
async def test_user_setup(hass: HomeAssistant, mock_bridge) -> None: async def test_user_setup(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_bridge
) -> None:
"""Test we can finish a config flow.""" """Test we can finish a config flow."""
with patch("homeassistant.components.switcher_kis.utils.DISCOVERY_TIME_SEC", 0): with patch("homeassistant.components.switcher_kis.utils.DISCOVERY_TIME_SEC", 0):
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": config_entries.SOURCE_USER}
) )
await hass.async_block_till_done()
assert mock_bridge.is_running is False assert result["type"] is FlowResultType.FORM
assert len(hass.data[DOMAIN][DATA_DISCOVERY].result()) == 2 assert result["step_id"] == "confirm"
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "confirm"
assert result["errors"] is None
with patch(
"homeassistant.components.switcher_kis.async_setup_entry", return_value=True
):
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {}) result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result2["type"] is FlowResultType.CREATE_ENTRY assert mock_bridge.is_running is False
assert result2["title"] == "Switcher" assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["result"].data == {} assert result2["title"] == "Switcher"
assert result2["result"].data == {}
await hass.async_block_till_done()
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_setup_abort_no_devices_found( async def test_user_setup_abort_no_devices_found(
hass: HomeAssistant, mock_bridge hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_bridge
) -> None: ) -> None:
"""Test we abort a config flow if no devices found.""" """Test we abort a config flow if no devices found."""
with patch("homeassistant.components.switcher_kis.utils.DISCOVERY_TIME_SEC", 0): with patch("homeassistant.components.switcher_kis.utils.DISCOVERY_TIME_SEC", 0):
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": config_entries.SOURCE_USER}
) )
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "confirm"
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert mock_bridge.is_running is False
assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "no_devices_found"
await hass.async_block_till_done() await hass.async_block_till_done()
assert mock_bridge.is_running is False assert len(mock_setup_entry.mock_calls) == 0
assert len(hass.data[DOMAIN][DATA_DISCOVERY].result()) == 0
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "confirm"
assert result["errors"] is None
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "no_devices_found"
async def test_single_instance(hass: HomeAssistant) -> None: async def test_single_instance(hass: HomeAssistant) -> None:

View File

@ -1,11 +1,9 @@
"""Test cases for the switcher_kis component.""" """Test cases for the switcher_kis component."""
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch
import pytest import pytest
from homeassistant import config_entries
from homeassistant.components.switcher_kis.const import ( from homeassistant.components.switcher_kis.const import (
DATA_DEVICE, DATA_DEVICE,
DOMAIN, DOMAIN,
@ -22,23 +20,6 @@ from .consts import DUMMY_SWITCHER_DEVICES
from tests.common import async_fire_time_changed from tests.common import async_fire_time_changed
@pytest.mark.parametrize("mock_bridge", [DUMMY_SWITCHER_DEVICES], indirect=True)
async def test_async_setup_user_config_flow(hass: HomeAssistant, mock_bridge) -> None:
"""Test setup started by user config flow."""
with patch("homeassistant.components.switcher_kis.utils.DISCOVERY_TIME_SEC", 0):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
await hass.async_block_till_done()
await hass.config_entries.flow.async_configure(result["flow_id"], {})
await hass.async_block_till_done()
assert mock_bridge.is_running is True
assert len(hass.data[DOMAIN]) == 2
assert len(hass.data[DOMAIN][DATA_DEVICE]) == 2
async def test_update_fail( async def test_update_fail(
hass: HomeAssistant, mock_bridge, caplog: pytest.LogCaptureFixture hass: HomeAssistant, mock_bridge, caplog: pytest.LogCaptureFixture
) -> None: ) -> None: