diff --git a/homeassistant/components/heos/__init__.py b/homeassistant/components/heos/__init__.py index dadd9f10464..ffbd8ebffd4 100644 --- a/homeassistant/components/heos/__init__.py +++ b/homeassistant/components/heos/__init__.py @@ -19,7 +19,7 @@ from .const import ( COMMAND_RETRY_ATTEMPTS, COMMAND_RETRY_DELAY, DATA_CONTROLLER, DATA_SOURCE_MANAGER, DOMAIN, SIGNAL_HEOS_SOURCES_UPDATED) -REQUIREMENTS = ['pyheos==0.3.0'] +REQUIREMENTS = ['pyheos==0.3.1'] CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ diff --git a/homeassistant/components/heos/config_flow.py b/homeassistant/components/heos/config_flow.py index 7ccb43c60e9..66650531cad 100644 --- a/homeassistant/components/heos/config_flow.py +++ b/homeassistant/components/heos/config_flow.py @@ -23,8 +23,13 @@ class HeosFlowHandler(config_entries.ConfigFlow): async def async_step_discovery(self, discovery_info): """Handle a discovered Heos device.""" - return await self.async_step_user( - {CONF_HOST: discovery_info[CONF_HOST]}) + # Only continue if this is the only active flow + flows = self.hass.config_entries.flow.async_progress() + heos_flows = [flow for flow in flows if flow['handler'] == DOMAIN] + if len(heos_flows) == 1: + return await self.async_step_user( + {CONF_HOST: discovery_info[CONF_HOST]}) + return self.async_abort(reason='already_setup') async def async_step_import(self, user_input=None): """Occurs when an entry is setup through config.""" diff --git a/homeassistant/components/heos/manifest.json b/homeassistant/components/heos/manifest.json index 91cefed75f7..2977345f97d 100644 --- a/homeassistant/components/heos/manifest.json +++ b/homeassistant/components/heos/manifest.json @@ -3,7 +3,7 @@ "name": "Heos", "documentation": "https://www.home-assistant.io/components/heos", "requirements": [ - "pyheos==0.3.0" + "pyheos==0.3.1" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index e61530ce77d..b64079b4460 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1064,7 +1064,7 @@ pygtt==1.1.2 pyhaversion==2.0.3 # homeassistant.components.heos -pyheos==0.3.0 +pyheos==0.3.1 # homeassistant.components.hikvision pyhik==0.2.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e2935369d92..6e70c636314 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -204,7 +204,7 @@ pydeconz==54 pydispatcher==2.0.5 # homeassistant.components.heos -pyheos==0.3.0 +pyheos==0.3.1 # homeassistant.components.homematic pyhomematic==0.1.58 diff --git a/tests/components/heos/conftest.py b/tests/components/heos/conftest.py index 1b76db21187..db675a24ee0 100644 --- a/tests/components/heos/conftest.py +++ b/tests/components/heos/conftest.py @@ -103,3 +103,21 @@ def input_sources_fixture() -> Sequence[InputSource]: def dispatcher_fixture() -> Dispatcher: """Create a dispatcher for testing.""" return Dispatcher() + + +@pytest.fixture(name="discovery_data") +def discovery_data_fixture() -> dict: + """Return mock discovery data for testing.""" + return { + 'host': '127.0.0.1', + 'manufacturer': 'Denon', + 'model_name': 'HEOS Drive', + 'model_number': 'DWSA-10 4.0', + 'name': 'Office', + 'port': 60006, + 'serial': None, + 'ssdp_description': + 'http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml', + 'udn': 'uuid:e61de70c-2250-1c22-0080-0005cdf512be', + 'upnp_device_type': 'urn:schemas-denon-com:device:AiosDevice:1' + } diff --git a/tests/components/heos/test_config_flow.py b/tests/components/heos/test_config_flow.py index ddb2bd39384..9c33cbee7aa 100644 --- a/tests/components/heos/test_config_flow.py +++ b/tests/components/heos/test_config_flow.py @@ -3,6 +3,7 @@ import asyncio from homeassistant import data_entry_flow from homeassistant.components.heos.config_flow import HeosFlowHandler +from homeassistant.components.heos.const import DOMAIN from homeassistant.const import CONF_HOST @@ -57,26 +58,41 @@ async def test_create_entry_when_host_valid(hass, controller): assert controller.disconnect.call_count == 1 -async def test_create_entry_with_discovery(hass, controller): - """Test result type is create entry when valid through discovery.""" - flow = HeosFlowHandler() - flow.hass = hass - data = { - 'host': '127.0.0.1', - 'manufacturer': 'Denon', - 'model_name': 'HEOS Drive', - 'model_number': 'DWSA-10 4.0', - 'name': 'Office', - 'port': 60006, - 'serial': None, - 'ssdp_description': - 'http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml', - 'udn': 'uuid:e61de70c-2250-1c22-0080-0005cdf512be', - 'upnp_device_type': 'urn:schemas-denon-com:device:AiosDevice:1' - } - result = await flow.async_step_discovery(data) - assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result['title'] == 'Controller (127.0.0.1)' - assert result['data'] == {'host': '127.0.0.1'} - assert controller.connect.call_count == 1 - assert controller.disconnect.call_count == 1 +async def test_create_entry_with_discovery(hass, controller, discovery_data): + """Test discovery creates entry.""" + await hass.config_entries.flow.async_init( + DOMAIN, context={'source': 'discovery'}, + data=discovery_data) + await hass.async_block_till_done() + entries = hass.config_entries.async_entries(DOMAIN) + assert len(entries) == 1 + assert entries[0].data == {CONF_HOST: discovery_data[CONF_HOST]} + assert entries[0].title == 'Controller (127.0.0.1)' + + +async def test_entry_already_exists_discovery( + hass, controller, discovery_data, config_entry): + """Test discovery does not create multiple entries when already setup.""" + config_entry.add_to_hass(hass) + await hass.config_entries.flow.async_init( + DOMAIN, context={'source': 'discovery'}, + data=discovery_data) + await hass.async_block_till_done() + entries = hass.config_entries.async_entries(DOMAIN) + assert len(entries) == 1 + + +async def test_multiple_discovery_creates_single_entry( + hass, controller, discovery_data): + """Test discovery of multiple devices creates a single entry.""" + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={'source': 'discovery'}, + data={CONF_HOST: discovery_data})) + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={'source': 'discovery'}, + data={CONF_HOST: discovery_data})) + await hass.async_block_till_done() + entries = hass.config_entries.async_entries(DOMAIN) + assert len(entries) == 1