diff --git a/homeassistant/components/motionmount/config_flow.py b/homeassistant/components/motionmount/config_flow.py index c7cb76779de711..4e007b909d30bd 100644 --- a/homeassistant/components/motionmount/config_flow.py +++ b/homeassistant/components/motionmount/config_flow.py @@ -107,9 +107,21 @@ async def async_step_zeroconf( # so we can avoid probing the device if its already # configured or ignored await self.async_set_unique_id(unique_id) - self._abort_if_unique_id_configured( - updates={CONF_HOST: host, CONF_PORT: port} + existing_entry = self._async_current_entries() + existing_host = next( + ( + e.data.get(CONF_HOST, "") + for e in existing_entry + if e.unique_id == unique_id + ), + "", ) + if not existing_host or existing_host.endswith(".local"): + host_updates = {CONF_HOST: host, CONF_PORT: port} + else: + host_updates = {CONF_PORT: port} + self.connection_data[CONF_HOST] = existing_host + self._abort_if_unique_id_configured(updates=host_updates) else: # Avoid probing devices that already have an entry self._async_abort_entries_match({CONF_HOST: host}) @@ -131,9 +143,21 @@ async def async_step_zeroconf( if unique_id: await self.async_set_unique_id(unique_id) - self._abort_if_unique_id_configured( - updates={CONF_HOST: host, CONF_PORT: port} + existing_entry = self._async_current_entries() + existing_host = next( + ( + e.data.get(CONF_HOST, "") + for e in existing_entry + if e.unique_id == unique_id + ), + "", + ) + host_updates = ( + {CONF_HOST: host, CONF_PORT: port} + if not existing_host or existing_host.endswith(".local") + else {CONF_PORT: port} ) + self._abort_if_unique_id_configured(updates=host_updates) else: await self._async_handle_discovery_without_unique_id() diff --git a/tests/components/motionmount/test_config_flow.py b/tests/components/motionmount/test_config_flow.py index f6c5e8d8cc3161..96536b22d6002a 100644 --- a/tests/components/motionmount/test_config_flow.py +++ b/tests/components/motionmount/test_config_flow.py @@ -389,6 +389,34 @@ async def test_zeroconf_device_exists_abort( assert result["reason"] == "already_configured" +async def test_zeroconf_does_not_overwrite_static_ip( + hass: HomeAssistant, + mock_motionmount: MagicMock, +) -> None: + """Test zeroconf discovery does not overwrite a manually configured static IP.""" + mock_config_entry = MockConfigEntry( + domain=DOMAIN, + unique_id=ZEROCONF_MAC, + data={ + CONF_HOST: HOST, + CONF_PORT: PORT, + }, + ) + mock_config_entry.add_to_hass(hass) + + discovery_info = dataclasses.replace(MOCK_ZEROCONF_TVM_SERVICE_INFO_V2) + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_ZEROCONF}, + data=discovery_info, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" + assert mock_config_entry.data[CONF_HOST] == HOST + assert mock_config_entry.data[CONF_HOST] != ZEROCONF_HOSTNAME + + async def test_zeroconf_authentication_needed( hass: HomeAssistant, mock_config_entry: MockConfigEntry,