diff --git a/custom_components/parcelapp/__init__.py b/custom_components/parcelapp/__init__.py index d8d7f39..7a8f852 100644 --- a/custom_components/parcelapp/__init__.py +++ b/custom_components/parcelapp/__init__.py @@ -81,19 +81,27 @@ async def cleanup_old_device(hass: HomeAssistant) -> None: Older versions of this integration registered a device using a malformed identifier -- a bare ``(DOMAIN,)`` tuple instead of the expected - ``(DOMAIN, )``. ``device_registry.async_get_device`` is - deprecated (scheduled for removal in HA Core 2027.8.0) because device - identifiers are no longer guaranteed unique across config entries, and it - cannot be used to look up the malformed single-element identifier anyway. - - Iterate the device registry and remove any device that still carries the - improper identifier. + ``(DOMAIN, )``. That device cannot be looked up with + ``device_registry.async_get_device`` (deprecated, and it requires a + well-formed identifier pair), and using ``device_registry.devices`` as a + mapping is deprecated too (stops working in HA Core 2027.9.0). + + Walk this integration's own config entries with the supported + ``async_entries_for_config_entry`` helper and remove any device that still + carries the improper identifier. """ device_reg = dr.async_get(hass) - for device in list(device_reg.devices.values()): - if any( - len(identifier) == 1 and identifier[0] == DOMAIN - for identifier in device.identifiers + removed: set[str] = set() + for config_entry in hass.config_entries.async_entries(DOMAIN): + for device in dr.async_entries_for_config_entry( + device_reg, config_entry.entry_id ): - _LOGGER.debug("Removing improper device %s", device.name) - device_reg.async_remove_device(device.id) + if device.id in removed: + continue + if any( + len(identifier) == 1 and identifier[0] == DOMAIN + for identifier in device.identifiers + ): + _LOGGER.debug("Removing improper device %s", device.name) + device_reg.async_remove_device(device.id) + removed.add(device.id) diff --git a/custom_components/parcelapp/manifest.json b/custom_components/parcelapp/manifest.json index b9e21f9..74c619d 100644 --- a/custom_components/parcelapp/manifest.json +++ b/custom_components/parcelapp/manifest.json @@ -11,5 +11,5 @@ "requests>=2.32.3", "python-dateutil>=2.9.0" ], - "version": "1.8.2" + "version": "1.8.3" } diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 0000000..74acc48 --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,32 @@ +"""Tests for the integration setup helpers.""" + +import pytest +from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr +from pytest_homeassistant_custom_component.common import MockConfigEntry + +from custom_components.parcelapp import cleanup_old_device +from custom_components.parcelapp.const import DOMAIN + + +@pytest.mark.asyncio +async def test_cleanup_removes_only_the_malformed_device(hass: HomeAssistant) -> None: + """The legacy bare (DOMAIN,) device is removed, a well-formed one is kept.""" + entry = MockConfigEntry( + domain=DOMAIN, entry_id="entry_1", data={"api_key": "test_api_key"} + ) + entry.add_to_hass(hass) + device_reg = dr.async_get(hass) + legacy = device_reg.async_get_or_create( + config_entry_id=entry.entry_id, identifiers={(DOMAIN,)}, name="Legacy" + ) + current = device_reg.async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, entry.entry_id)}, + name="Parcel", + ) + + await cleanup_old_device(hass) + + assert device_reg.async_get(legacy.id) is None + assert device_reg.async_get(current.id) is not None