diff --git a/homeassistant/components/zwave_me/__init__.py b/homeassistant/components/zwave_me/__init__.py index 10312f36dfc34cb861ce1c31040138d1be91f245..ed3d538d052c8653b3e2dc21570de604bb05ed31 100644 --- a/homeassistant/components/zwave_me/__init__.py +++ b/homeassistant/components/zwave_me/__init__.py @@ -8,6 +8,8 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_TOKEN, CONF_URL from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.helpers import device_registry +from homeassistant.helpers.device_registry import DeviceRegistry from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send from homeassistant.helpers.entity import DeviceInfo, Entity @@ -23,6 +25,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: controller = hass.data[DOMAIN][entry.entry_id] = ZWaveMeController(hass, entry) if await controller.async_establish_connection(): hass.async_create_task(async_setup_platforms(hass, entry, controller)) + registry = device_registry.async_get(hass) + controller.remove_stale_devices(registry) return True raise ConfigEntryNotReady() @@ -62,24 +66,33 @@ class ZWaveMeController: def add_device(self, device: ZWaveMeData) -> None: """Send signal to create device.""" - if device.deviceType in ZWAVE_ME_PLATFORMS and self.platforms_inited: - if device.id in self.device_ids: - dispatcher_send(self._hass, f"ZWAVE_ME_INFO_{device.id}", device) - else: - dispatcher_send( - self._hass, f"ZWAVE_ME_NEW_{device.deviceType.upper()}", device - ) - self.device_ids.add(device.id) - - def on_device_create(self, devices: list) -> None: + if device.id in self.device_ids: + dispatcher_send(self._hass, f"ZWAVE_ME_INFO_{device.id}", device) + else: + dispatcher_send( + self._hass, f"ZWAVE_ME_NEW_{device.deviceType.upper()}", device + ) + self.device_ids.add(device.id) + + def on_device_create(self, devices: list[ZWaveMeData]) -> None: """Create multiple devices.""" for device in devices: - self.add_device(device) + if device.deviceType in ZWAVE_ME_PLATFORMS and self.platforms_inited: + self.add_device(device) def on_device_update(self, new_info: ZWaveMeData) -> None: """Send signal to update device.""" dispatcher_send(self._hass, f"ZWAVE_ME_INFO_{new_info.id}", new_info) + def remove_stale_devices(self, registry: DeviceRegistry): + """Remove old-format devices in the registry.""" + for device_id in self.device_ids: + device = registry.async_get_device( + {(DOMAIN, f"{self.config.unique_id}-{device_id}")} + ) + if device is not None: + registry.async_remove_device(device.id) + async def async_setup_platforms( hass: HomeAssistant, entry: ConfigEntry, controller: ZWaveMeController @@ -113,7 +126,7 @@ class ZWaveMeEntity(Entity): def device_info(self) -> DeviceInfo: """Return device specific attributes.""" return DeviceInfo( - identifiers={(DOMAIN, self._attr_unique_id)}, + identifiers={(DOMAIN, self.device.deviceIdentifier)}, name=self._attr_name, manufacturer=self.device.manufacturer, sw_version=self.device.firmware, diff --git a/homeassistant/components/zwave_me/manifest.json b/homeassistant/components/zwave_me/manifest.json index 4ca933f43bc4b70d582a1d4cebe25bd8d3ffafe1..9aeeb7b2a40a1c7e9378813350030dbc5a0734b1 100644 --- a/homeassistant/components/zwave_me/manifest.json +++ b/homeassistant/components/zwave_me/manifest.json @@ -3,7 +3,7 @@ "name": "Z-Wave.Me", "documentation": "https://www.home-assistant.io/integrations/zwave_me", "iot_class": "local_push", - "requirements": ["zwave_me_ws==0.2.6", "url-normalize==1.4.3"], + "requirements": ["zwave_me_ws==0.3.0", "url-normalize==1.4.3"], "after_dependencies": ["zeroconf"], "zeroconf": [{ "type": "_hap._tcp.local.", "name": "*z.wave-me*" }], "config_flow": true, diff --git a/requirements_all.txt b/requirements_all.txt index dd54335dd7101b47284eaba98524cbb3d14cc157..29e9d79aa0da4ae5d9719245a6e5af3f369c7f74 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2640,4 +2640,4 @@ zm-py==0.5.2 zwave-js-server-python==0.43.0 # homeassistant.components.zwave_me -zwave_me_ws==0.2.6 +zwave_me_ws==0.3.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3ec5e21e4f693ff90baee72b3ab4092407766567..691b19b8b1235ff1afcf644009b6bb85364bf7d0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1832,4 +1832,4 @@ zigpy==0.51.5 zwave-js-server-python==0.43.0 # homeassistant.components.zwave_me -zwave_me_ws==0.2.6 +zwave_me_ws==0.3.0 diff --git a/tests/components/zwave_me/test_remove_stale_devices.py b/tests/components/zwave_me/test_remove_stale_devices.py new file mode 100644 index 0000000000000000000000000000000000000000..484c38b9f33d18498a2304e0728b5e14d323e5dd --- /dev/null +++ b/tests/components/zwave_me/test_remove_stale_devices.py @@ -0,0 +1,74 @@ +"""Test the zwave_me removal of stale devices.""" +from unittest.mock import patch +import uuid + +import pytest as pytest +from zwave_me_ws import ZWaveMeData + +from homeassistant.components.zwave_me import ZWaveMePlatform +from homeassistant.const import CONF_TOKEN, CONF_URL +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry, mock_device_registry + +DEFAULT_DEVICE_INFO = ZWaveMeData( + id="DummyDevice", + deviceType=ZWaveMePlatform.BINARY_SENSOR, + title="DeviceDevice", + level=100, + deviceIdentifier="16-23", +) + + +@pytest.fixture +def device_reg(hass): + """Return an empty, loaded, registry.""" + return mock_device_registry(hass) + + +async def mock_connection(controller): + """Mock established connection and setting identifiers.""" + controller.on_new_device(DEFAULT_DEVICE_INFO) + return True + + +@pytest.mark.parametrize( + "identifier,should_exist", + [ + (DEFAULT_DEVICE_INFO.id, False), + (DEFAULT_DEVICE_INFO.deviceIdentifier, True), + ], +) +async def test_remove_stale_devices( + hass: HomeAssistant, device_reg, identifier, should_exist +): + """Test removing devices with old-format ids.""" + + config_entry = MockConfigEntry( + unique_id=uuid.uuid4(), + domain="zwave_me", + data={CONF_TOKEN: "test_token", CONF_URL: "http://test_test"}, + ) + config_entry.add_to_hass(hass) + device_reg.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={("mac", "12:34:56:AB:CD:EF")}, + identifiers={("zwave_me", f"{config_entry.unique_id}-{identifier}")}, + ) + with patch("zwave_me_ws.ZWaveMe.get_connection", mock_connection,), patch( + "homeassistant.components.zwave_me.async_setup_platforms", + ): + await hass.config_entries.async_setup(config_entry.entry_id) + assert ( + bool( + device_reg.async_get_device( + { + ( + "zwave_me", + f"{config_entry.unique_id}-{identifier}", + ) + } + ) + ) + == should_exist + )