diff --git a/homeassistant/components/fritz/coordinator.py b/homeassistant/components/fritz/coordinator.py index 635c7a7cf340..49d899eb02ee 100644 --- a/homeassistant/components/fritz/coordinator.py +++ b/homeassistant/components/fritz/coordinator.py @@ -601,6 +601,10 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]): ) self.mesh_role = MeshRoles.NONE for mac, info in hosts.items(): + # The box lists its own LAN MAC in the Hosts table; skip it so it + # is not tracked as a child of itself, as the mesh path does. + if dr.format_mac(mac) == self.mac: + continue if self.manage_device_info(info, mac, consider_home): new_device = True await self.async_send_signal_device_update(new_device) diff --git a/tests/components/fritz/test_coordinator.py b/tests/components/fritz/test_coordinator.py index 01a7b8564879..5f362b0a5d89 100644 --- a/tests/components/fritz/test_coordinator.py +++ b/tests/components/fritz/test_coordinator.py @@ -16,6 +16,7 @@ import pytest from homeassistant.components.fritz.const import ( CONF_FEATURE_DEVICE_TRACKING, + CONF_OLD_DISCOVERY, DEFAULT_CONF_FEATURE_DEVICE_TRACKING, DEFAULT_SSL, DOMAIN, @@ -695,3 +696,41 @@ async def test_async_trigger_cleanup_preserves_fritz_device( ) assert fritz_device_after is not None assert fritz_device_after.id == fritz_device.id + + +async def test_old_discovery_does_not_self_reference_box( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + caplog: pytest.LogCaptureFixture, + fc_class_mock, + fh_class_mock, + fs_class_mock, +) -> None: + """Test old discovery does not link the box as its own via device. + + The Hosts table lists the box's own LAN MAC (MOCK_HOST_FRITZBOX). Its MAC + connection matches the router device, so tracking it would merge it into the + router and resolve via_device_id to itself, which the device registry rejects. + """ + entry = MockConfigEntry( + domain=DOMAIN, + data=MOCK_USER_DATA, + options={CONF_OLD_DISCOVERY: True}, + ) + entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done(wait_background_tasks=True) + + assert entry.state is ConfigEntryState.LOADED + + router = device_registry.async_get_device( + identifiers={(DOMAIN, MOCK_SERIAL_NUMBER)} + ) + assert router is not None + assert router.via_device_id is None + + devices = dr.async_entries_for_config_entry(device_registry, entry.entry_id) + assert devices + for device in devices: + assert device.via_device_id != device.id