diff --git a/homeassistant/components/onewire/config_flow.py b/homeassistant/components/onewire/config_flow.py index 55b575e5f62..b5039d19b2d 100644 --- a/homeassistant/components/onewire/config_flow.py +++ b/homeassistant/components/onewire/config_flow.py @@ -62,8 +62,9 @@ class OneWireFlowHandler(ConfigFlow, domain=DOMAIN): """Handle 1-Wire config flow start.""" errors: dict[str, str] = {} if user_input: - # Prevent duplicate entries (host+port) - self._async_abort_entries_match(user_input) + self._async_abort_entries_match( + {CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT]} + ) await validate_input(self.hass, user_input, errors) if not errors: @@ -77,6 +78,32 @@ class OneWireFlowHandler(ConfigFlow, domain=DOMAIN): errors=errors, ) + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle 1-Wire reconfiguration.""" + errors: dict[str, str] = {} + reconfigure_entry = self._get_reconfigure_entry() + if user_input: + self._async_abort_entries_match( + {CONF_HOST: user_input[CONF_HOST], CONF_PORT: user_input[CONF_PORT]} + ) + + await validate_input(self.hass, user_input, errors) + if not errors: + return self.async_update_reload_and_abort( + reconfigure_entry, data_updates=user_input + ) + + return self.async_show_form( + step_id="reconfigure", + data_schema=self.add_suggested_values_to_schema( + DATA_SCHEMA, reconfigure_entry.data | (user_input or {}) + ), + description_placeholders={"name": reconfigure_entry.title}, + errors=errors, + ) + @staticmethod @callback def async_get_options_flow( diff --git a/homeassistant/components/onewire/strings.json b/homeassistant/components/onewire/strings.json index 68585c3203f..cd8615dc5aa 100644 --- a/homeassistant/components/onewire/strings.json +++ b/homeassistant/components/onewire/strings.json @@ -1,21 +1,34 @@ { "config": { "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", + "reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]" }, "error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" }, "step": { + "reconfigure": { + "data": { + "host": "[%key:common::config_flow::data::host%]", + "port": "[%key:common::config_flow::data::port%]" + }, + "data_description": { + "host": "[%key:component::onewire::config::step::user::data_description::host%]", + "port": "[%key:component::onewire::config::step::user::data_description::port%]" + }, + "description": "Update OWServer configuration for {name}" + }, "user": { "data": { "host": "[%key:common::config_flow::data::host%]", "port": "[%key:common::config_flow::data::port%]" }, "data_description": { - "host": "The hostname or IP address of your 1-Wire device." + "host": "The hostname or IP address of your OWServer instance.", + "port": "The port of your OWServer instance (default is 4304)." }, - "title": "Set server details" + "title": "Set OWServer instance details" } } }, diff --git a/tests/components/onewire/test_config_flow.py b/tests/components/onewire/test_config_flow.py index 029e1278c86..cf61ab190db 100644 --- a/tests/components/onewire/test_config_flow.py +++ b/tests/components/onewire/test_config_flow.py @@ -17,6 +17,8 @@ from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers import device_registry as dr +from tests.common import MockConfigEntry + pytestmark = pytest.mark.usefixtures("mock_setup_entry") @@ -102,6 +104,78 @@ async def test_user_duplicate( assert result["reason"] == "already_configured" +async def test_reconfigure_flow( + hass: HomeAssistant, config_entry: MockConfigEntry, mock_setup_entry: AsyncMock +) -> None: + """Test reconfigure flow.""" + result = await config_entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + assert not result["errors"] + + # Invalid server + with patch( + "homeassistant.components.onewire.onewirehub.protocol.proxy", + side_effect=protocol.ConnError, + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_HOST: "2.3.4.5", CONF_PORT: 2345}, + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + assert result["errors"] == {"base": "cannot_connect"} + + # Valid server + with patch( + "homeassistant.components.onewire.onewirehub.protocol.proxy", + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_HOST: "2.3.4.5", CONF_PORT: 2345}, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + assert config_entry.data == {CONF_HOST: "2.3.4.5", CONF_PORT: 2345} + + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_reconfigure_duplicate( + hass: HomeAssistant, config_entry: MockConfigEntry, mock_setup_entry: AsyncMock +) -> None: + """Test reconfigure duplicate flow.""" + other_config_entry = MockConfigEntry( + domain=DOMAIN, + source=SOURCE_USER, + data={ + CONF_HOST: "2.3.4.5", + CONF_PORT: 2345, + }, + entry_id="other", + ) + other_config_entry.add_to_hass(hass) + + result = await config_entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + assert not result["errors"] + + # Duplicate server + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_HOST: "2.3.4.5", CONF_PORT: 2345}, + ) + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" + + assert len(mock_setup_entry.mock_calls) == 0 + assert config_entry.data == {CONF_HOST: "1.2.3.4", CONF_PORT: 1234} + assert other_config_entry.data == {CONF_HOST: "2.3.4.5", CONF_PORT: 2345} + + @pytest.mark.usefixtures("filled_device_registry") async def test_user_options_clear( hass: HomeAssistant, config_entry: ConfigEntry