mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 15:47:12 +00:00
Add reconfigure flow in Android TV Remote (#148044)
This commit is contained in:
parent
e5f7421703
commit
b410b414ec
@ -16,6 +16,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_REAUTH,
|
||||
SOURCE_RECONFIGURE,
|
||||
ConfigFlow,
|
||||
ConfigFlowResult,
|
||||
OptionsFlow,
|
||||
@ -40,12 +41,6 @@ APPS_NEW_ID = "NewApp"
|
||||
CONF_APP_DELETE = "app_delete"
|
||||
CONF_APP_ID = "app_id"
|
||||
|
||||
STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required("host"): str,
|
||||
}
|
||||
)
|
||||
|
||||
STEP_PAIR_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required("pin"): str,
|
||||
@ -66,7 +61,7 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle the initial step."""
|
||||
"""Handle the initial and reconfigure step."""
|
||||
errors: dict[str, str] = {}
|
||||
if user_input is not None:
|
||||
self.host = user_input[CONF_HOST]
|
||||
@ -75,15 +70,32 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
await api.async_generate_cert_if_missing()
|
||||
self.name, self.mac = await api.async_get_name_and_mac()
|
||||
await self.async_set_unique_id(format_mac(self.mac))
|
||||
if self.source == SOURCE_RECONFIGURE:
|
||||
self._abort_if_unique_id_mismatch()
|
||||
return self.async_update_reload_and_abort(
|
||||
self._get_reconfigure_entry(),
|
||||
data={
|
||||
CONF_HOST: self.host,
|
||||
CONF_NAME: self.name,
|
||||
CONF_MAC: self.mac,
|
||||
},
|
||||
)
|
||||
self._abort_if_unique_id_configured(updates={CONF_HOST: self.host})
|
||||
return await self._async_start_pair()
|
||||
except (CannotConnect, ConnectionClosed):
|
||||
# Likely invalid IP address or device is network unreachable. Stay
|
||||
# in the user step allowing the user to enter a different host.
|
||||
errors["base"] = "cannot_connect"
|
||||
else:
|
||||
user_input = {}
|
||||
default_host = user_input.get(CONF_HOST, vol.UNDEFINED)
|
||||
if self.source == SOURCE_RECONFIGURE:
|
||||
default_host = self._get_reconfigure_entry().data[CONF_HOST]
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=STEP_USER_DATA_SCHEMA,
|
||||
step_id="reconfigure" if self.source == SOURCE_RECONFIGURE else "user",
|
||||
data_schema=vol.Schema(
|
||||
{vol.Required(CONF_HOST, default=default_host): str}
|
||||
),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
@ -216,6 +228,12 @@ class AndroidTVRemoteConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle reconfiguration."""
|
||||
return await self.async_step_user(user_input)
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(
|
||||
|
@ -11,6 +11,15 @@
|
||||
"host": "The hostname or IP address of the Android TV device."
|
||||
}
|
||||
},
|
||||
"reconfigure": {
|
||||
"description": "Update the IP address of this previously configured Android TV device.",
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]"
|
||||
},
|
||||
"data_description": {
|
||||
"host": "The hostname or IP address of the Android TV device."
|
||||
}
|
||||
},
|
||||
"zeroconf_confirm": {
|
||||
"title": "Discovered Android TV",
|
||||
"description": "Do you want to add the Android TV ({name}) to Home Assistant? It will turn on and a pairing code will be displayed on it that you will need to enter in the next screen."
|
||||
@ -38,7 +47,9 @@
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
|
||||
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]",
|
||||
"unique_id_mismatch": "Please ensure you reconfigure against the same device."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
|
@ -1069,3 +1069,100 @@ async def test_options_flow(
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert mock_config_entry.options == {CONF_ENABLE_IME: True}
|
||||
|
||||
|
||||
async def test_reconfigure_flow_success(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_setup_entry: AsyncMock,
|
||||
mock_api: MagicMock,
|
||||
) -> None:
|
||||
"""Test the full reconfigure flow from start to finish without any exceptions."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
result = await mock_config_entry.start_reconfigure_flow(hass)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "reconfigure"
|
||||
assert not result["errors"]
|
||||
assert "host" in result["data_schema"].schema
|
||||
# Form should have as default value the existing host
|
||||
host_key = next(k for k in result["data_schema"].schema if k.schema == "host")
|
||||
assert host_key.default() == mock_config_entry.data["host"]
|
||||
|
||||
mock_api.async_generate_cert_if_missing = AsyncMock(return_value=True)
|
||||
mock_api.async_get_name_and_mac = AsyncMock(
|
||||
return_value=(mock_config_entry.data["name"], mock_config_entry.data["mac"])
|
||||
)
|
||||
|
||||
# Simulate user input with a new host
|
||||
new_host = "4.3.2.1"
|
||||
assert new_host != mock_config_entry.data["host"]
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {"host": new_host}
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "reconfigure_successful"
|
||||
assert mock_config_entry.data["host"] == new_host
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_reconfigure_flow_cannot_connect(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_setup_entry: AsyncMock,
|
||||
mock_api: MagicMock,
|
||||
) -> None:
|
||||
"""Test reconfigure flow with CannotConnect exception."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
result = await mock_config_entry.start_reconfigure_flow(hass)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "reconfigure"
|
||||
|
||||
mock_api.async_generate_cert_if_missing = AsyncMock(return_value=True)
|
||||
mock_api.async_get_name_and_mac = AsyncMock(side_effect=CannotConnect())
|
||||
|
||||
new_host = "4.3.2.1"
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {"host": new_host}
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "reconfigure"
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
assert mock_config_entry.data["host"] == "1.2.3.4"
|
||||
assert len(mock_setup_entry.mock_calls) == 0
|
||||
|
||||
|
||||
async def test_reconfigure_flow_unique_id_mismatch(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_setup_entry: AsyncMock,
|
||||
mock_api: MagicMock,
|
||||
) -> None:
|
||||
"""Test reconfigure flow with a different device (unique_id mismatch)."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
result = await mock_config_entry.start_reconfigure_flow(hass)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "reconfigure"
|
||||
|
||||
mock_api.async_generate_cert_if_missing = AsyncMock(return_value=True)
|
||||
# The new host corresponds to a device with a different MAC/unique_id
|
||||
new_mac = "FF:EE:DD:CC:BB:AA"
|
||||
assert new_mac != mock_config_entry.data["mac"]
|
||||
mock_api.async_get_name_and_mac = AsyncMock(return_value=("name", new_mac))
|
||||
|
||||
new_host = "4.3.2.1"
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {"host": new_host}
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "unique_id_mismatch"
|
||||
assert mock_config_entry.data["host"] == "1.2.3.4"
|
||||
assert len(mock_setup_entry.mock_calls) == 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user