mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Make harmony handle IP address changes (#33173)
If the IP address of the harmony hub changed it would not be rediscovered. We now connect to get the unique id and then update config entries with the correct ip if it is already setup.
This commit is contained in:
parent
087b672449
commit
0b2a8bf79a
@ -37,11 +37,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
|
||||
harmony_conf_file = hass.config.path(f"harmony_{entry.unique_id}.conf")
|
||||
try:
|
||||
device = HarmonyRemote(name, address, activity, harmony_conf_file, delay_secs)
|
||||
await device.connect()
|
||||
device = HarmonyRemote(
|
||||
name, entry.unique_id, address, activity, harmony_conf_file, delay_secs
|
||||
)
|
||||
connected_ok = await device.connect()
|
||||
except (asyncio.TimeoutError, ValueError, AttributeError):
|
||||
raise ConfigEntryNotReady
|
||||
|
||||
if not connected_ok:
|
||||
raise ConfigEntryNotReady
|
||||
|
||||
hass.data[DOMAIN][entry.entry_id] = device
|
||||
|
||||
entry.add_update_listener(_update_listener)
|
||||
|
@ -26,24 +26,32 @@ DATA_SCHEMA = vol.Schema(
|
||||
)
|
||||
|
||||
|
||||
async def get_harmony_client_if_available(hass: core.HomeAssistant, ip_address):
|
||||
"""Connect to a harmony hub and fetch info."""
|
||||
harmony = HarmonyAPI(ip_address=ip_address)
|
||||
|
||||
try:
|
||||
if not await harmony.connect():
|
||||
await harmony.close()
|
||||
return None
|
||||
except harmony_exceptions.TimeOut:
|
||||
return None
|
||||
|
||||
await harmony.close()
|
||||
|
||||
return harmony
|
||||
|
||||
|
||||
async def validate_input(hass: core.HomeAssistant, data):
|
||||
"""Validate the user input allows us to connect.
|
||||
|
||||
Data has the keys from DATA_SCHEMA with values provided by the user.
|
||||
"""
|
||||
harmony = HarmonyAPI(ip_address=data[CONF_HOST])
|
||||
|
||||
_LOGGER.debug("harmony:%s", harmony)
|
||||
|
||||
try:
|
||||
if not await harmony.connect():
|
||||
await harmony.close()
|
||||
raise CannotConnect
|
||||
except harmony_exceptions.TimeOut:
|
||||
harmony = await get_harmony_client_if_available(hass, data[CONF_HOST])
|
||||
if not harmony:
|
||||
raise CannotConnect
|
||||
|
||||
unique_id = find_unique_id_for_remote(harmony)
|
||||
await harmony.close()
|
||||
|
||||
# As a last resort we get the name from the harmony client
|
||||
# in the event a name was not provided. harmony.name is
|
||||
@ -74,7 +82,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
if user_input is not None:
|
||||
|
||||
try:
|
||||
info = await validate_input(self.hass, user_input)
|
||||
validated = await validate_input(self.hass, user_input)
|
||||
except CannotConnect:
|
||||
errors["base"] = "cannot_connect"
|
||||
except Exception: # pylint: disable=broad-except
|
||||
@ -82,7 +90,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
errors["base"] = "unknown"
|
||||
|
||||
if "base" not in errors:
|
||||
return await self._async_create_entry_from_valid_input(info, user_input)
|
||||
await self.async_set_unique_id(validated[UNIQUE_ID])
|
||||
self._abort_if_unique_id_configured()
|
||||
return await self._async_create_entry_from_valid_input(
|
||||
validated, user_input
|
||||
)
|
||||
|
||||
# Return form
|
||||
return self.async_show_form(
|
||||
@ -104,8 +116,17 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
CONF_NAME: friendly_name,
|
||||
}
|
||||
|
||||
if self._host_already_configured(self.harmony_config):
|
||||
return self.async_abort(reason="already_configured")
|
||||
harmony = await get_harmony_client_if_available(
|
||||
self.hass, self.harmony_config[CONF_HOST]
|
||||
)
|
||||
|
||||
if harmony:
|
||||
unique_id = find_unique_id_for_remote(harmony)
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured(
|
||||
updates={CONF_HOST: self.harmony_config[CONF_HOST]}
|
||||
)
|
||||
self.harmony_config[UNIQUE_ID] = unique_id
|
||||
|
||||
return await self.async_step_link()
|
||||
|
||||
@ -114,16 +135,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
errors = {}
|
||||
|
||||
if user_input is not None:
|
||||
try:
|
||||
info = await validate_input(self.hass, self.harmony_config)
|
||||
except CannotConnect:
|
||||
errors["base"] = "cannot_connect"
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Unexpected exception")
|
||||
errors["base"] = "unknown"
|
||||
|
||||
if "base" not in errors:
|
||||
return await self._async_create_entry_from_valid_input(info, user_input)
|
||||
# Everything was validated in async_step_ssdp
|
||||
# all we do now is create.
|
||||
return await self._async_create_entry_from_valid_input(
|
||||
self.harmony_config, {}
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="link",
|
||||
@ -146,8 +162,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
async def _async_create_entry_from_valid_input(self, validated, user_input):
|
||||
"""Single path to create the config entry from validated input."""
|
||||
await self.async_set_unique_id(validated[UNIQUE_ID])
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
data = {CONF_NAME: validated[CONF_NAME], CONF_HOST: validated[CONF_HOST]}
|
||||
# Options from yaml are preserved, we will pull them out when
|
||||
# we setup the config entry
|
||||
|
@ -34,7 +34,6 @@ from .const import (
|
||||
SERVICE_CHANGE_CHANNEL,
|
||||
SERVICE_SYNC,
|
||||
)
|
||||
from .util import find_unique_id_for_remote
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -130,7 +129,7 @@ def register_services(hass):
|
||||
class HarmonyRemote(remote.RemoteDevice):
|
||||
"""Remote representation used to control a Harmony device."""
|
||||
|
||||
def __init__(self, name, host, activity, out_path, delay_secs):
|
||||
def __init__(self, name, unique_id, host, activity, out_path, delay_secs):
|
||||
"""Initialize HarmonyRemote class."""
|
||||
self._name = name
|
||||
self.host = host
|
||||
@ -141,6 +140,7 @@ class HarmonyRemote(remote.RemoteDevice):
|
||||
self._config_path = out_path
|
||||
self.delay_secs = delay_secs
|
||||
self._available = False
|
||||
self._unique_id = unique_id
|
||||
self._undo_dispatch_subscription = None
|
||||
|
||||
@property
|
||||
@ -217,7 +217,7 @@ class HarmonyRemote(remote.RemoteDevice):
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique id."""
|
||||
return find_unique_id_for_remote(self._client)
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -91,19 +91,28 @@ async def test_form_ssdp(hass):
|
||||
"""Test we get the form with ssdp source."""
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_SSDP},
|
||||
data={
|
||||
"friendlyName": "Harmony Hub",
|
||||
"ssdp_location": "http://192.168.209.238:8088/description",
|
||||
},
|
||||
)
|
||||
harmonyapi = _get_mock_harmonyapi(connect=True)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.harmony.config_flow.HarmonyAPI",
|
||||
return_value=harmonyapi,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_SSDP},
|
||||
data={
|
||||
"friendlyName": "Harmony Hub",
|
||||
"ssdp_location": "http://192.168.1.12:8088/description",
|
||||
},
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "link"
|
||||
assert result["errors"] == {}
|
||||
assert result["description_placeholders"] == {
|
||||
"host": "Harmony Hub",
|
||||
"name": "192.168.1.12",
|
||||
}
|
||||
|
||||
harmonyapi = _get_mock_harmonyapi(connect=True)
|
||||
with patch(
|
||||
"homeassistant.components.harmony.config_flow.HarmonyAPI",
|
||||
return_value=harmonyapi,
|
||||
@ -117,7 +126,7 @@ async def test_form_ssdp(hass):
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["title"] == "Harmony Hub"
|
||||
assert result2["data"] == {
|
||||
"host": "192.168.209.238",
|
||||
"host": "192.168.1.12",
|
||||
"name": "Harmony Hub",
|
||||
}
|
||||
await hass.async_block_till_done()
|
||||
|
Loading…
x
Reference in New Issue
Block a user