diff --git a/homeassistant/components/sma/config_flow.py b/homeassistant/components/sma/config_flow.py index f43c851d04a..e08b9ade9fc 100644 --- a/homeassistant/components/sma/config_flow.py +++ b/homeassistant/components/sma/config_flow.py @@ -184,7 +184,36 @@ class SmaConfigFlow(ConfigFlow, domain=DOMAIN): self._data[CONF_HOST] = discovery_info.ip self._data[CONF_MAC] = format_mac(self._discovery_data[CONF_MAC]) - await self.async_set_unique_id(discovery_info.hostname.replace("SMA", "")) + _LOGGER.debug( + "DHCP discovery detected SMA device: %s, IP: %s, MAC: %s", + self._discovery_data[CONF_NAME], + self._discovery_data[CONF_HOST], + self._discovery_data[CONF_MAC], + ) + + existing_entries_with_host = [ + entry + for entry in self._async_current_entries(include_ignore=False) + if entry.data.get(CONF_HOST) == self._data[CONF_HOST] + and not entry.data.get(CONF_MAC) + ] + + # If we have an existing entry with the same host but no MAC address, + # we update the entry with the MAC address and reload it. + if existing_entries_with_host: + entry = existing_entries_with_host[0] + self.async_update_reload_and_abort( + entry, data_updates={CONF_MAC: self._data[CONF_MAC]} + ) + + # Finally, check if the hostname (which represents the SMA serial number) is unique + serial_number = discovery_info.hostname.lower() + # Example hostname: sma12345678-01 + # Remove 'sma' prefix and strip everything after the dash (including the dash) + if serial_number.startswith("sma"): + serial_number = serial_number.removeprefix("sma") + serial_number = serial_number.split("-", 1)[0] + await self.async_set_unique_id(serial_number) self._abort_if_unique_id_configured() return await self.async_step_discovery_confirm() diff --git a/tests/components/sma/test_config_flow.py b/tests/components/sma/test_config_flow.py index 29779ec2773..b2e488318a5 100644 --- a/tests/components/sma/test_config_flow.py +++ b/tests/components/sma/test_config_flow.py @@ -11,8 +11,10 @@ import pytest from homeassistant.components.sma.const import DOMAIN from homeassistant.config_entries import SOURCE_DHCP, SOURCE_USER +from homeassistant.const import CONF_MAC from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType +from homeassistant.helpers.device_registry import format_mac from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo from . import ( @@ -37,6 +39,12 @@ DHCP_DISCOVERY_DUPLICATE = DhcpServiceInfo( macaddress="0015bb00abcd", ) +DHCP_DISCOVERY_DUPLICATE_001 = DhcpServiceInfo( + ip="1.1.1.1", + hostname="SMA123456789-001", + macaddress="0015bb00abcd", +) + async def test_form( hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_sma_client: AsyncMock @@ -154,6 +162,31 @@ async def test_dhcp_already_configured( assert result["reason"] == "already_configured" +async def test_dhcp_already_configured_duplicate( + hass: HomeAssistant, mock_config_entry: MockConfigEntry +) -> None: + """Test starting a flow by DHCP when already configured and MAC is added.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert CONF_MAC not in mock_config_entry.data + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_DHCP}, + data=DHCP_DISCOVERY_DUPLICATE_001, + ) + + assert result["type"] == FlowResultType.ABORT + assert result["reason"] == "already_configured" + await hass.async_block_till_done() + + assert mock_config_entry.data.get(CONF_MAC) == format_mac( + DHCP_DISCOVERY_DUPLICATE_001.macaddress + ) + + @pytest.mark.parametrize( ("exception", "error"), [