From d52ad38dcae0d4decc97e791be6cb36e4b94488d Mon Sep 17 00:00:00 2001 From: Simone Chemelli Date: Tue, 24 Mar 2026 20:38:28 +0100 Subject: [PATCH] Add reconfigure config flow to SamsungTV (#165907) --- .../components/samsungtv/config_flow.py | 27 +++++++++ .../components/samsungtv/quality_scale.yaml | 4 +- .../components/samsungtv/strings.json | 12 +++- .../components/samsungtv/test_config_flow.py | 59 +++++++++++++++++++ 4 files changed, 98 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py index f268044c103..938b719c802 100644 --- a/homeassistant/components/samsungtv/config_flow.py +++ b/homeassistant/components/samsungtv/config_flow.py @@ -13,6 +13,7 @@ from samsungtvws.encrypted.authenticator import SamsungTVEncryptedWSAsyncAuthent import voluptuous as vol from homeassistant.config_entries import ( + SOURCE_RECONFIGURE, ConfigEntry, ConfigEntryState, ConfigFlow, @@ -289,6 +290,32 @@ class SamsungTVConfigFlow(ConfigFlow, domain=DOMAIN): errors=errors, ) + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle reconfiguration of the config entry.""" + reconfigure_entry = self._get_reconfigure_entry() + + errors: dict[str, str] | None = None + if user_input is not None: + if await self._async_set_name_host_from_input(user_input): + self._async_abort_entries_match({CONF_HOST: self._host}) + return self.async_update_reload_and_abort( + reconfigure_entry, + data_updates={CONF_HOST: self._host}, + ) + errors = {"base": "invalid_host"} + + suggested_values = user_input or {CONF_HOST: reconfigure_entry.data[CONF_HOST]} + return self.async_show_form( + step_id=SOURCE_RECONFIGURE, + data_schema=self.add_suggested_values_to_schema( + DATA_SCHEMA, + suggested_values, + ), + errors=errors, + ) + async def async_step_pairing( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: diff --git a/homeassistant/components/samsungtv/quality_scale.yaml b/homeassistant/components/samsungtv/quality_scale.yaml index 4cea6ea319e..2a993698f9a 100644 --- a/homeassistant/components/samsungtv/quality_scale.yaml +++ b/homeassistant/components/samsungtv/quality_scale.yaml @@ -76,9 +76,7 @@ rules: icon-translations: status: done comment: no custom icons, only default icons - reconfiguration-flow: - status: todo - comment: handle at least host change + reconfiguration-flow: done repair-issues: status: exempt comment: no known repair use case so far diff --git a/homeassistant/components/samsungtv/strings.json b/homeassistant/components/samsungtv/strings.json index 75292e4d438..180e412a4db 100644 --- a/homeassistant/components/samsungtv/strings.json +++ b/homeassistant/components/samsungtv/strings.json @@ -7,7 +7,8 @@ "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "id_missing": "This Samsung device doesn't have a serial number to identify it.", "not_supported": "This Samsung device is currently not supported.", - "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%]" }, "error": { "auth_missing": "[%key:component::samsungtv::config::abort::auth_missing%]", @@ -43,6 +44,15 @@ }, "description": "[%key:component::samsungtv::config::step::encrypted_pairing::description%]" }, + "reconfigure": { + "data": { + "host": "[%key:common::config_flow::data::host%]" + }, + "data_description": { + "host": "[%key:component::samsungtv::config::step::user::data_description::host%]" + }, + "description": "Update the hostname or IP address of your Samsung TV." + }, "user": { "data": { "host": "[%key:common::config_flow::data::host%]", diff --git a/tests/components/samsungtv/test_config_flow.py b/tests/components/samsungtv/test_config_flow.py index 35f30bc7a10..71c7fd9093d 100644 --- a/tests/components/samsungtv/test_config_flow.py +++ b/tests/components/samsungtv/test_config_flow.py @@ -1823,6 +1823,65 @@ async def test_form_reauth_legacy(hass: HomeAssistant) -> None: assert result2["reason"] == "reauth_successful" +async def test_reconfigure_host(hass: HomeAssistant) -> None: + """Test reconfigure flow updates the host.""" + entry = MockConfigEntry(domain=DOMAIN, data=ENTRYDATA_WEBSOCKET) + entry.add_to_hass(hass) + + result = await entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == config_entries.SOURCE_RECONFIGURE + + with patch( + "homeassistant.components.samsungtv.config_flow.socket.gethostbyname", + return_value="10.10.12.77", + ): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_HOST: "new-host"}, + ) + + assert result2["type"] is FlowResultType.ABORT + assert result2["reason"] == "reconfigure_successful" + assert entry.data[CONF_HOST] == "10.10.12.77" + + +async def test_reconfigure_host_invalid(hass: HomeAssistant) -> None: + """Test reconfigure flow retries on invalid host.""" + entry = MockConfigEntry(domain=DOMAIN, data=ENTRYDATA_WEBSOCKET) + entry.add_to_hass(hass) + + result = await entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + + with patch( + "homeassistant.components.samsungtv.config_flow.socket.gethostbyname", + side_effect=socket.gaierror("invalid host"), + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_HOST: "bad-host"}, + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == config_entries.SOURCE_RECONFIGURE + assert result["errors"] == {"base": "invalid_host"} + + with patch( + "homeassistant.components.samsungtv.config_flow.socket.gethostbyname", + return_value="10.10.12.77", + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_HOST: "new-host"}, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + assert entry.data[CONF_HOST] == "10.10.12.77" + + @pytest.mark.usefixtures("remote_websocket", "rest_api") async def test_form_reauth_websocket(hass: HomeAssistant) -> None: """Test reauthenticate websocket."""