Rework Z-Wave.Me to group entities of one physical devices (#78553)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Dmitry Vlasov <kerbalspacema@gmail.com>
This commit is contained in:
Poltorak Serguei 2022-11-02 19:53:10 +03:00 committed by GitHub
parent 93d74cafdc
commit 7af0f16f79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 14 deletions

View file

@ -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)
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:
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,

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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
)