Clean zwave_js entity driver access (#72427)

pull/72467/head
Martin Hjelmare 2022-05-24 23:52:07 +02:00 committed by GitHub
parent c4ca106379
commit f7475a5bdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 250 additions and 165 deletions

View File

@ -124,13 +124,13 @@ def register_node_in_dev_reg(
hass: HomeAssistant,
entry: ConfigEntry,
dev_reg: device_registry.DeviceRegistry,
client: ZwaveClient,
driver: Driver,
node: ZwaveNode,
remove_device_func: Callable[[device_registry.DeviceEntry], None],
) -> device_registry.DeviceEntry:
"""Register node in dev reg."""
device_id = get_device_id(client, node)
device_id_ext = get_device_id_ext(client, node)
device_id = get_device_id(driver, node)
device_id_ext = get_device_id_ext(driver, node)
device = dev_reg.async_get_device({device_id})
# Replace the device if it can be determined that this node is not the
@ -281,7 +281,7 @@ async def setup_driver( # noqa: C901
ent_reg,
registered_unique_ids[device.id][disc_info.platform],
device,
client,
driver,
disc_info,
)
@ -316,7 +316,7 @@ async def setup_driver( # noqa: C901
LOGGER.debug("Processing node %s", node)
# register (or update) node in device registry
device = register_node_in_dev_reg(
hass, entry, dev_reg, client, node, remove_device
hass, entry, dev_reg, driver, node, remove_device
)
# We only want to create the defaultdict once, even on reinterviews
if device.id not in registered_unique_ids:
@ -384,7 +384,7 @@ async def setup_driver( # noqa: C901
)
# we do submit the node to device registry so user has
# some visual feedback that something is (in the process of) being added
register_node_in_dev_reg(hass, entry, dev_reg, client, node, remove_device)
register_node_in_dev_reg(hass, entry, dev_reg, driver, node, remove_device)
async def async_on_value_added(
value_updates_disc_info: dict[str, ZwaveDiscoveryInfo], value: Value
@ -393,7 +393,7 @@ async def setup_driver( # noqa: C901
# If node isn't ready or a device for this node doesn't already exist, we can
# let the node ready event handler perform discovery. If a value has already
# been processed, we don't need to do it again
device_id = get_device_id(client, value.node)
device_id = get_device_id(driver, value.node)
if (
not value.node.ready
or not (device := dev_reg.async_get_device({device_id}))
@ -417,7 +417,7 @@ async def setup_driver( # noqa: C901
node: ZwaveNode = event["node"]
replaced: bool = event.get("replaced", False)
# grab device in device registry attached to this node
dev_id = get_device_id(client, node)
dev_id = get_device_id(driver, node)
device = dev_reg.async_get_device({dev_id})
# We assert because we know the device exists
assert device
@ -426,7 +426,7 @@ async def setup_driver( # noqa: C901
async_dispatcher_send(
hass,
f"{DOMAIN}_{get_valueless_base_unique_id(client, node)}_remove_entity",
f"{DOMAIN}_{get_valueless_base_unique_id(driver, node)}_remove_entity",
)
else:
remove_device(device)
@ -434,7 +434,7 @@ async def setup_driver( # noqa: C901
@callback
def async_on_value_notification(notification: ValueNotification) -> None:
"""Relay stateless value notification events from Z-Wave nodes to hass."""
device = dev_reg.async_get_device({get_device_id(client, notification.node)})
device = dev_reg.async_get_device({get_device_id(driver, notification.node)})
# We assert because we know the device exists
assert device
raw_value = value = notification.value
@ -469,7 +469,7 @@ async def setup_driver( # noqa: C901
notification: EntryControlNotification | NotificationNotification | PowerLevelNotification | MultilevelSwitchNotification = event[
"notification"
]
device = dev_reg.async_get_device({get_device_id(client, notification.node)})
device = dev_reg.async_get_device({get_device_id(driver, notification.node)})
# We assert because we know the device exists
assert device
event_data = {
@ -533,11 +533,11 @@ async def setup_driver( # noqa: C901
return
disc_info = value_updates_disc_info[value.value_id]
device = dev_reg.async_get_device({get_device_id(client, value.node)})
device = dev_reg.async_get_device({get_device_id(driver, value.node)})
# We assert because we know the device exists
assert device
unique_id = get_unique_id(client, disc_info.primary_value.value_id)
unique_id = get_unique_id(driver, disc_info.primary_value.value_id)
entity_id = ent_reg.async_get_entity_id(disc_info.platform, DOMAIN, unique_id)
raw_value = value_ = value.value
@ -575,7 +575,7 @@ async def setup_driver( # noqa: C901
dev_reg, entry.entry_id
)
known_devices = [
dev_reg.async_get_device({get_device_id(client, node)})
dev_reg.async_get_device({get_device_id(driver, node)})
for node in driver.controller.nodes.values()
]

View File

@ -10,6 +10,7 @@ from zwave_js_server.const.command_class.lock import DOOR_STATUS_PROPERTY
from zwave_js_server.const.command_class.notification import (
CC_SPECIFIC_NOTIFICATION_TYPE,
)
from zwave_js_server.model.driver import Driver
from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR_DOMAIN,
@ -267,6 +268,8 @@ async def async_setup_entry(
@callback
def async_add_binary_sensor(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Binary Sensor."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[BinarySensorEntity] = []
if info.platform_hint == "notification":
@ -298,7 +301,7 @@ async def async_setup_entry(
entities.append(
ZWaveNotificationBinarySensor(
config_entry, client, info, state_key, notification_description
config_entry, driver, info, state_key, notification_description
)
)
elif info.platform_hint == "property" and (
@ -308,12 +311,12 @@ async def async_setup_entry(
):
entities.append(
ZWavePropertyBinarySensor(
config_entry, client, info, property_description
config_entry, driver, info, property_description
)
)
else:
# boolean sensor
entities.append(ZWaveBooleanBinarySensor(config_entry, client, info))
entities.append(ZWaveBooleanBinarySensor(config_entry, driver, info))
async_add_entities(entities)
@ -332,11 +335,11 @@ class ZWaveBooleanBinarySensor(ZWaveBaseEntity, BinarySensorEntity):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
) -> None:
"""Initialize a ZWaveBooleanBinarySensor entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
# Entity class attributes
self._attr_name = self.generate_name(include_value_name=True)
@ -359,13 +362,13 @@ class ZWaveNotificationBinarySensor(ZWaveBaseEntity, BinarySensorEntity):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
state_key: str,
description: NotificationZWaveJSEntityDescription | None = None,
) -> None:
"""Initialize a ZWaveNotificationBinarySensor entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self.state_key = state_key
if description:
self.entity_description = description
@ -394,12 +397,12 @@ class ZWavePropertyBinarySensor(ZWaveBaseEntity, BinarySensorEntity):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
description: PropertyZWaveJSEntityDescription,
) -> None:
"""Initialize a ZWavePropertyBinarySensor entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self.entity_description = description
self._attr_name = self.generate_name(include_value_name=True)

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.node import Node as ZwaveNode
from homeassistant.components.button import ButtonEntity
@ -28,7 +29,9 @@ async def async_setup_entry(
@callback
def async_add_ping_button_entity(node: ZwaveNode) -> None:
"""Add ping button entity."""
async_add_entities([ZWaveNodePingButton(client, node)])
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
async_add_entities([ZWaveNodePingButton(driver, node)])
config_entry.async_on_unload(
async_dispatcher_connect(
@ -45,7 +48,7 @@ class ZWaveNodePingButton(ButtonEntity):
_attr_should_poll = False
_attr_entity_category = EntityCategory.CONFIG
def __init__(self, client: ZwaveClient, node: ZwaveNode) -> None:
def __init__(self, driver: Driver, node: ZwaveNode) -> None:
"""Initialize a ping Z-Wave device button entity."""
self.node = node
name: str = (
@ -53,11 +56,11 @@ class ZWaveNodePingButton(ButtonEntity):
)
# Entity class attributes
self._attr_name = f"{name}: Ping"
self._base_unique_id = get_valueless_base_unique_id(client, node)
self._base_unique_id = get_valueless_base_unique_id(driver, node)
self._attr_unique_id = f"{self._base_unique_id}.ping"
# device is precreated in main handler
self._attr_device_info = DeviceInfo(
identifiers={get_device_id(client, node)},
identifiers={get_device_id(driver, node)},
)
async def async_poll_value(self, _: bool) -> None:

View File

@ -17,6 +17,7 @@ from zwave_js_server.const.command_class.thermostat import (
ThermostatOperatingState,
ThermostatSetpointType,
)
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.value import Value as ZwaveValue
from homeassistant.components.climate import (
@ -103,11 +104,13 @@ async def async_setup_entry(
@callback
def async_add_climate(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Climate."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "dynamic_current_temp":
entities.append(DynamicCurrentTempClimate(config_entry, client, info))
entities.append(DynamicCurrentTempClimate(config_entry, driver, info))
else:
entities.append(ZWaveClimate(config_entry, client, info))
entities.append(ZWaveClimate(config_entry, driver, info))
async_add_entities(entities)
@ -124,10 +127,10 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
"""Representation of a Z-Wave climate."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize thermostat."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._hvac_modes: dict[HVACMode, int | None] = {}
self._hvac_presets: dict[str, int | None] = {}
self._unit_value: ZwaveValue | None = None
@ -479,10 +482,10 @@ class DynamicCurrentTempClimate(ZWaveClimate):
"""Representation of a thermostat that can dynamically use a different Zwave Value for current temp."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize thermostat."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self.data_template = cast(
DynamicCurrentTempClimateDataTemplate, self.info.platform_data_template
)

View File

@ -15,6 +15,7 @@ from zwave_js_server.const.command_class.multilevel_switch import (
COVER_OPEN_PROPERTY,
COVER_UP_PROPERTY,
)
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.value import Value as ZwaveValue
from homeassistant.components.cover import (
@ -51,13 +52,15 @@ async def async_setup_entry(
@callback
def async_add_cover(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave cover."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "motorized_barrier":
entities.append(ZwaveMotorizedBarrier(config_entry, client, info))
entities.append(ZwaveMotorizedBarrier(config_entry, driver, info))
elif info.platform_hint == "window_shutter_tilt":
entities.append(ZWaveTiltCover(config_entry, client, info))
entities.append(ZWaveTiltCover(config_entry, driver, info))
else:
entities.append(ZWaveCover(config_entry, client, info))
entities.append(ZWaveCover(config_entry, driver, info))
async_add_entities(entities)
config_entry.async_on_unload(
@ -105,11 +108,11 @@ class ZWaveCover(ZWaveBaseEntity, CoverEntity):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
) -> None:
"""Initialize a ZWaveCover entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
# Entity class attributes
self._attr_device_class = CoverDeviceClass.WINDOW
@ -188,11 +191,11 @@ class ZWaveTiltCover(ZWaveCover):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
) -> None:
"""Initialize a ZWaveCover entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self.data_template = cast(
CoverTiltDataTemplate, self.info.platform_data_template
)
@ -233,11 +236,11 @@ class ZwaveMotorizedBarrier(ZWaveBaseEntity, CoverEntity):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
) -> None:
"""Initialize a ZwaveMotorizedBarrier entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._target_state: ZwaveValue = self.get_zwave_value(
TARGET_STATE_PROPERTY, add_to_watched_value_ids=False
)

View File

@ -3,8 +3,8 @@ from __future__ import annotations
import logging
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import NodeStatus
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.value import Value as ZwaveValue, get_value_id
from homeassistant.config_entries import ConfigEntry
@ -30,11 +30,11 @@ class ZWaveBaseEntity(Entity):
_attr_should_poll = False
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize a generic Z-Wave device entity."""
self.config_entry = config_entry
self.client = client
self.driver = driver
self.info = info
# entities requiring additional values, can add extra ids to this list
self.watched_value_ids = {self.info.primary_value.value_id}
@ -46,16 +46,14 @@ class ZWaveBaseEntity(Entity):
# Entity class attributes
self._attr_name = self.generate_name()
self._attr_unique_id = get_unique_id(
self.client, self.info.primary_value.value_id
)
self._attr_unique_id = get_unique_id(driver, self.info.primary_value.value_id)
self._attr_entity_registry_enabled_default = (
self.info.entity_registry_enabled_default
)
self._attr_assumed_state = self.info.assumed_state
# device is precreated in main handler
self._attr_device_info = DeviceInfo(
identifiers={get_device_id(self.client, self.info.node)},
identifiers={get_device_id(driver, self.info.node)},
)
@callback
@ -145,7 +143,10 @@ class ZWaveBaseEntity(Entity):
if item:
name += f" - {item}"
# append endpoint if > 1
if self.info.primary_value.endpoint > 1:
if (
self.info.primary_value.endpoint is not None
and self.info.primary_value.endpoint > 1
):
name += f" ({self.info.primary_value.endpoint})"
return name
@ -154,7 +155,7 @@ class ZWaveBaseEntity(Entity):
def available(self) -> bool:
"""Return entity availability."""
return (
self.client.connected
self.driver.client.connected
and bool(self.info.node.ready)
and self.info.node.status != NodeStatus.DEAD
)

View File

@ -10,6 +10,7 @@ from zwave_js_server.const.command_class.thermostat import (
THERMOSTAT_FAN_OFF_PROPERTY,
THERMOSTAT_FAN_STATE_PROPERTY,
)
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.value import Value as ZwaveValue
from homeassistant.components.fan import (
@ -53,13 +54,15 @@ async def async_setup_entry(
@callback
def async_add_fan(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave fan."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "has_fan_value_mapping":
entities.append(ValueMappingZwaveFan(config_entry, client, info))
entities.append(ValueMappingZwaveFan(config_entry, driver, info))
elif info.platform_hint == "thermostat_fan":
entities.append(ZwaveThermostatFan(config_entry, client, info))
entities.append(ZwaveThermostatFan(config_entry, driver, info))
else:
entities.append(ZwaveFan(config_entry, client, info))
entities.append(ZwaveFan(config_entry, driver, info))
async_add_entities(entities)
@ -78,10 +81,10 @@ class ZwaveFan(ZWaveBaseEntity, FanEntity):
_attr_supported_features = FanEntityFeature.SET_SPEED
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize the fan."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._target_value = self.get_zwave_value(TARGET_VALUE_PROPERTY)
async def async_set_percentage(self, percentage: int) -> None:
@ -147,10 +150,10 @@ class ValueMappingZwaveFan(ZwaveFan):
"""A Zwave fan with a value mapping data (e.g., 1-24 is low)."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize the fan."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self.data_template = cast(
FanValueMappingDataTemplate, self.info.platform_data_template
)
@ -300,10 +303,10 @@ class ZwaveThermostatFan(ZWaveBaseEntity, FanEntity):
_fan_state: ZwaveValue | None = None
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize the thermostat fan."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._fan_mode = self.info.primary_value

View File

@ -110,29 +110,29 @@ def update_data_collection_preference(
@callback
def get_valueless_base_unique_id(client: ZwaveClient, node: ZwaveNode) -> str:
def get_valueless_base_unique_id(driver: Driver, node: ZwaveNode) -> str:
"""Return the base unique ID for an entity that is not based on a value."""
return f"{client.driver.controller.home_id}.{node.node_id}"
return f"{driver.controller.home_id}.{node.node_id}"
def get_unique_id(client: ZwaveClient, value_id: str) -> str:
def get_unique_id(driver: Driver, value_id: str) -> str:
"""Get unique ID from client and value ID."""
return f"{client.driver.controller.home_id}.{value_id}"
return f"{driver.controller.home_id}.{value_id}"
@callback
def get_device_id(client: ZwaveClient, node: ZwaveNode) -> tuple[str, str]:
def get_device_id(driver: Driver, node: ZwaveNode) -> tuple[str, str]:
"""Get device registry identifier for Z-Wave node."""
return (DOMAIN, f"{client.driver.controller.home_id}-{node.node_id}")
return (DOMAIN, f"{driver.controller.home_id}-{node.node_id}")
@callback
def get_device_id_ext(client: ZwaveClient, node: ZwaveNode) -> tuple[str, str] | None:
def get_device_id_ext(driver: Driver, node: ZwaveNode) -> tuple[str, str] | None:
"""Get extended device registry identifier for Z-Wave node."""
if None in (node.manufacturer_id, node.product_type, node.product_id):
return None
domain, dev_id = get_device_id(client, node)
domain, dev_id = get_device_id(driver, node)
return (
domain,
f"{dev_id}-{node.manufacturer_id}:{node.product_type}:{node.product_id}",

View File

@ -11,6 +11,7 @@ from zwave_js_server.const.command_class.humidity_control import (
HumidityControlMode,
HumidityControlSetpointType,
)
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.value import Value as ZwaveValue
from homeassistant.components.humidifier import (
@ -85,6 +86,8 @@ async def async_setup_entry(
@callback
def async_add_humidifier(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Humidifier."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
if (
@ -93,7 +96,7 @@ async def async_setup_entry(
):
entities.append(
ZWaveHumidifier(
config_entry, client, info, HUMIDIFIER_ENTITY_DESCRIPTION
config_entry, driver, info, HUMIDIFIER_ENTITY_DESCRIPTION
)
)
@ -103,7 +106,7 @@ async def async_setup_entry(
):
entities.append(
ZWaveHumidifier(
config_entry, client, info, DEHUMIDIFIER_ENTITY_DESCRIPTION
config_entry, driver, info, DEHUMIDIFIER_ENTITY_DESCRIPTION
)
)
@ -128,12 +131,12 @@ class ZWaveHumidifier(ZWaveBaseEntity, HumidifierEntity):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
description: ZwaveHumidifierEntityDescription,
) -> None:
"""Initialize humidifier."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self.entity_description = description

View File

@ -23,6 +23,7 @@ from zwave_js_server.const.command_class.color_switch import (
TARGET_COLOR_PROPERTY,
ColorComponent,
)
from zwave_js_server.model.driver import Driver
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
@ -72,11 +73,13 @@ async def async_setup_entry(
@callback
def async_add_light(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Light."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
if info.platform_hint == "black_is_off":
async_add_entities([ZwaveBlackIsOffLight(config_entry, client, info)])
async_add_entities([ZwaveBlackIsOffLight(config_entry, driver, info)])
else:
async_add_entities([ZwaveLight(config_entry, client, info)])
async_add_entities([ZwaveLight(config_entry, driver, info)])
config_entry.async_on_unload(
async_dispatcher_connect(
@ -101,10 +104,10 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity):
"""Representation of a Z-Wave light."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize the light."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._supports_color = False
self._supports_rgbw = False
self._supports_color_temp = False
@ -445,10 +448,10 @@ class ZwaveBlackIsOffLight(ZwaveLight):
"""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize the light."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._last_color: dict[str, int] | None = None
self._supported_color_modes.discard(ColorMode.BRIGHTNESS)

View File

@ -61,8 +61,10 @@ async def async_setup_entry(
@callback
def async_add_lock(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Lock."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
entities.append(ZWaveLock(config_entry, client, info))
entities.append(ZWaveLock(config_entry, driver, info))
async_add_entities(entities)

View File

@ -4,7 +4,7 @@ from __future__ import annotations
from dataclasses import dataclass
import logging
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.value import Value as ZwaveValue
from homeassistant.const import STATE_UNAVAILABLE
@ -138,12 +138,12 @@ def async_migrate_discovered_value(
ent_reg: EntityRegistry,
registered_unique_ids: set[str],
device: DeviceEntry,
client: ZwaveClient,
driver: Driver,
disc_info: ZwaveDiscoveryInfo,
) -> None:
"""Migrate unique ID for entity/entities tied to discovered value."""
new_unique_id = get_unique_id(client, disc_info.primary_value.value_id)
new_unique_id = get_unique_id(driver, disc_info.primary_value.value_id)
# On reinterviews, there is no point in going through this logic again for already
# discovered values
@ -155,7 +155,7 @@ def async_migrate_discovered_value(
# 2021.2.*, 2021.3.0b0, and 2021.3.0 formats
old_unique_ids = [
get_unique_id(client, value_id)
get_unique_id(driver, value_id)
for value_id in get_old_value_ids(disc_info.primary_value)
]

View File

@ -3,6 +3,7 @@ from __future__ import annotations
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import TARGET_VALUE_PROPERTY
from zwave_js_server.model.driver import Driver
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN, NumberEntity
from homeassistant.config_entries import ConfigEntry
@ -28,11 +29,13 @@ async def async_setup_entry(
@callback
def async_add_number(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave number entity."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "volume":
entities.append(ZwaveVolumeNumberEntity(config_entry, client, info))
entities.append(ZwaveVolumeNumberEntity(config_entry, driver, info))
else:
entities.append(ZwaveNumberEntity(config_entry, client, info))
entities.append(ZwaveNumberEntity(config_entry, driver, info))
async_add_entities(entities)
config_entry.async_on_unload(
@ -48,10 +51,10 @@ class ZwaveNumberEntity(ZWaveBaseEntity, NumberEntity):
"""Representation of a Z-Wave number entity."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize a ZwaveNumberEntity entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
if self.info.primary_value.metadata.writeable:
self._target_value = self.info.primary_value
else:
@ -99,10 +102,10 @@ class ZwaveVolumeNumberEntity(ZWaveBaseEntity, NumberEntity):
"""Representation of a volume number entity."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize a ZwaveVolumeNumberEntity entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self.correction_factor = int(
self.info.primary_value.metadata.max - self.info.primary_value.metadata.min
)

View File

@ -6,6 +6,7 @@ from typing import cast
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import TARGET_VALUE_PROPERTY, CommandClass
from zwave_js_server.const.command_class.sound_switch import ToneID
from zwave_js_server.model.driver import Driver
from homeassistant.components.select import DOMAIN as SELECT_DOMAIN, SelectEntity
from homeassistant.config_entries import ConfigEntry
@ -32,15 +33,17 @@ async def async_setup_entry(
@callback
def async_add_select(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave select entity."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "Default tone":
entities.append(ZwaveDefaultToneSelectEntity(config_entry, client, info))
entities.append(ZwaveDefaultToneSelectEntity(config_entry, driver, info))
elif info.platform_hint == "multilevel_switch":
entities.append(
ZwaveMultilevelSwitchSelectEntity(config_entry, client, info)
ZwaveMultilevelSwitchSelectEntity(config_entry, driver, info)
)
else:
entities.append(ZwaveSelectEntity(config_entry, client, info))
entities.append(ZwaveSelectEntity(config_entry, driver, info))
async_add_entities(entities)
config_entry.async_on_unload(
@ -58,10 +61,10 @@ class ZwaveSelectEntity(ZWaveBaseEntity, SelectEntity):
_attr_entity_category = EntityCategory.CONFIG
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize a ZwaveSelectEntity entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
# Entity class attributes
self._attr_name = self.generate_name(include_value_name=True)
@ -94,10 +97,10 @@ class ZwaveDefaultToneSelectEntity(ZWaveBaseEntity, SelectEntity):
_attr_entity_category = EntityCategory.CONFIG
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize a ZwaveDefaultToneSelectEntity entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._tones_value = self.get_zwave_value(
"toneId", command_class=CommandClass.SOUND_SWITCH
)
@ -145,10 +148,10 @@ class ZwaveMultilevelSwitchSelectEntity(ZWaveBaseEntity, SelectEntity):
"""Representation of a Z-Wave Multilevel Switch CC select entity."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize a ZwaveSelectEntity entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._target_value = self.get_zwave_value(TARGET_VALUE_PROPERTY)
assert self.info.platform_data_template
self._lookup_map = cast(

View File

@ -12,6 +12,7 @@ from zwave_js_server.const.command_class.meter import (
RESET_METER_OPTION_TARGET_VALUE,
RESET_METER_OPTION_TYPE,
)
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.node import Node as ZwaveNode
from zwave_js_server.model.value import ConfigurationValue
from zwave_js_server.util.command_class.meter import get_meter_type
@ -179,6 +180,8 @@ async def async_setup_entry(
@callback
def async_add_sensor(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Sensor."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
if info.platform_data:
@ -191,13 +194,13 @@ async def async_setup_entry(
if info.platform_hint == "string_sensor":
entities.append(
ZWaveStringSensor(config_entry, client, info, entity_description)
ZWaveStringSensor(config_entry, driver, info, entity_description)
)
elif info.platform_hint == "numeric_sensor":
entities.append(
ZWaveNumericSensor(
config_entry,
client,
driver,
info,
entity_description,
data.unit_of_measurement,
@ -205,17 +208,17 @@ async def async_setup_entry(
)
elif info.platform_hint == "list_sensor":
entities.append(
ZWaveListSensor(config_entry, client, info, entity_description)
ZWaveListSensor(config_entry, driver, info, entity_description)
)
elif info.platform_hint == "config_parameter":
entities.append(
ZWaveConfigParameterSensor(
config_entry, client, info, entity_description
config_entry, driver, info, entity_description
)
)
elif info.platform_hint == "meter":
entities.append(
ZWaveMeterSensor(config_entry, client, info, entity_description)
ZWaveMeterSensor(config_entry, driver, info, entity_description)
)
else:
LOGGER.warning(
@ -230,7 +233,9 @@ async def async_setup_entry(
@callback
def async_add_node_status_sensor(node: ZwaveNode) -> None:
"""Add node status sensor."""
async_add_entities([ZWaveNodeStatusSensor(config_entry, client, node)])
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
async_add_entities([ZWaveNodeStatusSensor(config_entry, driver, node)])
config_entry.async_on_unload(
async_dispatcher_connect(
@ -265,13 +270,13 @@ class ZwaveSensorBase(ZWaveBaseEntity, SensorEntity):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
entity_description: SensorEntityDescription,
unit_of_measurement: str | None = None,
) -> None:
"""Initialize a ZWaveSensorBase entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self.entity_description = entity_description
self._attr_native_unit_of_measurement = unit_of_measurement
@ -370,14 +375,14 @@ class ZWaveListSensor(ZwaveSensorBase):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
entity_description: SensorEntityDescription,
unit_of_measurement: str | None = None,
) -> None:
"""Initialize a ZWaveListSensor entity."""
super().__init__(
config_entry, client, info, entity_description, unit_of_measurement
config_entry, driver, info, entity_description, unit_of_measurement
)
# Entity class attributes
@ -414,14 +419,14 @@ class ZWaveConfigParameterSensor(ZwaveSensorBase):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
entity_description: SensorEntityDescription,
unit_of_measurement: str | None = None,
) -> None:
"""Initialize a ZWaveConfigParameterSensor entity."""
super().__init__(
config_entry, client, info, entity_description, unit_of_measurement
config_entry, driver, info, entity_description, unit_of_measurement
)
self._primary_value = cast(ConfigurationValue, self.info.primary_value)
@ -466,11 +471,10 @@ class ZWaveNodeStatusSensor(SensorEntity):
_attr_entity_category = EntityCategory.DIAGNOSTIC
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, node: ZwaveNode
self, config_entry: ConfigEntry, driver: Driver, node: ZwaveNode
) -> None:
"""Initialize a generic Z-Wave device entity."""
self.config_entry = config_entry
self.client = client
self.node = node
name: str = (
self.node.name
@ -479,11 +483,11 @@ class ZWaveNodeStatusSensor(SensorEntity):
)
# Entity class attributes
self._attr_name = f"{name}: Node Status"
self._base_unique_id = get_valueless_base_unique_id(client, node)
self._base_unique_id = get_valueless_base_unique_id(driver, node)
self._attr_unique_id = f"{self._base_unique_id}.node_status"
# device is precreated in main handler
self._attr_device_info = DeviceInfo(
identifiers={get_device_id(self.client, self.node)},
identifiers={get_device_id(driver, self.node)},
)
self._attr_native_value: str = node.status.name.lower()

View File

@ -5,6 +5,7 @@ from typing import Any
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const.command_class.sound_switch import ToneID
from zwave_js_server.model.driver import Driver
from homeassistant.components.siren import (
DOMAIN as SIREN_DOMAIN,
@ -35,8 +36,10 @@ async def async_setup_entry(
@callback
def async_add_siren(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave siren entity."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
entities.append(ZwaveSirenEntity(config_entry, client, info))
entities.append(ZwaveSirenEntity(config_entry, driver, info))
async_add_entities(entities)
config_entry.async_on_unload(
@ -52,10 +55,10 @@ class ZwaveSirenEntity(ZWaveBaseEntity, SirenEntity):
"""Representation of a Z-Wave siren entity."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize a ZwaveSirenEntity entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
# Entity class attributes
self._attr_available_tones = {
int(id): val for id, val in self.info.primary_value.metadata.states.items()

View File

@ -9,6 +9,7 @@ from zwave_js_server.const import TARGET_VALUE_PROPERTY
from zwave_js_server.const.command_class.barrier_operator import (
BarrierEventSignalingSubsystemState,
)
from zwave_js_server.model.driver import Driver
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN, SwitchEntity
from homeassistant.config_entries import ConfigEntry
@ -36,13 +37,15 @@ async def async_setup_entry(
@callback
def async_add_switch(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Switch."""
driver = client.driver
assert driver is not None # Driver is ready before platforms are loaded.
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "barrier_event_signaling_state":
entities.append(
ZWaveBarrierEventSignalingSwitch(config_entry, client, info)
ZWaveBarrierEventSignalingSwitch(config_entry, driver, info)
)
else:
entities.append(ZWaveSwitch(config_entry, client, info))
entities.append(ZWaveSwitch(config_entry, driver, info))
async_add_entities(entities)
@ -59,10 +62,10 @@ class ZWaveSwitch(ZWaveBaseEntity, SwitchEntity):
"""Representation of a Z-Wave switch."""
def __init__(
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
) -> None:
"""Initialize the switch."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._target_value = self.get_zwave_value(TARGET_VALUE_PROPERTY)
@ -91,11 +94,11 @@ class ZWaveBarrierEventSignalingSwitch(ZWaveBaseEntity, SwitchEntity):
def __init__(
self,
config_entry: ConfigEntry,
client: ZwaveClient,
driver: Driver,
info: ZwaveDiscoveryInfo,
) -> None:
"""Initialize a ZWaveBarrierEventSignalingSwitch entity."""
super().__init__(config_entry, client, info)
super().__init__(config_entry, driver, info)
self._state: bool | None = None
self._update_state()

View File

@ -207,7 +207,9 @@ async def async_attach_trigger(
unsubs.append(source.on(event_name, async_on_event))
for node in nodes:
device_identifier = get_device_id(node.client, node)
driver = node.client.driver
assert driver is not None # The node comes from the driver.
device_identifier = get_device_id(driver, node)
device = dev_reg.async_get_device({device_identifier})
assert device
# We need to store the device for the callback

View File

@ -162,7 +162,9 @@ async def async_attach_trigger(
dev_reg = dr.async_get(hass)
for node in nodes:
device_identifier = get_device_id(node.client, node)
driver = node.client.driver
assert driver is not None # The node comes from the driver.
device_identifier = get_device_id(driver, node)
device = dev_reg.async_get_device({device_identifier})
assert device
value_id = get_value_id(node, command_class, property_, endpoint, property_key)

View File

@ -78,7 +78,7 @@ from homeassistant.helpers import device_registry as dr
def get_device(hass, node):
"""Get device ID for a node."""
dev_reg = dr.async_get(hass)
device_id = get_device_id(node.client, node)
device_id = get_device_id(node.client.driver, node)
return dev_reg.async_get_device({device_id})
@ -124,11 +124,12 @@ async def test_node_ready(
node_data = deepcopy(multisensor_6_state) # Copy to allow modification in tests.
node = Node(client, node_data)
node.data["ready"] = False
client.driver.controller.nodes[node.node_id] = node
driver = client.driver
driver.controller.nodes[node.node_id] = node
dev_reg = dr.async_get(hass)
device = dev_reg.async_get_or_create(
config_entry_id=entry.entry_id, identifiers={get_device_id(client, node)}
config_entry_id=entry.entry_id, identifiers={get_device_id(driver, node)}
)
await ws_client.send_json(

View File

@ -49,11 +49,12 @@ async def test_ping_entity(
assert "There is no value to refresh for this entity" in caplog.text
# Assert a node ping button entity is not created for the controller
node = client.driver.controller.nodes[1]
driver = client.driver
node = driver.controller.nodes[1]
assert node.is_controller_node
assert (
async_get(hass).async_get_entity_id(
DOMAIN, "sensor", f"{get_valueless_base_unique_id(client, node)}.ping"
DOMAIN, "sensor", f"{get_valueless_base_unique_id(driver, node)}.ping"
)
is None
)

View File

@ -30,7 +30,9 @@ async def test_get_actions(
"""Test we get the expected actions from a zwave_js node."""
node = lock_schlage_be469
dev_reg = device_registry.async_get(hass)
device = dev_reg.async_get_device({get_device_id(client, node)})
driver = client.driver
assert driver
device = dev_reg.async_get_device({get_device_id(driver, node)})
assert device
expected_actions = [
{
@ -99,7 +101,9 @@ async def test_get_actions_meter(
"""Test we get the expected meter actions from a zwave_js node."""
node = aeon_smart_switch_6
dev_reg = device_registry.async_get(hass)
device = dev_reg.async_get_device({get_device_id(client, node)})
driver = client.driver
assert driver
device = dev_reg.async_get_device({get_device_id(driver, node)})
assert device
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device.id
@ -116,7 +120,9 @@ async def test_actions(
) -> None:
"""Test actions."""
node = climate_radio_thermostat_ct100_plus
device_id = get_device_id(client, node)
driver = client.driver
assert driver
device_id = get_device_id(driver, node)
dev_reg = device_registry.async_get(hass)
device = dev_reg.async_get_device({device_id})
assert device
@ -236,7 +242,9 @@ async def test_actions_multiple_calls(
) -> None:
"""Test actions can be called multiple times and still work."""
node = climate_radio_thermostat_ct100_plus
device_id = get_device_id(client, node)
driver = client.driver
assert driver
device_id = get_device_id(driver, node)
dev_reg = device_registry.async_get(hass)
device = dev_reg.async_get_device({device_id})
assert device
@ -281,7 +289,9 @@ async def test_lock_actions(
) -> None:
"""Test actions for locks."""
node = lock_schlage_be469
device_id = get_device_id(client, node)
driver = client.driver
assert driver
device_id = get_device_id(driver, node)
dev_reg = device_registry.async_get(hass)
device = dev_reg.async_get_device({device_id})
assert device
@ -350,7 +360,9 @@ async def test_reset_meter_action(
) -> None:
"""Test reset_meter action."""
node = aeon_smart_switch_6
device_id = get_device_id(client, node)
driver = client.driver
assert driver
device_id = get_device_id(driver, node)
dev_reg = device_registry.async_get(hass)
device = dev_reg.async_get_device({device_id})
assert device
@ -613,7 +625,9 @@ async def test_get_action_capabilities_meter_triggers(
"""Test we get the expected action capabilities for meter triggers."""
node = aeon_smart_switch_6
dev_reg = device_registry.async_get(hass)
device = dev_reg.async_get_device({get_device_id(client, node)})
driver = client.driver
assert driver
device = dev_reg.async_get_device({get_device_id(driver, node)})
assert device
capabilities = await device_action.async_get_action_capabilities(
hass,
@ -669,7 +683,9 @@ async def test_unavailable_entity_actions(
await hass.async_block_till_done()
node = lock_schlage_be469
dev_reg = device_registry.async_get(hass)
device = dev_reg.async_get_device({get_device_id(client, node)})
driver = client.driver
assert driver
device = dev_reg.async_get_device({get_device_id(driver, node)})
assert device
actions = await async_get_device_automations(
hass, DeviceAutomationType.ACTION, device.id

View File

@ -51,7 +51,7 @@ async def test_device_diagnostics(
):
"""Test the device level diagnostics data dump."""
dev_reg = async_get(hass)
device = dev_reg.async_get_device({get_device_id(client, multisensor_6)})
device = dev_reg.async_get_device({get_device_id(client.driver, multisensor_6)})
assert device
# Update a value and ensure it is reflected in the node state

View File

@ -800,8 +800,10 @@ async def test_removed_device(
hass, client, climate_radio_thermostat_ct100_plus, lock_schlage_be469, integration
):
"""Test that the device registry gets updated when a device gets removed."""
driver = client.driver
assert driver
# Verify how many nodes are available
assert len(client.driver.controller.nodes) == 2
assert len(driver.controller.nodes) == 2
# Make sure there are the same number of devices
dev_reg = dr.async_get(hass)
@ -814,7 +816,7 @@ async def test_removed_device(
assert len(entity_entries) == 29
# Remove a node and reload the entry
old_node = client.driver.controller.nodes.pop(13)
old_node = driver.controller.nodes.pop(13)
await hass.config_entries.async_reload(integration.entry_id)
await hass.async_block_till_done()
@ -824,7 +826,7 @@ async def test_removed_device(
assert len(device_entries) == 1
entity_entries = er.async_entries_for_config_entry(ent_reg, integration.entry_id)
assert len(entity_entries) == 17
assert dev_reg.async_get_device({get_device_id(client, old_node)}) is None
assert dev_reg.async_get_device({get_device_id(driver, old_node)}) is None
async def test_suggested_area(hass, client, eaton_rf9640_dimmer):

View File

@ -190,12 +190,14 @@ async def test_old_entity_migration(
):
"""Test old entity on a different endpoint is migrated to a new one."""
node = Node(client, copy.deepcopy(hank_binary_switch_state))
driver = client.driver
assert driver
ent_reg = er.async_get(hass)
dev_reg = dr.async_get(hass)
device = dev_reg.async_get_or_create(
config_entry_id=integration.entry_id,
identifiers={get_device_id(client, node)},
identifiers={get_device_id(driver, node)},
manufacturer=hank_binary_switch_state["deviceConfig"]["manufacturer"],
model=hank_binary_switch_state["deviceConfig"]["label"],
)
@ -204,7 +206,7 @@ async def test_old_entity_migration(
entity_name = SENSOR_NAME.split(".")[1]
# Create entity RegistryEntry using fake endpoint
old_unique_id = f"{client.driver.controller.home_id}.32-50-1-value-66049"
old_unique_id = f"{driver.controller.home_id}.32-50-1-value-66049"
entity_entry = ent_reg.async_get_or_create(
"sensor",
DOMAIN,
@ -221,7 +223,7 @@ async def test_old_entity_migration(
for i in range(0, 2):
# Add a ready node, unique ID should be migrated
event = {"node": node}
client.driver.controller.emit("node added", event)
driver.controller.emit("node added", event)
await hass.async_block_till_done()
# Check that new RegistryEntry is using new unique ID format
@ -236,12 +238,14 @@ async def test_different_endpoint_migration_status_sensor(
):
"""Test that the different endpoint migration logic skips over the status sensor."""
node = Node(client, copy.deepcopy(hank_binary_switch_state))
driver = client.driver
assert driver
ent_reg = er.async_get(hass)
dev_reg = dr.async_get(hass)
device = dev_reg.async_get_or_create(
config_entry_id=integration.entry_id,
identifiers={get_device_id(client, node)},
identifiers={get_device_id(driver, node)},
manufacturer=hank_binary_switch_state["deviceConfig"]["manufacturer"],
model=hank_binary_switch_state["deviceConfig"]["label"],
)
@ -250,7 +254,7 @@ async def test_different_endpoint_migration_status_sensor(
entity_name = SENSOR_NAME.split(".")[1]
# Create entity RegistryEntry using fake endpoint
old_unique_id = f"{client.driver.controller.home_id}.32.node_status"
old_unique_id = f"{driver.controller.home_id}.32.node_status"
entity_entry = ent_reg.async_get_or_create(
"sensor",
DOMAIN,
@ -267,7 +271,7 @@ async def test_different_endpoint_migration_status_sensor(
for i in range(0, 2):
# Add a ready node, unique ID should be migrated
event = {"node": node}
client.driver.controller.emit("node added", event)
driver.controller.emit("node added", event)
await hass.async_block_till_done()
# Check that the RegistryEntry is using the same unique ID
@ -280,12 +284,14 @@ async def test_skip_old_entity_migration_for_multiple(
):
"""Test that multiple entities of the same value but on a different endpoint get skipped."""
node = Node(client, copy.deepcopy(hank_binary_switch_state))
driver = client.driver
assert driver
ent_reg = er.async_get(hass)
dev_reg = dr.async_get(hass)
device = dev_reg.async_get_or_create(
config_entry_id=integration.entry_id,
identifiers={get_device_id(client, node)},
identifiers={get_device_id(driver, node)},
manufacturer=hank_binary_switch_state["deviceConfig"]["manufacturer"],
model=hank_binary_switch_state["deviceConfig"]["label"],
)
@ -294,7 +300,7 @@ async def test_skip_old_entity_migration_for_multiple(
entity_name = SENSOR_NAME.split(".")[1]
# Create two entity entrrys using different endpoints
old_unique_id_1 = f"{client.driver.controller.home_id}.32-50-1-value-66049"
old_unique_id_1 = f"{driver.controller.home_id}.32-50-1-value-66049"
entity_entry = ent_reg.async_get_or_create(
"sensor",
DOMAIN,
@ -308,7 +314,7 @@ async def test_skip_old_entity_migration_for_multiple(
assert entity_entry.unique_id == old_unique_id_1
# Create two entity entrrys using different endpoints
old_unique_id_2 = f"{client.driver.controller.home_id}.32-50-2-value-66049"
old_unique_id_2 = f"{driver.controller.home_id}.32-50-2-value-66049"
entity_entry = ent_reg.async_get_or_create(
"sensor",
DOMAIN,
@ -322,12 +328,12 @@ async def test_skip_old_entity_migration_for_multiple(
assert entity_entry.unique_id == old_unique_id_2
# Add a ready node, unique ID should be migrated
event = {"node": node}
client.driver.controller.emit("node added", event)
driver.controller.emit("node added", event)
await hass.async_block_till_done()
# Check that new RegistryEntry is created using new unique ID format
entity_entry = ent_reg.async_get(SENSOR_NAME)
new_unique_id = f"{client.driver.controller.home_id}.32-50-0-value-66049"
new_unique_id = f"{driver.controller.home_id}.32-50-0-value-66049"
assert entity_entry.unique_id == new_unique_id
# Check that the old entities stuck around because we skipped the migration step
@ -340,12 +346,14 @@ async def test_old_entity_migration_notification_binary_sensor(
):
"""Test old entity on a different endpoint is migrated to a new one for a notification binary sensor."""
node = Node(client, copy.deepcopy(multisensor_6_state))
driver = client.driver
assert driver
ent_reg = er.async_get(hass)
dev_reg = dr.async_get(hass)
device = dev_reg.async_get_or_create(
config_entry_id=integration.entry_id,
identifiers={get_device_id(client, node)},
identifiers={get_device_id(driver, node)},
manufacturer=multisensor_6_state["deviceConfig"]["manufacturer"],
model=multisensor_6_state["deviceConfig"]["label"],
)
@ -353,7 +361,9 @@ async def test_old_entity_migration_notification_binary_sensor(
entity_name = NOTIFICATION_MOTION_BINARY_SENSOR.split(".")[1]
# Create entity RegistryEntry using old unique ID format
old_unique_id = f"{client.driver.controller.home_id}.52-113-1-Home Security-Motion sensor status.8"
old_unique_id = (
f"{driver.controller.home_id}.52-113-1-Home Security-Motion sensor status.8"
)
entity_entry = ent_reg.async_get_or_create(
"binary_sensor",
DOMAIN,
@ -370,12 +380,14 @@ async def test_old_entity_migration_notification_binary_sensor(
for _ in range(0, 2):
# Add a ready node, unique ID should be migrated
event = {"node": node}
client.driver.controller.emit("node added", event)
driver.controller.emit("node added", event)
await hass.async_block_till_done()
# Check that new RegistryEntry is using new unique ID format
entity_entry = ent_reg.async_get(NOTIFICATION_MOTION_BINARY_SENSOR)
new_unique_id = f"{client.driver.controller.home_id}.52-113-0-Home Security-Motion sensor status.8"
new_unique_id = (
f"{driver.controller.home_id}.52-113-0-Home Security-Motion sensor status.8"
)
assert entity_entry.unique_id == new_unique_id
assert (
ent_reg.async_get_entity_id("binary_sensor", DOMAIN, old_unique_id) is None

View File

@ -205,13 +205,14 @@ async def test_node_status_sensor(
assert hass.states.get(NODE_STATUS_ENTITY).state != STATE_UNAVAILABLE
# Assert a node status sensor entity is not created for the controller
node = client.driver.controller.nodes[1]
driver = client.driver
node = driver.controller.nodes[1]
assert node.is_controller_node
assert (
ent_reg.async_get_entity_id(
DOMAIN,
"sensor",
f"{get_valueless_base_unique_id(client, node)}.node_status",
f"{get_valueless_base_unique_id(driver, node)}.node_status",
)
is None
)

View File

@ -1367,11 +1367,11 @@ async def test_multicast_set_value(
# Test using area ID
dev_reg = async_get_dev_reg(hass)
device_eurotronic = dev_reg.async_get_device(
{get_device_id(client, climate_eurotronic_spirit_z)}
{get_device_id(client.driver, climate_eurotronic_spirit_z)}
)
assert device_eurotronic
device_danfoss = dev_reg.async_get_device(
{get_device_id(client, climate_danfoss_lc_13)}
{get_device_id(client.driver, climate_danfoss_lc_13)}
)
assert device_danfoss
area_reg = async_get_area_reg(hass)
@ -1655,11 +1655,15 @@ async def test_ping(
"""Test ping service."""
dev_reg = async_get_dev_reg(hass)
device_radio_thermostat = dev_reg.async_get_device(
{get_device_id(client, climate_radio_thermostat_ct100_plus_different_endpoints)}
{
get_device_id(
client.driver, climate_radio_thermostat_ct100_plus_different_endpoints
)
}
)
assert device_radio_thermostat
device_danfoss = dev_reg.async_get_device(
{get_device_id(client, climate_danfoss_lc_13)}
{get_device_id(client.driver, climate_danfoss_lc_13)}
)
assert device_danfoss
@ -1789,11 +1793,15 @@ async def test_invoke_cc_api(
"""Test invoke_cc_api service."""
dev_reg = async_get_dev_reg(hass)
device_radio_thermostat = dev_reg.async_get_device(
{get_device_id(client, climate_radio_thermostat_ct100_plus_different_endpoints)}
{
get_device_id(
client.driver, climate_radio_thermostat_ct100_plus_different_endpoints
)
}
)
assert device_radio_thermostat
device_danfoss = dev_reg.async_get_device(
{get_device_id(client, climate_danfoss_lc_13)}
{get_device_id(client.driver, climate_danfoss_lc_13)}
)
assert device_danfoss