mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 04:37:06 +00:00
Update HEOS host from discovery (#138950)
This commit is contained in:
parent
1d43cb3f29
commit
b73c6ed768
@ -102,6 +102,18 @@ async def _validate_auth(
|
||||
return True
|
||||
|
||||
|
||||
def _get_current_hosts(entry: HeosConfigEntry) -> set[str]:
|
||||
"""Get a set of current hosts from the entry."""
|
||||
hosts = set(entry.data[CONF_HOST])
|
||||
if hasattr(entry, "runtime_data"):
|
||||
hosts.update(
|
||||
player.ip_address
|
||||
for player in entry.runtime_data.heos.players.values()
|
||||
if player.ip_address is not None
|
||||
)
|
||||
return hosts
|
||||
|
||||
|
||||
class HeosFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Define a flow for HEOS."""
|
||||
|
||||
@ -125,10 +137,15 @@ class HeosFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
if TYPE_CHECKING:
|
||||
assert discovery_info.ssdp_location
|
||||
|
||||
await self.async_set_unique_id(DOMAIN)
|
||||
# Connect to discovered host and get system information
|
||||
entry: HeosConfigEntry | None = await self.async_set_unique_id(DOMAIN)
|
||||
hostname = urlparse(discovery_info.ssdp_location).hostname
|
||||
assert hostname is not None
|
||||
|
||||
# Abort early when discovered host is part of the current system
|
||||
if entry and hostname in _get_current_hosts(entry):
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
|
||||
# Connect to discovered host and get system information
|
||||
heos = Heos(HeosOptions(hostname, events=False, heart_beat=False))
|
||||
try:
|
||||
await heos.connect()
|
||||
@ -146,8 +163,23 @@ class HeosFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
# Select the preferred host, if available
|
||||
if system_info.preferred_hosts:
|
||||
hostname = system_info.preferred_hosts[0].ip_address
|
||||
self._discovered_host = hostname
|
||||
return await self.async_step_confirm_discovery()
|
||||
|
||||
# Move to confirmation when not configured
|
||||
if entry is None:
|
||||
self._discovered_host = hostname
|
||||
return await self.async_step_confirm_discovery()
|
||||
|
||||
# Only update if the configured host isn't part of the discovered hosts to ensure new players that come online don't trigger a reload
|
||||
if entry.data[CONF_HOST] not in [host.ip_address for host in system_info.hosts]:
|
||||
_LOGGER.debug(
|
||||
"Updated host %s to discovered host %s", entry.data[CONF_HOST], hostname
|
||||
)
|
||||
return self.async_update_reload_and_abort(
|
||||
entry,
|
||||
data_updates={CONF_HOST: hostname},
|
||||
reason="reconfigure_successful",
|
||||
)
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
|
||||
async def async_step_confirm_discovery(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
@ -167,6 +199,7 @@ class HeosFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
) -> ConfigFlowResult:
|
||||
"""Obtain host and validate connection."""
|
||||
await self.async_set_unique_id(DOMAIN)
|
||||
self._abort_if_unique_id_configured(error="single_instance_allowed")
|
||||
# Try connecting to host if provided
|
||||
errors: dict[str, str] = {}
|
||||
host = None
|
||||
|
@ -9,7 +9,6 @@
|
||||
"loggers": ["pyheos"],
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["pyheos==1.0.2"],
|
||||
"single_config_entry": true,
|
||||
"ssdp": [
|
||||
{
|
||||
"st": "urn:schemas-denon-com:device:ACT-Denon:1"
|
||||
|
@ -38,9 +38,7 @@ rules:
|
||||
# Gold
|
||||
devices: done
|
||||
diagnostics: done
|
||||
discovery-update-info:
|
||||
status: todo
|
||||
comment: Explore if this is possible.
|
||||
discovery-update-info: done
|
||||
discovery: done
|
||||
docs-data-update: done
|
||||
docs-examples: done
|
||||
|
@ -7,7 +7,9 @@ from pyheos import (
|
||||
CommandFailedError,
|
||||
ConnectionState,
|
||||
HeosError,
|
||||
HeosHost,
|
||||
HeosSystem,
|
||||
NetworkType,
|
||||
)
|
||||
import pytest
|
||||
|
||||
@ -118,17 +120,44 @@ async def test_discovery(
|
||||
|
||||
|
||||
async def test_discovery_flow_aborts_already_setup(
|
||||
hass: HomeAssistant, discovery_data: SsdpServiceInfo, config_entry: MockConfigEntry
|
||||
hass: HomeAssistant,
|
||||
discovery_data_bedroom: SsdpServiceInfo,
|
||||
config_entry: MockConfigEntry,
|
||||
controller: MockHeos,
|
||||
) -> None:
|
||||
"""Test discovery flow aborts when entry already setup."""
|
||||
"""Test discovery flow aborts when entry already setup and hosts didn't change."""
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
assert config_entry.data[CONF_HOST] == "127.0.0.1"
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data
|
||||
DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data_bedroom
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "single_instance_allowed"
|
||||
assert controller.get_system_info.call_count == 0
|
||||
assert config_entry.data[CONF_HOST] == "127.0.0.1"
|
||||
|
||||
|
||||
async def test_discovery_aborts_same_system(
|
||||
hass: HomeAssistant,
|
||||
discovery_data_bedroom: SsdpServiceInfo,
|
||||
controller: MockHeos,
|
||||
config_entry: MockConfigEntry,
|
||||
system: HeosSystem,
|
||||
) -> None:
|
||||
"""Test discovery does not update when current host is part of discovered's system."""
|
||||
config_entry.add_to_hass(hass)
|
||||
assert config_entry.data[CONF_HOST] == "127.0.0.1"
|
||||
|
||||
controller.get_system_info.return_value = system
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data_bedroom
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "single_instance_allowed"
|
||||
assert controller.get_system_info.call_count == 1
|
||||
assert config_entry.data[CONF_HOST] == "127.0.0.1"
|
||||
|
||||
|
||||
async def test_discovery_fails_to_connect_aborts(
|
||||
@ -145,6 +174,26 @@ async def test_discovery_fails_to_connect_aborts(
|
||||
assert controller.disconnect.call_count == 1
|
||||
|
||||
|
||||
async def test_discovery_updates(
|
||||
hass: HomeAssistant,
|
||||
discovery_data_bedroom: SsdpServiceInfo,
|
||||
controller: MockHeos,
|
||||
config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test discovery updates existing entry."""
|
||||
config_entry.add_to_hass(hass)
|
||||
assert config_entry.data[CONF_HOST] == "127.0.0.1"
|
||||
|
||||
host = HeosHost("Player", "Model", None, None, "127.0.0.2", NetworkType.WIRED, True)
|
||||
controller.get_system_info.return_value = HeosSystem(None, host, [host])
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_SSDP}, data=discovery_data_bedroom
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "reconfigure_successful"
|
||||
assert config_entry.data[CONF_HOST] == "127.0.0.2"
|
||||
|
||||
|
||||
async def test_reconfigure_validates_and_updates_config(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||
) -> None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user