mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 02:07:09 +00:00
Remove HEOS yaml import (#133082)
This commit is contained in:
parent
2cd4ebbfb2
commit
566843591e
@ -8,23 +8,19 @@ from datetime import timedelta
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pyheos import Heos, HeosError, HeosPlayer, const as heos_const
|
from pyheos import Heos, HeosError, HeosPlayer, const as heos_const
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP, Platform
|
from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP, Platform
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
from homeassistant.helpers.dispatcher import (
|
from homeassistant.helpers.dispatcher import (
|
||||||
async_dispatcher_connect,
|
async_dispatcher_connect,
|
||||||
async_dispatcher_send,
|
async_dispatcher_send,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.typing import ConfigType
|
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.util import Throttle
|
||||||
|
|
||||||
from . import services
|
from . import services
|
||||||
from .config_flow import format_title
|
|
||||||
from .const import (
|
from .const import (
|
||||||
COMMAND_RETRY_ATTEMPTS,
|
COMMAND_RETRY_ATTEMPTS,
|
||||||
COMMAND_RETRY_DELAY,
|
COMMAND_RETRY_DELAY,
|
||||||
@ -35,14 +31,6 @@ from .const import (
|
|||||||
|
|
||||||
PLATFORMS = [Platform.MEDIA_PLAYER]
|
PLATFORMS = [Platform.MEDIA_PLAYER]
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
|
||||||
vol.All(
|
|
||||||
cv.deprecated(DOMAIN),
|
|
||||||
{DOMAIN: vol.Schema({vol.Required(CONF_HOST): cv.string})},
|
|
||||||
),
|
|
||||||
extra=vol.ALLOW_EXTRA,
|
|
||||||
)
|
|
||||||
|
|
||||||
MIN_UPDATE_SOURCES = timedelta(seconds=1)
|
MIN_UPDATE_SOURCES = timedelta(seconds=1)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -61,30 +49,6 @@ class HeosRuntimeData:
|
|||||||
type HeosConfigEntry = ConfigEntry[HeosRuntimeData]
|
type HeosConfigEntry = ConfigEntry[HeosRuntimeData]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|
||||||
"""Set up the HEOS component."""
|
|
||||||
if DOMAIN not in config:
|
|
||||||
return True
|
|
||||||
host = config[DOMAIN][CONF_HOST]
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
if not entries:
|
|
||||||
# Create new entry based on config
|
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": SOURCE_IMPORT}, data={CONF_HOST: host}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# Check if host needs to be updated
|
|
||||||
entry = entries[0]
|
|
||||||
if entry.data[CONF_HOST] != host:
|
|
||||||
hass.config_entries.async_update_entry(
|
|
||||||
entry, title=format_title(host), data={**entry.data, CONF_HOST: host}
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool:
|
||||||
"""Initialize config entry which represents the HEOS controller."""
|
"""Initialize config entry which represents the HEOS controller."""
|
||||||
# For backwards compat
|
# For backwards compat
|
||||||
|
@ -10,7 +10,7 @@ from homeassistant.components import ssdp
|
|||||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST
|
||||||
|
|
||||||
from .const import DATA_DISCOVERED_HOSTS, DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
def format_title(host: str) -> str:
|
def format_title(host: str) -> str:
|
||||||
@ -34,43 +34,32 @@ class HeosFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
friendly_name = (
|
friendly_name = (
|
||||||
f"{discovery_info.upnp[ssdp.ATTR_UPNP_FRIENDLY_NAME]} ({hostname})"
|
f"{discovery_info.upnp[ssdp.ATTR_UPNP_FRIENDLY_NAME]} ({hostname})"
|
||||||
)
|
)
|
||||||
self.hass.data.setdefault(DATA_DISCOVERED_HOSTS, {})
|
self.hass.data.setdefault(DOMAIN, {})
|
||||||
self.hass.data[DATA_DISCOVERED_HOSTS][friendly_name] = hostname
|
self.hass.data[DOMAIN][friendly_name] = hostname
|
||||||
# Abort if other flows in progress or an entry already exists
|
|
||||||
if self._async_in_progress() or self._async_current_entries():
|
|
||||||
return self.async_abort(reason="single_instance_allowed")
|
|
||||||
await self.async_set_unique_id(DOMAIN)
|
await self.async_set_unique_id(DOMAIN)
|
||||||
# Show selection form
|
# Show selection form
|
||||||
return self.async_show_form(step_id="user")
|
return self.async_show_form(step_id="user")
|
||||||
|
|
||||||
async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
|
|
||||||
"""Occurs when an entry is setup through config."""
|
|
||||||
host = import_data[CONF_HOST]
|
|
||||||
# raise_on_progress is False here in case ssdp discovers
|
|
||||||
# heos first which would block the import
|
|
||||||
await self.async_set_unique_id(DOMAIN, raise_on_progress=False)
|
|
||||||
return self.async_create_entry(title=format_title(host), data={CONF_HOST: host})
|
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
"""Obtain host and validate connection."""
|
"""Obtain host and validate connection."""
|
||||||
self.hass.data.setdefault(DATA_DISCOVERED_HOSTS, {})
|
self.hass.data.setdefault(DOMAIN, {})
|
||||||
# Only a single entry is needed for all devices
|
await self.async_set_unique_id(DOMAIN)
|
||||||
if self._async_current_entries():
|
|
||||||
return self.async_abort(reason="single_instance_allowed")
|
|
||||||
# Try connecting to host if provided
|
# Try connecting to host if provided
|
||||||
errors = {}
|
errors = {}
|
||||||
host = None
|
host = None
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
host = user_input[CONF_HOST]
|
host = user_input[CONF_HOST]
|
||||||
# Map host from friendly name if in discovered hosts
|
# Map host from friendly name if in discovered hosts
|
||||||
host = self.hass.data[DATA_DISCOVERED_HOSTS].get(host, host)
|
host = self.hass.data[DOMAIN].get(host, host)
|
||||||
heos = Heos(host)
|
heos = Heos(host)
|
||||||
try:
|
try:
|
||||||
await heos.connect()
|
await heos.connect()
|
||||||
self.hass.data.pop(DATA_DISCOVERED_HOSTS)
|
self.hass.data.pop(DOMAIN)
|
||||||
return await self.async_step_import({CONF_HOST: host})
|
return self.async_create_entry(
|
||||||
|
title=format_title(host), data={CONF_HOST: host}
|
||||||
|
)
|
||||||
except HeosError:
|
except HeosError:
|
||||||
errors[CONF_HOST] = "cannot_connect"
|
errors[CONF_HOST] = "cannot_connect"
|
||||||
finally:
|
finally:
|
||||||
@ -78,9 +67,7 @@ class HeosFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
# Return form
|
# Return form
|
||||||
host_type = (
|
host_type = (
|
||||||
str
|
str if not self.hass.data[DOMAIN] else vol.In(list(self.hass.data[DOMAIN]))
|
||||||
if not self.hass.data[DATA_DISCOVERED_HOSTS]
|
|
||||||
else vol.In(list(self.hass.data[DATA_DISCOVERED_HOSTS]))
|
|
||||||
)
|
)
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user",
|
step_id="user",
|
||||||
|
@ -4,7 +4,6 @@ ATTR_PASSWORD = "password"
|
|||||||
ATTR_USERNAME = "username"
|
ATTR_USERNAME = "username"
|
||||||
COMMAND_RETRY_ATTEMPTS = 2
|
COMMAND_RETRY_ATTEMPTS = 2
|
||||||
COMMAND_RETRY_DELAY = 1
|
COMMAND_RETRY_DELAY = 1
|
||||||
DATA_DISCOVERED_HOSTS = "heos_discovered_hosts"
|
|
||||||
DOMAIN = "heos"
|
DOMAIN = "heos"
|
||||||
SERVICE_SIGN_IN = "sign_in"
|
SERVICE_SIGN_IN = "sign_in"
|
||||||
SERVICE_SIGN_OUT = "sign_out"
|
SERVICE_SIGN_OUT = "sign_out"
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["pyheos"],
|
"loggers": ["pyheos"],
|
||||||
"requirements": ["pyheos==0.7.2"],
|
"requirements": ["pyheos==0.7.2"],
|
||||||
|
"single_config_entry": true,
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
"st": "urn:schemas-denon-com:device:ACT-Denon:1"
|
"st": "urn:schemas-denon-com:device:ACT-Denon:1"
|
||||||
|
@ -8,19 +8,10 @@ rules:
|
|||||||
comment: Integration is a local push integration
|
comment: Integration is a local push integration
|
||||||
brands: done
|
brands: done
|
||||||
common-modules: todo
|
common-modules: todo
|
||||||
config-flow-test-coverage:
|
config-flow-test-coverage: done
|
||||||
status: todo
|
|
||||||
comment:
|
|
||||||
1. The config flow is 100% covered, however some tests need to let HA create the flow
|
|
||||||
handler instead of doing it manually in the test.
|
|
||||||
2. We should also make sure every test ends in either CREATE_ENTRY or ABORT so we test
|
|
||||||
that the flow is able to recover from an error.
|
|
||||||
config-flow:
|
config-flow:
|
||||||
status: todo
|
status: done
|
||||||
comment: |
|
comment: Consider enhnacement to automatically select a host when multiple are discovered.
|
||||||
1. YAML import to be removed after core team meeting discussion on approach.
|
|
||||||
2. Consider enhnacement to automatically select a host when multiple are discovered.
|
|
||||||
3. Move hass.data[heos_discovered_hosts] into hass.data[heos]
|
|
||||||
dependency-transparency: done
|
dependency-transparency: done
|
||||||
docs-actions: done
|
docs-actions: done
|
||||||
docs-high-level-description: done
|
docs-high-level-description: done
|
||||||
@ -34,15 +25,9 @@ rules:
|
|||||||
entity-unique-id: done
|
entity-unique-id: done
|
||||||
has-entity-name: done
|
has-entity-name: done
|
||||||
runtime-data: done
|
runtime-data: done
|
||||||
test-before-configure: todo
|
test-before-configure: done
|
||||||
test-before-setup: done
|
test-before-setup: done
|
||||||
unique-config-entry:
|
unique-config-entry: done
|
||||||
status: todo
|
|
||||||
comment: |
|
|
||||||
The HEOS integration only supports a single config entry, but needs to be migrated to use
|
|
||||||
the `single_config_entry` flag. HEOS devices interconnect to each other, so connecting to
|
|
||||||
a single node yields access to all the devices setup with HEOS on your network. The HEOS API
|
|
||||||
documentation does not recommend connecting to multiple nodes which would provide no bennefit.
|
|
||||||
# Silver
|
# Silver
|
||||||
action-exceptions:
|
action-exceptions:
|
||||||
status: todo
|
status: todo
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
|
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
||||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
|
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -164,6 +164,25 @@ def discovery_data_fixture() -> dict:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="discovery_data_bedroom")
|
||||||
|
def discovery_data_fixture_bedroom() -> dict:
|
||||||
|
"""Return mock discovery data for testing."""
|
||||||
|
return ssdp.SsdpServiceInfo(
|
||||||
|
ssdp_usn="mock_usn",
|
||||||
|
ssdp_st="mock_st",
|
||||||
|
ssdp_location="http://127.0.0.2:60006/upnp/desc/aios_device/aios_device.xml",
|
||||||
|
upnp={
|
||||||
|
ssdp.ATTR_UPNP_DEVICE_TYPE: "urn:schemas-denon-com:device:AiosDevice:1",
|
||||||
|
ssdp.ATTR_UPNP_FRIENDLY_NAME: "Bedroom",
|
||||||
|
ssdp.ATTR_UPNP_MANUFACTURER: "Denon",
|
||||||
|
ssdp.ATTR_UPNP_MODEL_NAME: "HEOS Drive",
|
||||||
|
ssdp.ATTR_UPNP_MODEL_NUMBER: "DWSA-10 4.0",
|
||||||
|
ssdp.ATTR_UPNP_SERIAL: None,
|
||||||
|
ssdp.ATTR_UPNP_UDN: "uuid:e61de70c-2250-1c22-0080-0005cdf512be",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="quick_selects")
|
@pytest.fixture(name="quick_selects")
|
||||||
def quick_selects_fixture() -> dict[int, str]:
|
def quick_selects_fixture() -> dict[int, str]:
|
||||||
"""Create a dict of quick selects for testing."""
|
"""Create a dict of quick selects for testing."""
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
"""Tests for the Heos config flow module."""
|
"""Tests for the Heos config flow module."""
|
||||||
|
|
||||||
from unittest.mock import patch
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
from pyheos import HeosError
|
from pyheos import HeosError
|
||||||
|
|
||||||
from homeassistant.components import heos, ssdp
|
from homeassistant.components import heos, ssdp
|
||||||
from homeassistant.components.heos.config_flow import HeosFlowHandler
|
from homeassistant.components.heos.const import DOMAIN
|
||||||
from homeassistant.components.heos.const import DATA_DISCOVERED_HOSTS, DOMAIN
|
from homeassistant.config_entries import SOURCE_SSDP, SOURCE_USER
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_SSDP, SOURCE_USER
|
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
@ -17,18 +13,20 @@ from homeassistant.data_entry_flow import FlowResultType
|
|||||||
async def test_flow_aborts_already_setup(hass: HomeAssistant, config_entry) -> None:
|
async def test_flow_aborts_already_setup(hass: HomeAssistant, config_entry) -> None:
|
||||||
"""Test flow aborts when entry already setup."""
|
"""Test flow aborts when entry already setup."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
flow = HeosFlowHandler()
|
|
||||||
flow.hass = hass
|
result = await hass.config_entries.flow.async_init(
|
||||||
result = await flow.async_step_user()
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.ABORT
|
assert result["type"] is FlowResultType.ABORT
|
||||||
assert result["reason"] == "single_instance_allowed"
|
assert result["reason"] == "single_instance_allowed"
|
||||||
|
|
||||||
|
|
||||||
async def test_no_host_shows_form(hass: HomeAssistant) -> None:
|
async def test_no_host_shows_form(hass: HomeAssistant) -> None:
|
||||||
"""Test form is shown when host not provided."""
|
"""Test form is shown when host not provided."""
|
||||||
flow = HeosFlowHandler()
|
result = await hass.config_entries.flow.async_init(
|
||||||
flow.hass = hass
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
result = await flow.async_step_user()
|
)
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
assert result["errors"] == {}
|
assert result["errors"] == {}
|
||||||
@ -45,14 +43,12 @@ async def test_cannot_connect_shows_error_form(hass: HomeAssistant, controller)
|
|||||||
assert result["errors"][CONF_HOST] == "cannot_connect"
|
assert result["errors"][CONF_HOST] == "cannot_connect"
|
||||||
assert controller.connect.call_count == 1
|
assert controller.connect.call_count == 1
|
||||||
assert controller.disconnect.call_count == 1
|
assert controller.disconnect.call_count == 1
|
||||||
controller.connect.reset_mock()
|
|
||||||
controller.disconnect.reset_mock()
|
|
||||||
|
|
||||||
|
|
||||||
async def test_create_entry_when_host_valid(hass: HomeAssistant, controller) -> None:
|
async def test_create_entry_when_host_valid(hass: HomeAssistant, controller) -> None:
|
||||||
"""Test result type is create entry when host is valid."""
|
"""Test result type is create entry when host is valid."""
|
||||||
data = {CONF_HOST: "127.0.0.1"}
|
data = {CONF_HOST: "127.0.0.1"}
|
||||||
with patch("homeassistant.components.heos.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
heos.DOMAIN, context={"source": SOURCE_USER}, data=data
|
heos.DOMAIN, context={"source": SOURCE_USER}, data=data
|
||||||
)
|
)
|
||||||
@ -60,7 +56,7 @@ async def test_create_entry_when_host_valid(hass: HomeAssistant, controller) ->
|
|||||||
assert result["result"].unique_id == DOMAIN
|
assert result["result"].unique_id == DOMAIN
|
||||||
assert result["title"] == "Controller (127.0.0.1)"
|
assert result["title"] == "Controller (127.0.0.1)"
|
||||||
assert result["data"] == data
|
assert result["data"] == data
|
||||||
assert controller.connect.call_count == 1
|
assert controller.connect.call_count == 2 # Also called in async_setup_entry
|
||||||
assert controller.disconnect.call_count == 1
|
assert controller.disconnect.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@ -68,50 +64,48 @@ async def test_create_entry_when_friendly_name_valid(
|
|||||||
hass: HomeAssistant, controller
|
hass: HomeAssistant, controller
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test result type is create entry when friendly name is valid."""
|
"""Test result type is create entry when friendly name is valid."""
|
||||||
hass.data[DATA_DISCOVERED_HOSTS] = {"Office (127.0.0.1)": "127.0.0.1"}
|
hass.data[DOMAIN] = {"Office (127.0.0.1)": "127.0.0.1"}
|
||||||
data = {CONF_HOST: "Office (127.0.0.1)"}
|
data = {CONF_HOST: "Office (127.0.0.1)"}
|
||||||
with patch("homeassistant.components.heos.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
heos.DOMAIN, context={"source": SOURCE_USER}, data=data
|
heos.DOMAIN, context={"source": SOURCE_USER}, data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
assert result["result"].unique_id == DOMAIN
|
assert result["result"].unique_id == DOMAIN
|
||||||
assert result["title"] == "Controller (127.0.0.1)"
|
assert result["title"] == "Controller (127.0.0.1)"
|
||||||
assert result["data"] == {CONF_HOST: "127.0.0.1"}
|
assert result["data"] == {CONF_HOST: "127.0.0.1"}
|
||||||
assert controller.connect.call_count == 1
|
assert controller.connect.call_count == 2 # Also called in async_setup_entry
|
||||||
assert controller.disconnect.call_count == 1
|
assert controller.disconnect.call_count == 1
|
||||||
assert DATA_DISCOVERED_HOSTS not in hass.data
|
assert DOMAIN not in hass.data
|
||||||
|
|
||||||
|
|
||||||
async def test_discovery_shows_create_form(
|
async def test_discovery_shows_create_form(
|
||||||
hass: HomeAssistant, controller, discovery_data: ssdp.SsdpServiceInfo
|
hass: HomeAssistant,
|
||||||
|
controller,
|
||||||
|
discovery_data: ssdp.SsdpServiceInfo,
|
||||||
|
discovery_data_bedroom: ssdp.SsdpServiceInfo,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test discovery shows form to confirm setup and subsequent abort."""
|
"""Test discovery shows form to confirm setup."""
|
||||||
|
|
||||||
await hass.config_entries.flow.async_init(
|
# Single discovered host shows form for user to finish setup.
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
heos.DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data
|
heos.DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
assert hass.data[DOMAIN] == {"Office (127.0.0.1)": "127.0.0.1"}
|
||||||
flows_in_progress = hass.config_entries.flow.async_progress()
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert flows_in_progress[0]["context"]["unique_id"] == DOMAIN
|
assert result["step_id"] == "user"
|
||||||
assert len(flows_in_progress) == 1
|
|
||||||
assert hass.data[DATA_DISCOVERED_HOSTS] == {"Office (127.0.0.1)": "127.0.0.1"}
|
|
||||||
|
|
||||||
port = urlparse(discovery_data.ssdp_location).port
|
# Subsequent discovered hosts append to discovered hosts and abort.
|
||||||
discovery_data.ssdp_location = f"http://127.0.0.2:{port}/"
|
result = await hass.config_entries.flow.async_init(
|
||||||
discovery_data.upnp[ssdp.ATTR_UPNP_FRIENDLY_NAME] = "Bedroom"
|
heos.DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data_bedroom
|
||||||
|
|
||||||
await hass.config_entries.flow.async_init(
|
|
||||||
heos.DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data
|
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
assert hass.data[DOMAIN] == {
|
||||||
flows_in_progress = hass.config_entries.flow.async_progress()
|
|
||||||
assert flows_in_progress[0]["context"]["unique_id"] == DOMAIN
|
|
||||||
assert len(flows_in_progress) == 1
|
|
||||||
assert hass.data[DATA_DISCOVERED_HOSTS] == {
|
|
||||||
"Office (127.0.0.1)": "127.0.0.1",
|
"Office (127.0.0.1)": "127.0.0.1",
|
||||||
"Bedroom (127.0.0.2)": "127.0.0.2",
|
"Bedroom (127.0.0.2)": "127.0.0.2",
|
||||||
}
|
}
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "already_in_progress"
|
||||||
|
|
||||||
|
|
||||||
async def test_discovery_flow_aborts_already_setup(
|
async def test_discovery_flow_aborts_already_setup(
|
||||||
@ -119,41 +113,10 @@ async def test_discovery_flow_aborts_already_setup(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test discovery flow aborts when entry already setup."""
|
"""Test discovery flow aborts when entry already setup."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
flow = HeosFlowHandler()
|
|
||||||
flow.hass = hass
|
result = await hass.config_entries.flow.async_init(
|
||||||
result = await flow.async_step_ssdp(discovery_data)
|
DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data
|
||||||
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.ABORT
|
assert result["type"] is FlowResultType.ABORT
|
||||||
assert result["reason"] == "single_instance_allowed"
|
assert result["reason"] == "single_instance_allowed"
|
||||||
|
|
||||||
|
|
||||||
async def test_discovery_sets_the_unique_id(
|
|
||||||
hass: HomeAssistant, controller, discovery_data: ssdp.SsdpServiceInfo
|
|
||||||
) -> None:
|
|
||||||
"""Test discovery sets the unique id."""
|
|
||||||
|
|
||||||
port = urlparse(discovery_data.ssdp_location).port
|
|
||||||
discovery_data.ssdp_location = f"http://127.0.0.2:{port}/"
|
|
||||||
discovery_data.upnp[ssdp.ATTR_UPNP_FRIENDLY_NAME] = "Bedroom"
|
|
||||||
|
|
||||||
await hass.config_entries.flow.async_init(
|
|
||||||
heos.DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
flows_in_progress = hass.config_entries.flow.async_progress()
|
|
||||||
assert flows_in_progress[0]["context"]["unique_id"] == DOMAIN
|
|
||||||
assert len(flows_in_progress) == 1
|
|
||||||
assert hass.data[DATA_DISCOVERED_HOSTS] == {"Bedroom (127.0.0.2)": "127.0.0.2"}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import_sets_the_unique_id(hass: HomeAssistant, controller) -> None:
|
|
||||||
"""Test import sets the unique id."""
|
|
||||||
|
|
||||||
with patch("homeassistant.components.heos.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
heos.DOMAIN,
|
|
||||||
context={"source": SOURCE_IMPORT},
|
|
||||||
data={CONF_HOST: "127.0.0.2"},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
||||||
assert result["result"].unique_id == DOMAIN
|
|
||||||
|
@ -13,40 +13,11 @@ from homeassistant.components.heos import (
|
|||||||
async_unload_entry,
|
async_unload_entry,
|
||||||
)
|
)
|
||||||
from homeassistant.components.heos.const import DOMAIN
|
from homeassistant.components.heos.const import DOMAIN
|
||||||
from homeassistant.const import CONF_HOST
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
|
||||||
async def test_async_setup_creates_entry(hass: HomeAssistant, config) -> None:
|
|
||||||
"""Test component setup creates entry from config."""
|
|
||||||
assert await async_setup_component(hass, DOMAIN, config)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
assert len(entries) == 1
|
|
||||||
entry = entries[0]
|
|
||||||
assert entry.title == "Controller (127.0.0.1)"
|
|
||||||
assert entry.data == {CONF_HOST: "127.0.0.1"}
|
|
||||||
assert entry.unique_id == DOMAIN
|
|
||||||
|
|
||||||
|
|
||||||
async def test_async_setup_updates_entry(
|
|
||||||
hass: HomeAssistant, config_entry, config, controller
|
|
||||||
) -> None:
|
|
||||||
"""Test component setup updates entry from config."""
|
|
||||||
config[DOMAIN][CONF_HOST] = "127.0.0.2"
|
|
||||||
config_entry.add_to_hass(hass)
|
|
||||||
assert await async_setup_component(hass, DOMAIN, config)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
assert len(entries) == 1
|
|
||||||
entry = entries[0]
|
|
||||||
assert entry.title == "Controller (127.0.0.2)"
|
|
||||||
assert entry.data == {CONF_HOST: "127.0.0.2"}
|
|
||||||
assert entry.unique_id == DOMAIN
|
|
||||||
|
|
||||||
|
|
||||||
async def test_async_setup_returns_true(
|
async def test_async_setup_returns_true(
|
||||||
hass: HomeAssistant, config_entry, config
|
hass: HomeAssistant, config_entry, config
|
||||||
) -> None:
|
) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user