From 9c784ac62234a6839e5ded31a71744a5dccebcf7 Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Wed, 19 Apr 2023 10:47:07 -0400 Subject: [PATCH] Refactor ZHA (#91476) * rename channel -> cluster handler * remove refs to channels and create endpoint class * remove remaining references to channels * fix filter * take in latest changes from #91403 * missed one * missed a reference --- .coveragerc | 2 +- .../components/zha/alarm_control_panel.py | 38 +- homeassistant/components/zha/binary_sensor.py | 63 +- homeassistant/components/zha/button.py | 38 +- homeassistant/components/zha/climate.py | 62 +- .../components/zha/core/channels/__init__.py | 385 ----- .../components/zha/core/channels/helpers.py | 15 - .../components/zha/core/channels/protocol.py | 113 -- .../base.py => cluster_handlers/__init__.py} | 188 +-- .../closures.py | 28 +- .../{channels => cluster_handlers}/general.py | 241 +-- .../zha/core/cluster_handlers/helpers.py | 15 + .../homeautomation.py | 48 +- .../{channels => cluster_handlers}/hvac.py | 34 +- .../lighting.py | 40 +- .../lightlink.py | 18 +- .../manufacturerspecific.py | 100 +- .../measurement.py | 100 +- .../zha/core/cluster_handlers/protocol.py | 143 ++ .../security.py | 48 +- .../smartenergy.py | 90 +- homeassistant/components/zha/core/const.py | 90 +- .../components/zha/core/decorators.py | 14 +- homeassistant/components/zha/core/device.py | 156 +- .../components/zha/core/discovery.py | 211 +-- homeassistant/components/zha/core/endpoint.py | 220 +++ homeassistant/components/zha/core/gateway.py | 8 +- homeassistant/components/zha/core/group.py | 2 +- homeassistant/components/zha/core/helpers.py | 8 +- .../components/zha/core/registries.py | 162 +- homeassistant/components/zha/cover.py | 75 +- homeassistant/components/zha/device_action.py | 61 +- .../components/zha/device_tracker.py | 16 +- homeassistant/components/zha/entity.py | 32 +- homeassistant/components/zha/fan.py | 65 +- homeassistant/components/zha/light.py | 183 ++- homeassistant/components/zha/lock.py | 42 +- homeassistant/components/zha/number.py | 158 +- homeassistant/components/zha/select.py | 98 +- homeassistant/components/zha/sensor.py | 268 ++-- homeassistant/components/zha/siren.py | 32 +- homeassistant/components/zha/switch.py | 139 +- homeassistant/components/zha/websocket_api.py | 32 +- tests/components/zha/conftest.py | 14 +- tests/components/zha/test_base.py | 8 +- ...t_channels.py => test_cluster_handlers.py} | 340 ++--- tests/components/zha/test_device.py | 60 +- tests/components/zha/test_device_action.py | 8 +- tests/components/zha/test_device_trigger.py | 4 +- tests/components/zha/test_discover.py | 191 ++- tests/components/zha/test_light.py | 28 +- tests/components/zha/test_registries.py | 323 ++-- tests/components/zha/test_sensor.py | 26 +- tests/components/zha/zha_devices_list.py | 1356 ++++++++--------- 54 files changed, 3230 insertions(+), 3009 deletions(-) delete mode 100644 homeassistant/components/zha/core/channels/__init__.py delete mode 100644 homeassistant/components/zha/core/channels/helpers.py delete mode 100644 homeassistant/components/zha/core/channels/protocol.py rename homeassistant/components/zha/core/{channels/base.py => cluster_handlers/__init__.py} (75%) rename homeassistant/components/zha/core/{channels => cluster_handlers}/closures.py (85%) rename homeassistant/components/zha/core/{channels => cluster_handlers}/general.py (67%) create mode 100644 homeassistant/components/zha/core/cluster_handlers/helpers.py rename homeassistant/components/zha/core/{channels => cluster_handlers}/homeautomation.py (78%) rename homeassistant/components/zha/core/{channels => cluster_handlers}/hvac.py (91%) rename homeassistant/components/zha/core/{channels => cluster_handlers}/lighting.py (80%) rename homeassistant/components/zha/core/{channels => cluster_handlers}/lightlink.py (69%) rename homeassistant/components/zha/core/{channels => cluster_handlers}/manufacturerspecific.py (78%) rename homeassistant/components/zha/core/{channels => cluster_handlers}/measurement.py (52%) create mode 100644 homeassistant/components/zha/core/cluster_handlers/protocol.py rename homeassistant/components/zha/core/{channels => cluster_handlers}/security.py (90%) rename homeassistant/components/zha/core/{channels => cluster_handlers}/smartenergy.py (74%) create mode 100644 homeassistant/components/zha/core/endpoint.py rename tests/components/zha/{test_channels.py => test_cluster_handlers.py} (63%) diff --git a/.coveragerc b/.coveragerc index 4481d393be5..84ff641d400 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1509,7 +1509,7 @@ omit = homeassistant/components/zeversolar/entity.py homeassistant/components/zeversolar/sensor.py homeassistant/components/zha/websocket_api.py - homeassistant/components/zha/core/channels/* + homeassistant/components/zha/core/cluster_handlers/* homeassistant/components/zha/core/device.py homeassistant/components/zha/core/gateway.py homeassistant/components/zha/core/helpers.py diff --git a/homeassistant/components/zha/alarm_control_panel.py b/homeassistant/components/zha/alarm_control_panel.py index 6a5e8bb476a..dfb19ac3bad 100644 --- a/homeassistant/components/zha/alarm_control_panel.py +++ b/homeassistant/components/zha/alarm_control_panel.py @@ -25,13 +25,13 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from .core import discovery -from .core.channels.security import ( +from .core.cluster_handlers.security import ( SIGNAL_ALARM_TRIGGERED, SIGNAL_ARMED_STATE_CHANGED, - IasAce as AceChannel, + IasAce as AceClusterHandler, ) from .core.const import ( - CHANNEL_IAS_ACE, + CLUSTER_HANDLER_IAS_ACE, CONF_ALARM_ARM_REQUIRES_CODE, CONF_ALARM_FAILED_TRIES, CONF_ALARM_MASTER_CODE, @@ -77,7 +77,7 @@ async def async_setup_entry( config_entry.async_on_unload(unsub) -@STRICT_MATCH(channel_names=CHANNEL_IAS_ACE) +@STRICT_MATCH(cluster_handler_names=CLUSTER_HANDLER_IAS_ACE) class ZHAAlarmControlPanel(ZhaEntity, AlarmControlPanelEntity): """Entity for ZHA alarm control devices.""" @@ -89,18 +89,20 @@ class ZHAAlarmControlPanel(ZhaEntity, AlarmControlPanelEntity): | AlarmControlPanelEntityFeature.TRIGGER ) - def __init__(self, unique_id, zha_device: ZHADevice, channels, **kwargs) -> None: + def __init__( + self, unique_id, zha_device: ZHADevice, cluster_handlers, **kwargs + ) -> None: """Initialize the ZHA alarm control device.""" - super().__init__(unique_id, zha_device, channels, **kwargs) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) cfg_entry = zha_device.gateway.config_entry - self._channel: AceChannel = channels[0] - self._channel.panel_code = async_get_zha_config_value( + self._cluster_handler: AceClusterHandler = cluster_handlers[0] + self._cluster_handler.panel_code = async_get_zha_config_value( cfg_entry, ZHA_ALARM_OPTIONS, CONF_ALARM_MASTER_CODE, "1234" ) - self._channel.code_required_arm_actions = async_get_zha_config_value( + self._cluster_handler.code_required_arm_actions = async_get_zha_config_value( cfg_entry, ZHA_ALARM_OPTIONS, CONF_ALARM_ARM_REQUIRES_CODE, False ) - self._channel.max_invalid_tries = async_get_zha_config_value( + self._cluster_handler.max_invalid_tries = async_get_zha_config_value( cfg_entry, ZHA_ALARM_OPTIONS, CONF_ALARM_FAILED_TRIES, 3 ) @@ -108,10 +110,10 @@ class ZHAAlarmControlPanel(ZhaEntity, AlarmControlPanelEntity): """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._channel, SIGNAL_ARMED_STATE_CHANGED, self.async_set_armed_mode + self._cluster_handler, SIGNAL_ARMED_STATE_CHANGED, self.async_set_armed_mode ) self.async_accept_signal( - self._channel, SIGNAL_ALARM_TRIGGERED, self.async_alarm_trigger + self._cluster_handler, SIGNAL_ALARM_TRIGGERED, self.async_alarm_trigger ) @callback @@ -122,26 +124,26 @@ class ZHAAlarmControlPanel(ZhaEntity, AlarmControlPanelEntity): @property def code_arm_required(self) -> bool: """Whether the code is required for arm actions.""" - return self._channel.code_required_arm_actions + return self._cluster_handler.code_required_arm_actions async def async_alarm_disarm(self, code: str | None = None) -> None: """Send disarm command.""" - self._channel.arm(IasAce.ArmMode.Disarm, code, 0) + self._cluster_handler.arm(IasAce.ArmMode.Disarm, code, 0) self.async_write_ha_state() async def async_alarm_arm_home(self, code: str | None = None) -> None: """Send arm home command.""" - self._channel.arm(IasAce.ArmMode.Arm_Day_Home_Only, code, 0) + self._cluster_handler.arm(IasAce.ArmMode.Arm_Day_Home_Only, code, 0) self.async_write_ha_state() async def async_alarm_arm_away(self, code: str | None = None) -> None: """Send arm away command.""" - self._channel.arm(IasAce.ArmMode.Arm_All_Zones, code, 0) + self._cluster_handler.arm(IasAce.ArmMode.Arm_All_Zones, code, 0) self.async_write_ha_state() async def async_alarm_arm_night(self, code: str | None = None) -> None: """Send arm night command.""" - self._channel.arm(IasAce.ArmMode.Arm_Night_Sleep_Only, code, 0) + self._cluster_handler.arm(IasAce.ArmMode.Arm_Night_Sleep_Only, code, 0) self.async_write_ha_state() async def async_alarm_trigger(self, code: str | None = None) -> None: @@ -151,4 +153,4 @@ class ZHAAlarmControlPanel(ZhaEntity, AlarmControlPanelEntity): @property def state(self) -> str | None: """Return the state of the entity.""" - return IAS_ACE_STATE_MAP.get(self._channel.armed_state) + return IAS_ACE_STATE_MAP.get(self._cluster_handler.armed_state) diff --git a/homeassistant/components/zha/binary_sensor.py b/homeassistant/components/zha/binary_sensor.py index 696216e3e81..d7b81832c2e 100644 --- a/homeassistant/components/zha/binary_sensor.py +++ b/homeassistant/components/zha/binary_sensor.py @@ -20,11 +20,11 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .core import discovery from .core.const import ( - CHANNEL_ACCELEROMETER, - CHANNEL_BINARY_INPUT, - CHANNEL_OCCUPANCY, - CHANNEL_ON_OFF, - CHANNEL_ZONE, + CLUSTER_HANDLER_ACCELEROMETER, + CLUSTER_HANDLER_BINARY_INPUT, + CLUSTER_HANDLER_OCCUPANCY, + CLUSTER_HANDLER_ON_OFF, + CLUSTER_HANDLER_ZONE, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED, @@ -72,22 +72,22 @@ class BinarySensor(ZhaEntity, BinarySensorEntity): SENSOR_ATTR: str | None = None - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Initialize the ZHA binary sensor.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._channel = channels[0] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._cluster_handler = cluster_handlers[0] async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) @property def is_on(self) -> bool: """Return True if the switch is on based on the state machine.""" - raw_state = self._channel.cluster.get(self.SENSOR_ATTR) + raw_state = self._cluster_handler.cluster.get(self.SENSOR_ATTR) if raw_state is None: return False return self.parse(raw_state) @@ -103,7 +103,7 @@ class BinarySensor(ZhaEntity, BinarySensorEntity): return bool(value) -@MULTI_MATCH(channel_names=CHANNEL_ACCELEROMETER) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ACCELEROMETER) class Accelerometer(BinarySensor): """ZHA BinarySensor.""" @@ -111,7 +111,7 @@ class Accelerometer(BinarySensor): _attr_device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.MOVING -@MULTI_MATCH(channel_names=CHANNEL_OCCUPANCY) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_OCCUPANCY) class Occupancy(BinarySensor): """ZHA BinarySensor.""" @@ -119,7 +119,7 @@ class Occupancy(BinarySensor): _attr_device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.OCCUPANCY -@STRICT_MATCH(channel_names=CHANNEL_ON_OFF) +@STRICT_MATCH(cluster_handler_names=CLUSTER_HANDLER_ON_OFF) class Opening(BinarySensor): """ZHA OnOff BinarySensor.""" @@ -131,13 +131,13 @@ class Opening(BinarySensor): @callback def async_restore_last_state(self, last_state): """Restore previous state to zigpy cache.""" - self._channel.cluster.update_attribute( + self._cluster_handler.cluster.update_attribute( OnOff.attributes_by_name[self.SENSOR_ATTR].id, t.Bool.true if last_state.state == STATE_ON else t.Bool.false, ) -@MULTI_MATCH(channel_names=CHANNEL_BINARY_INPUT) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_BINARY_INPUT) class BinaryInput(BinarySensor): """ZHA BinarySensor.""" @@ -145,14 +145,14 @@ class BinaryInput(BinarySensor): @STRICT_MATCH( - channel_names=CHANNEL_ON_OFF, + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, manufacturers="IKEA of Sweden", models=lambda model: isinstance(model, str) and model is not None and model.find("motion") != -1, ) @STRICT_MATCH( - channel_names=CHANNEL_ON_OFF, + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, manufacturers="Philips", models={"SML001", "SML002"}, ) @@ -162,7 +162,7 @@ class Motion(Opening): _attr_device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.MOTION -@MULTI_MATCH(channel_names=CHANNEL_ZONE) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ZONE) class IASZone(BinarySensor): """ZHA IAS BinarySensor.""" @@ -171,7 +171,7 @@ class IASZone(BinarySensor): @property def device_class(self) -> BinarySensorDeviceClass | None: """Return device class from component DEVICE_CLASSES.""" - return CLASS_MAPPING.get(self._channel.cluster.get("zone_type")) + return CLASS_MAPPING.get(self._cluster_handler.cluster.get("zone_type")) @staticmethod def parse(value: bool | int) -> bool: @@ -204,13 +204,13 @@ class IASZone(BinarySensor): else: migrated_state = IasZone.ZoneStatus(0) - self._channel.cluster.update_attribute( + self._cluster_handler.cluster.update_attribute( IasZone.attributes_by_name[self.SENSOR_ATTR].id, migrated_state ) @MULTI_MATCH( - channel_names="tuya_manufacturer", + cluster_handler_names="tuya_manufacturer", manufacturers={ "_TZE200_htnnfasr", }, @@ -222,7 +222,7 @@ class FrostLock(BinarySensor, id_suffix="frost_lock"): _attr_device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.LOCK -@MULTI_MATCH(channel_names="ikea_airpurifier") +@MULTI_MATCH(cluster_handler_names="ikea_airpurifier") class ReplaceFilter(BinarySensor, id_suffix="replace_filter"): """ZHA BinarySensor.""" @@ -230,7 +230,7 @@ class ReplaceFilter(BinarySensor, id_suffix="replace_filter"): _attr_device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.PROBLEM -@MULTI_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"}) class AqaraPetFeederErrorDetected(BinarySensor, id_suffix="error_detected"): """ZHA aqara pet feeder error detected binary sensor.""" @@ -240,7 +240,8 @@ class AqaraPetFeederErrorDetected(BinarySensor, id_suffix="error_detected"): @MULTI_MATCH( - channel_names="opple_cluster", models={"lumi.plug.mmeu01", "lumi.plug.maeu01"} + cluster_handler_names="opple_cluster", + models={"lumi.plug.mmeu01", "lumi.plug.maeu01"}, ) class XiaomiPlugConsumerConnected(BinarySensor, id_suffix="consumer_connected"): """ZHA Xiaomi plug consumer connected binary sensor.""" @@ -250,7 +251,7 @@ class XiaomiPlugConsumerConnected(BinarySensor, id_suffix="consumer_connected"): _attr_device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.PLUG -@MULTI_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"}) class AqaraThermostatWindowOpen(BinarySensor, id_suffix="window_open"): """ZHA Aqara thermostat window open binary sensor.""" @@ -259,7 +260,7 @@ class AqaraThermostatWindowOpen(BinarySensor, id_suffix="window_open"): _attr_name: str = "Window open" -@MULTI_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"}) class AqaraThermostatValveAlarm(BinarySensor, id_suffix="valve_alarm"): """ZHA Aqara thermostat valve alarm binary sensor.""" @@ -268,7 +269,9 @@ class AqaraThermostatValveAlarm(BinarySensor, id_suffix="valve_alarm"): _attr_name: str = "Valve alarm" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"} +) class AqaraThermostatCalibrated(BinarySensor, id_suffix="calibrated"): """ZHA Aqara thermostat calibrated binary sensor.""" @@ -277,7 +280,9 @@ class AqaraThermostatCalibrated(BinarySensor, id_suffix="calibrated"): _attr_name: str = "Calibrated" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"} +) class AqaraThermostatExternalSensor(BinarySensor, id_suffix="sensor"): """ZHA Aqara thermostat external sensor binary sensor.""" @@ -286,7 +291,7 @@ class AqaraThermostatExternalSensor(BinarySensor, id_suffix="sensor"): _attr_name: str = "External sensor" -@MULTI_MATCH(channel_names="opple_cluster", models={"lumi.sensor_smoke.acn03"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"lumi.sensor_smoke.acn03"}) class AqaraLinkageAlarmState(BinarySensor, id_suffix="linkage_alarm_state"): """ZHA Aqara linkage alarm state binary sensor.""" diff --git a/homeassistant/components/zha/button.py b/homeassistant/components/zha/button.py index b3ff3f5aedd..6564f3bc39a 100644 --- a/homeassistant/components/zha/button.py +++ b/homeassistant/components/zha/button.py @@ -18,12 +18,12 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from .core import discovery -from .core.const import CHANNEL_IDENTIFY, DATA_ZHA, SIGNAL_ADD_ENTITIES +from .core.const import CLUSTER_HANDLER_IDENTIFY, DATA_ZHA, SIGNAL_ADD_ENTITIES from .core.registries import ZHA_ENTITIES from .entity import ZhaEntity if TYPE_CHECKING: - from .core.channels.base import ZigbeeChannel + from .core.cluster_handlers import ClusterHandler from .core.device import ZHADevice @@ -65,12 +65,12 @@ class ZHAButton(ZhaEntity, ButtonEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this button.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._channel: ZigbeeChannel = channels[0] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._cluster_handler: ClusterHandler = cluster_handlers[0] @abc.abstractmethod def get_args(self) -> list[Any]: @@ -78,12 +78,12 @@ class ZHAButton(ZhaEntity, ButtonEntity): async def async_press(self) -> None: """Send out a update command.""" - command = getattr(self._channel, self._command_name) + command = getattr(self._cluster_handler, self._command_name) arguments = self.get_args() await command(*arguments) -@MULTI_MATCH(channel_names=CHANNEL_IDENTIFY) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_IDENTIFY) class ZHAIdentifyButton(ZHAButton): """Defines a ZHA identify button.""" @@ -92,7 +92,7 @@ class ZHAIdentifyButton(ZHAButton): cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. @@ -100,10 +100,10 @@ class ZHAIdentifyButton(ZHAButton): Return entity if it is a supported configuration, otherwise return None """ if ZHA_ENTITIES.prevent_entity_creation( - Platform.BUTTON, zha_device.ieee, CHANNEL_IDENTIFY + Platform.BUTTON, zha_device.ieee, CLUSTER_HANDLER_IDENTIFY ): return None - return cls(unique_id, zha_device, channels, **kwargs) + return cls(unique_id, zha_device, cluster_handlers, **kwargs) _attr_device_class: ButtonDeviceClass = ButtonDeviceClass.UPDATE _attr_entity_category = EntityCategory.DIAGNOSTIC @@ -126,17 +126,17 @@ class ZHAAttributeButton(ZhaEntity, ButtonEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this button.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._channel: ZigbeeChannel = channels[0] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._cluster_handler: ClusterHandler = cluster_handlers[0] async def async_press(self) -> None: """Write attribute with defined value.""" try: - result = await self._channel.cluster.write_attributes( + result = await self._cluster_handler.cluster.write_attributes( {self._attribute_name: self._attribute_value} ) except zigpy.exceptions.ZigbeeException as ex: @@ -149,7 +149,7 @@ class ZHAAttributeButton(ZhaEntity, ButtonEntity): @CONFIG_DIAGNOSTIC_MATCH( - channel_names="tuya_manufacturer", + cluster_handler_names="tuya_manufacturer", manufacturers={ "_TZE200_htnnfasr", }, @@ -164,7 +164,9 @@ class FrostLockResetButton(ZHAAttributeButton, id_suffix="reset_frost_lock"): _attr_entity_category = EntityCategory.CONFIG -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.motion.ac01"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.motion.ac01"} +) class NoPresenceStatusResetButton( ZHAAttributeButton, id_suffix="reset_no_presence_status" ): @@ -177,7 +179,7 @@ class NoPresenceStatusResetButton( _attr_entity_category = EntityCategory.CONFIG -@MULTI_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"}) class AqaraPetFeederFeedButton(ZHAAttributeButton, id_suffix="feeding"): """Defines a feed button for the aqara c1 pet feeder.""" @@ -187,7 +189,7 @@ class AqaraPetFeederFeedButton(ZHAAttributeButton, id_suffix="feeding"): @CONFIG_DIAGNOSTIC_MATCH( - channel_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} + cluster_handler_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} ) class AqaraSelfTestButton(ZHAAttributeButton, id_suffix="self_test"): """Defines a ZHA self-test button for Aqara smoke sensors.""" diff --git a/homeassistant/components/zha/climate.py b/homeassistant/components/zha/climate.py index 022be309c45..f27aa406f2d 100644 --- a/homeassistant/components/zha/climate.py +++ b/homeassistant/components/zha/climate.py @@ -43,8 +43,8 @@ import homeassistant.util.dt as dt_util from .core import discovery from .core.const import ( - CHANNEL_FAN, - CHANNEL_THERMOSTAT, + CLUSTER_HANDLER_FAN, + CLUSTER_HANDLER_THERMOSTAT, DATA_ZHA, PRESET_COMPLEX, PRESET_SCHEDULE, @@ -127,9 +127,9 @@ async def async_setup_entry( @MULTI_MATCH( - channel_names=CHANNEL_THERMOSTAT, - aux_channels=CHANNEL_FAN, - stop_on_match_group=CHANNEL_THERMOSTAT, + cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT, + aux_cluster_handlers=CLUSTER_HANDLER_FAN, + stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT, ) class Thermostat(ZhaEntity, ClimateEntity): """Representation of a ZHA Thermostat device.""" @@ -140,14 +140,14 @@ class Thermostat(ZhaEntity, ClimateEntity): _attr_precision = PRECISION_TENTHS _attr_temperature_unit = UnitOfTemperature.CELSIUS - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Initialize ZHA Thermostat instance.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._thrm = self.cluster_channels.get(CHANNEL_THERMOSTAT) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._thrm = self.cluster_handlers.get(CLUSTER_HANDLER_THERMOSTAT) self._preset = PRESET_NONE self._presets = [] self._supported_flags = ClimateEntityFeature.TARGET_TEMPERATURE - self._fan = self.cluster_channels.get(CHANNEL_FAN) + self._fan = self.cluster_handlers.get(CLUSTER_HANDLER_FAN) @property def current_temperature(self): @@ -480,9 +480,9 @@ class Thermostat(ZhaEntity, ClimateEntity): @MULTI_MATCH( - channel_names={CHANNEL_THERMOSTAT, "sinope_manufacturer_specific"}, + cluster_handler_names={CLUSTER_HANDLER_THERMOSTAT, "sinope_manufacturer_specific"}, manufacturers="Sinope Technologies", - stop_on_match_group=CHANNEL_THERMOSTAT, + stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT, ) class SinopeTechnologiesThermostat(Thermostat): """Sinope Technologies Thermostat.""" @@ -490,12 +490,12 @@ class SinopeTechnologiesThermostat(Thermostat): manufacturer = 0x119C update_time_interval = timedelta(minutes=randint(45, 75)) - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Initialize ZHA Thermostat instance.""" - super().__init__(unique_id, zha_device, channels, **kwargs) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) self._presets = [PRESET_AWAY, PRESET_NONE] self._supported_flags |= ClimateEntityFeature.PRESET_MODE - self._manufacturer_ch = self.cluster_channels["sinope_manufacturer_specific"] + self._manufacturer_ch = self.cluster_handlers["sinope_manufacturer_specific"] @property def _rm_rs_action(self) -> HVACAction: @@ -553,28 +553,28 @@ class SinopeTechnologiesThermostat(Thermostat): @MULTI_MATCH( - channel_names=CHANNEL_THERMOSTAT, - aux_channels=CHANNEL_FAN, + cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT, + aux_cluster_handlers=CLUSTER_HANDLER_FAN, manufacturers={"Zen Within", "LUX"}, - stop_on_match_group=CHANNEL_THERMOSTAT, + stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT, ) class ZenWithinThermostat(Thermostat): """Zen Within Thermostat implementation.""" @MULTI_MATCH( - channel_names=CHANNEL_THERMOSTAT, - aux_channels=CHANNEL_FAN, + cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT, + aux_cluster_handlers=CLUSTER_HANDLER_FAN, manufacturers="Centralite", models={"3157100", "3157100-E"}, - stop_on_match_group=CHANNEL_THERMOSTAT, + stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT, ) class CentralitePearl(ZenWithinThermostat): """Centralite Pearl Thermostat implementation.""" @STRICT_MATCH( - channel_names=CHANNEL_THERMOSTAT, + cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT, manufacturers={ "_TZE200_ckud7u2l", "_TZE200_ywdxldoj", @@ -594,9 +594,9 @@ class CentralitePearl(ZenWithinThermostat): class MoesThermostat(Thermostat): """Moes Thermostat implementation.""" - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Initialize ZHA Thermostat instance.""" - super().__init__(unique_id, zha_device, channels, **kwargs) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) self._presets = [ PRESET_NONE, PRESET_AWAY, @@ -668,7 +668,7 @@ class MoesThermostat(Thermostat): @STRICT_MATCH( - channel_names=CHANNEL_THERMOSTAT, + cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT, manufacturers={ "_TZE200_b6wax7g0", }, @@ -676,9 +676,9 @@ class MoesThermostat(Thermostat): class BecaThermostat(Thermostat): """Beca Thermostat implementation.""" - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Initialize ZHA Thermostat instance.""" - super().__init__(unique_id, zha_device, channels, **kwargs) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) self._presets = [ PRESET_NONE, PRESET_AWAY, @@ -743,10 +743,10 @@ class BecaThermostat(Thermostat): @MULTI_MATCH( - channel_names=CHANNEL_THERMOSTAT, + cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT, manufacturers="Stelpro", models={"SORB"}, - stop_on_match_group=CHANNEL_THERMOSTAT, + stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT, ) class StelproFanHeater(Thermostat): """Stelpro Fan Heater implementation.""" @@ -758,7 +758,7 @@ class StelproFanHeater(Thermostat): @STRICT_MATCH( - channel_names=CHANNEL_THERMOSTAT, + cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT, manufacturers={ "_TZE200_7yoranx2", "_TZE200_e9ba97vf", # TV01-ZG @@ -780,9 +780,9 @@ class ZONNSMARTThermostat(Thermostat): PRESET_HOLIDAY = "holiday" PRESET_FROST = "frost protect" - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Initialize ZHA Thermostat instance.""" - super().__init__(unique_id, zha_device, channels, **kwargs) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) self._presets = [ PRESET_NONE, self.PRESET_HOLIDAY, diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py deleted file mode 100644 index a708e65a07a..00000000000 --- a/homeassistant/components/zha/core/channels/__init__.py +++ /dev/null @@ -1,385 +0,0 @@ -"""Channels module for Zigbee Home Automation.""" -from __future__ import annotations - -import asyncio -from typing import TYPE_CHECKING, Any - -from typing_extensions import Self -import zigpy.endpoint -import zigpy.zcl.clusters.closures - -from homeassistant.const import ATTR_DEVICE_ID -from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers.dispatcher import async_dispatcher_send - -from . import ( # noqa: F401 - base, - closures, - general, - homeautomation, - hvac, - lighting, - lightlink, - manufacturerspecific, - measurement, - protocol, - security, - smartenergy, -) -from .. import ( - const, - device as zha_core_device, - discovery as zha_disc, - registries as zha_regs, -) - -if TYPE_CHECKING: - from ...entity import ZhaEntity - from ..device import ZHADevice - -_ChannelsDictType = dict[str, base.ZigbeeChannel] - - -class Channels: - """All discovered channels of a device.""" - - def __init__(self, zha_device: ZHADevice) -> None: - """Initialize instance.""" - self._pools: list[ChannelPool] = [] - self._power_config: base.ZigbeeChannel | None = None - self._identify: base.ZigbeeChannel | None = None - self._unique_id = str(zha_device.ieee) - self._zdo_channel = base.ZDOChannel(zha_device.device.endpoints[0], zha_device) - self._zha_device = zha_device - - @property - def pools(self) -> list[ChannelPool]: - """Return channel pools list.""" - return self._pools - - @property - def power_configuration_ch(self) -> base.ZigbeeChannel | None: - """Return power configuration channel.""" - return self._power_config - - @power_configuration_ch.setter - def power_configuration_ch(self, channel: base.ZigbeeChannel) -> None: - """Power configuration channel setter.""" - if self._power_config is None: - self._power_config = channel - - @property - def identify_ch(self) -> base.ZigbeeChannel | None: - """Return power configuration channel.""" - return self._identify - - @identify_ch.setter - def identify_ch(self, channel: base.ZigbeeChannel) -> None: - """Power configuration channel setter.""" - if self._identify is None: - self._identify = channel - - @property - def zdo_channel(self) -> base.ZDOChannel: - """Return ZDO channel.""" - return self._zdo_channel - - @property - def zha_device(self) -> ZHADevice: - """Return parent ZHA device.""" - return self._zha_device - - @property - def unique_id(self) -> str: - """Return the unique id for this channel.""" - return self._unique_id - - @property - def zigbee_signature(self) -> dict[int, dict[str, Any]]: - """Get the zigbee signatures for the pools in channels.""" - return { - signature[0]: signature[1] - for signature in [pool.zigbee_signature for pool in self.pools] - } - - @classmethod - def new(cls, zha_device: ZHADevice) -> Self: - """Create new instance.""" - channels = cls(zha_device) - for ep_id in sorted(zha_device.device.endpoints): - channels.add_pool(ep_id) - return channels - - def add_pool(self, ep_id: int) -> None: - """Add channels for a specific endpoint.""" - if ep_id == 0: - return - self._pools.append(ChannelPool.new(self, ep_id)) - - async def async_initialize(self, from_cache: bool = False) -> None: - """Initialize claimed channels.""" - await self.zdo_channel.async_initialize(from_cache) - self.zdo_channel.debug("'async_initialize' stage succeeded") - await asyncio.gather( - *(pool.async_initialize(from_cache) for pool in self.pools) - ) - - async def async_configure(self) -> None: - """Configure claimed channels.""" - await self.zdo_channel.async_configure() - self.zdo_channel.debug("'async_configure' stage succeeded") - await asyncio.gather(*(pool.async_configure() for pool in self.pools)) - async_dispatcher_send( - self.zha_device.hass, - const.ZHA_CHANNEL_MSG, - { - const.ATTR_TYPE: const.ZHA_CHANNEL_CFG_DONE, - }, - ) - - @callback - def async_new_entity( - self, - component: str, - entity_class: type[ZhaEntity], - unique_id: str, - channels: list[base.ZigbeeChannel], - ): - """Signal new entity addition.""" - if self.zha_device.status == zha_core_device.DeviceStatus.INITIALIZED: - return - - self.zha_device.hass.data[const.DATA_ZHA][component].append( - (entity_class, (unique_id, self.zha_device, channels)) - ) - - @callback - def async_send_signal(self, signal: str, *args: Any) -> None: - """Send a signal through hass dispatcher.""" - async_dispatcher_send(self.zha_device.hass, signal, *args) - - @callback - def zha_send_event(self, event_data: dict[str, str | int]) -> None: - """Relay events to hass.""" - self.zha_device.hass.bus.async_fire( - const.ZHA_EVENT, - { - const.ATTR_DEVICE_IEEE: str(self.zha_device.ieee), - const.ATTR_UNIQUE_ID: self.unique_id, - ATTR_DEVICE_ID: self.zha_device.device_id, - **event_data, - }, - ) - - -class ChannelPool: - """All channels of an endpoint.""" - - def __init__(self, channels: Channels, ep_id: int) -> None: - """Initialize instance.""" - self._all_channels: _ChannelsDictType = {} - self._channels = channels - self._claimed_channels: _ChannelsDictType = {} - self._id = ep_id - self._client_channels: dict[str, base.ClientChannel] = {} - self._unique_id = f"{channels.unique_id}-{ep_id}" - - @property - def all_channels(self) -> _ChannelsDictType: - """All server channels of an endpoint.""" - return self._all_channels - - @property - def claimed_channels(self) -> _ChannelsDictType: - """Channels in use.""" - return self._claimed_channels - - @property - def client_channels(self) -> dict[str, base.ClientChannel]: - """Return a dict of client channels.""" - return self._client_channels - - @property - def endpoint(self) -> zigpy.endpoint.Endpoint: - """Return endpoint of zigpy device.""" - return self._channels.zha_device.device.endpoints[self.id] - - @property - def id(self) -> int: - """Return endpoint id.""" - return self._id - - @property - def nwk(self) -> int: - """Device NWK for logging.""" - return self._channels.zha_device.nwk - - @property - def is_mains_powered(self) -> bool | None: - """Device is_mains_powered.""" - return self._channels.zha_device.is_mains_powered - - @property - def manufacturer(self) -> str: - """Return device manufacturer.""" - return self._channels.zha_device.manufacturer - - @property - def manufacturer_code(self) -> int | None: - """Return device manufacturer.""" - return self._channels.zha_device.manufacturer_code - - @property - def hass(self) -> HomeAssistant: - """Return hass.""" - return self._channels.zha_device.hass - - @property - def model(self) -> str: - """Return device model.""" - return self._channels.zha_device.model - - @property - def quirk_class(self) -> str: - """Return device quirk class.""" - return self._channels.zha_device.quirk_class - - @property - def skip_configuration(self) -> bool: - """Return True if device does not require channel configuration.""" - return self._channels.zha_device.skip_configuration - - @property - def unique_id(self) -> str: - """Return the unique id for this channel.""" - return self._unique_id - - @property - def zigbee_signature(self) -> tuple[int, dict[str, Any]]: - """Get the zigbee signature for the endpoint this pool represents.""" - return ( - self.endpoint.endpoint_id, - { - const.ATTR_PROFILE_ID: self.endpoint.profile_id, - const.ATTR_DEVICE_TYPE: f"0x{self.endpoint.device_type:04x}" - if self.endpoint.device_type is not None - else "", - const.ATTR_IN_CLUSTERS: [ - f"0x{cluster_id:04x}" - for cluster_id in sorted(self.endpoint.in_clusters) - ], - const.ATTR_OUT_CLUSTERS: [ - f"0x{cluster_id:04x}" - for cluster_id in sorted(self.endpoint.out_clusters) - ], - }, - ) - - @classmethod - def new(cls, channels: Channels, ep_id: int) -> Self: - """Create new channels for an endpoint.""" - pool = cls(channels, ep_id) - pool.add_all_channels() - pool.add_client_channels() - if not channels.zha_device.is_coordinator: - zha_disc.PROBE.discover_entities(pool) - return pool - - @callback - def add_all_channels(self) -> None: - """Create and add channels for all input clusters.""" - for cluster_id, cluster in self.endpoint.in_clusters.items(): - channel_class = zha_regs.ZIGBEE_CHANNEL_REGISTRY.get( - cluster_id, base.ZigbeeChannel - ) - # really ugly hack to deal with xiaomi using the door lock cluster - # incorrectly. - if ( - hasattr(cluster, "ep_attribute") - and cluster_id == zigpy.zcl.clusters.closures.DoorLock.cluster_id - and cluster.ep_attribute == "multistate_input" - ): - channel_class = general.MultistateInput - # end of ugly hack - channel = channel_class(cluster, self) - if channel.name == const.CHANNEL_POWER_CONFIGURATION: - if ( - self._channels.power_configuration_ch - or self._channels.zha_device.is_mains_powered - ): - # on power configuration channel per device - continue - self._channels.power_configuration_ch = channel - elif channel.name == const.CHANNEL_IDENTIFY: - self._channels.identify_ch = channel - - self.all_channels[channel.id] = channel - - @callback - def add_client_channels(self) -> None: - """Create client channels for all output clusters if in the registry.""" - for cluster_id, channel_class in zha_regs.CLIENT_CHANNELS_REGISTRY.items(): - cluster = self.endpoint.out_clusters.get(cluster_id) - if cluster is not None: - channel = channel_class(cluster, self) - self.client_channels[channel.id] = channel - - async def async_initialize(self, from_cache: bool = False) -> None: - """Initialize claimed channels.""" - await self._execute_channel_tasks("async_initialize", from_cache) - - async def async_configure(self) -> None: - """Configure claimed channels.""" - await self._execute_channel_tasks("async_configure") - - async def _execute_channel_tasks(self, func_name: str, *args: Any) -> None: - """Add a throttled channel task and swallow exceptions.""" - channels = [*self.claimed_channels.values(), *self.client_channels.values()] - tasks = [getattr(ch, func_name)(*args) for ch in channels] - results = await asyncio.gather(*tasks, return_exceptions=True) - for channel, outcome in zip(channels, results): - if isinstance(outcome, Exception): - channel.warning( - "'%s' stage failed: %s", func_name, str(outcome), exc_info=outcome - ) - continue - channel.debug("'%s' stage succeeded", func_name) - - @callback - def async_new_entity( - self, - component: str, - entity_class: type[ZhaEntity], - unique_id: str, - channels: list[base.ZigbeeChannel], - ): - """Signal new entity addition.""" - self._channels.async_new_entity(component, entity_class, unique_id, channels) - - @callback - def async_send_signal(self, signal: str, *args: Any) -> None: - """Send a signal through hass dispatcher.""" - self._channels.async_send_signal(signal, *args) - - @callback - def claim_channels(self, channels: list[base.ZigbeeChannel]) -> None: - """Claim a channel.""" - self.claimed_channels.update({ch.id: ch for ch in channels}) - - @callback - def unclaimed_channels(self) -> list[base.ZigbeeChannel]: - """Return a list of available (unclaimed) channels.""" - claimed = set(self.claimed_channels) - available = set(self.all_channels) - return [self.all_channels[chan_id] for chan_id in (available - claimed)] - - @callback - def zha_send_event(self, event_data: dict[str, Any]) -> None: - """Relay events to hass.""" - self._channels.zha_send_event( - { - const.ATTR_UNIQUE_ID: self.unique_id, - const.ATTR_ENDPOINT_ID: self.id, - **event_data, - } - ) diff --git a/homeassistant/components/zha/core/channels/helpers.py b/homeassistant/components/zha/core/channels/helpers.py deleted file mode 100644 index 2297af312eb..00000000000 --- a/homeassistant/components/zha/core/channels/helpers.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Helpers for use with ZHA Zigbee channels.""" -from .base import ZigbeeChannel - - -def is_hue_motion_sensor(channel: ZigbeeChannel) -> bool: - """Return true if the manufacturer and model match known Hue motion sensor models.""" - return channel.cluster.endpoint.manufacturer in ( - "Philips", - "Signify Netherlands B.V.", - ) and channel.cluster.endpoint.model in ( - "SML001", - "SML002", - "SML003", - "SML004", - ) diff --git a/homeassistant/components/zha/core/channels/protocol.py b/homeassistant/components/zha/core/channels/protocol.py deleted file mode 100644 index 51d837a8014..00000000000 --- a/homeassistant/components/zha/core/channels/protocol.py +++ /dev/null @@ -1,113 +0,0 @@ -"""Protocol channels module for Zigbee Home Automation.""" -from zigpy.zcl.clusters import protocol - -from .. import registries -from .base import ZigbeeChannel - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.AnalogInputExtended.cluster_id) -class AnalogInputExtended(ZigbeeChannel): - """Analog Input Extended channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.AnalogInputRegular.cluster_id) -class AnalogInputRegular(ZigbeeChannel): - """Analog Input Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.AnalogOutputExtended.cluster_id) -class AnalogOutputExtended(ZigbeeChannel): - """Analog Output Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.AnalogOutputRegular.cluster_id) -class AnalogOutputRegular(ZigbeeChannel): - """Analog Output Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.AnalogValueExtended.cluster_id) -class AnalogValueExtended(ZigbeeChannel): - """Analog Value Extended edition channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.AnalogValueRegular.cluster_id) -class AnalogValueRegular(ZigbeeChannel): - """Analog Value Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.BacnetProtocolTunnel.cluster_id) -class BacnetProtocolTunnel(ZigbeeChannel): - """Bacnet Protocol Tunnel channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.BinaryInputExtended.cluster_id) -class BinaryInputExtended(ZigbeeChannel): - """Binary Input Extended channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.BinaryInputRegular.cluster_id) -class BinaryInputRegular(ZigbeeChannel): - """Binary Input Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.BinaryOutputExtended.cluster_id) -class BinaryOutputExtended(ZigbeeChannel): - """Binary Output Extended channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.BinaryOutputRegular.cluster_id) -class BinaryOutputRegular(ZigbeeChannel): - """Binary Output Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.BinaryValueExtended.cluster_id) -class BinaryValueExtended(ZigbeeChannel): - """Binary Value Extended channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.BinaryValueRegular.cluster_id) -class BinaryValueRegular(ZigbeeChannel): - """Binary Value Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.GenericTunnel.cluster_id) -class GenericTunnel(ZigbeeChannel): - """Generic Tunnel channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register( - protocol.MultistateInputExtended.cluster_id -) -class MultiStateInputExtended(ZigbeeChannel): - """Multistate Input Extended channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.MultistateInputRegular.cluster_id) -class MultiStateInputRegular(ZigbeeChannel): - """Multistate Input Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register( - protocol.MultistateOutputExtended.cluster_id -) -class MultiStateOutputExtended(ZigbeeChannel): - """Multistate Output Extended channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register( - protocol.MultistateOutputRegular.cluster_id -) -class MultiStateOutputRegular(ZigbeeChannel): - """Multistate Output Regular channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register( - protocol.MultistateValueExtended.cluster_id -) -class MultiStateValueExtended(ZigbeeChannel): - """Multistate Value Extended channel.""" - - -@registries.ZIGBEE_CHANNEL_REGISTRY.register(protocol.MultistateValueRegular.cluster_id) -class MultiStateValueRegular(ZigbeeChannel): - """Multistate Value Regular channel.""" diff --git a/homeassistant/components/zha/core/channels/base.py b/homeassistant/components/zha/core/cluster_handlers/__init__.py similarity index 75% rename from homeassistant/components/zha/core/channels/base.py rename to homeassistant/components/zha/core/cluster_handlers/__init__.py index 48f69ffbf2d..4fe58e409e8 100644 --- a/homeassistant/components/zha/core/channels/base.py +++ b/homeassistant/components/zha/core/cluster_handlers/__init__.py @@ -1,4 +1,4 @@ -"""Base classes for channels.""" +"""Cluster handlers module for Zigbee Home Automation.""" from __future__ import annotations import asyncio @@ -29,19 +29,19 @@ from ..const import ( ATTR_TYPE, ATTR_UNIQUE_ID, ATTR_VALUE, - CHANNEL_ZDO, + CLUSTER_HANDLER_ZDO, REPORT_CONFIG_ATTR_PER_REQ, SIGNAL_ATTR_UPDATED, - ZHA_CHANNEL_MSG, - ZHA_CHANNEL_MSG_BIND, - ZHA_CHANNEL_MSG_CFG_RPT, - ZHA_CHANNEL_MSG_DATA, - ZHA_CHANNEL_READS_PER_REQ, + ZHA_CLUSTER_HANDLER_MSG, + ZHA_CLUSTER_HANDLER_MSG_BIND, + ZHA_CLUSTER_HANDLER_MSG_CFG_RPT, + ZHA_CLUSTER_HANDLER_MSG_DATA, + ZHA_CLUSTER_HANDLER_READS_PER_REQ, ) from ..helpers import LogMixin, retryable_req, safe_read if TYPE_CHECKING: - from . import ChannelPool + from ..endpoint import Endpoint _LOGGER = logging.getLogger(__name__) @@ -56,31 +56,31 @@ class AttrReportConfig(TypedDict, total=True): config: tuple[int, int, int | float] -def parse_and_log_command(channel, tsn, command_id, args): +def parse_and_log_command(cluster_handler, tsn, command_id, args): """Parse and log a zigbee cluster command.""" try: - name = channel.cluster.server_commands[command_id].name + name = cluster_handler.cluster.server_commands[command_id].name except KeyError: name = f"0x{command_id:02X}" - channel.debug( + cluster_handler.debug( "received '%s' command with %s args on cluster_id '%s' tsn '%s'", name, args, - channel.cluster.cluster_id, + cluster_handler.cluster.cluster_id, tsn, ) return name -def decorate_command(channel, command): +def decorate_command(cluster_handler, command): """Wrap a cluster command to make it safe.""" @wraps(command) async def wrapper(*args, **kwds): try: result = await command(*args, **kwds) - channel.debug( + cluster_handler.debug( "executed '%s' command with args: '%s' kwargs: '%s' result: %s", command.__name__, args, @@ -90,7 +90,7 @@ def decorate_command(channel, command): return result except (zigpy.exceptions.ZigbeeException, asyncio.TimeoutError) as ex: - channel.debug( + cluster_handler.debug( "command failed: '%s' args: '%s' kwargs '%s' exception: '%s'", command.__name__, args, @@ -102,32 +102,32 @@ def decorate_command(channel, command): return wrapper -class ChannelStatus(Enum): - """Status of a channel.""" +class ClusterHandlerStatus(Enum): + """Status of a cluster handler.""" CREATED = 1 CONFIGURED = 2 INITIALIZED = 3 -class ZigbeeChannel(LogMixin): - """Base channel for a Zigbee cluster.""" +class ClusterHandler(LogMixin): + """Base cluster handler for a Zigbee cluster.""" REPORT_CONFIG: tuple[AttrReportConfig, ...] = () BIND: bool = True - # Dict of attributes to read on channel initialization. + # Dict of attributes to read on cluster handler initialization. # Dict keys -- attribute ID or names, with bool value indicating whether a cached # attribute read is acceptable. ZCL_INIT_ATTRS: dict[int | str, bool] = {} - def __init__(self, cluster: zigpy.zcl.Cluster, ch_pool: ChannelPool) -> None: - """Initialize ZigbeeChannel.""" - self._generic_id = f"channel_0x{cluster.cluster_id:04x}" - self._ch_pool = ch_pool + def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None: + """Initialize ClusterHandler.""" + self._generic_id = f"cluster_handler_0x{cluster.cluster_id:04x}" + self._endpoint: Endpoint = endpoint self._cluster = cluster - self._id = f"{ch_pool.id}:0x{cluster.cluster_id:04x}" - unique_id = ch_pool.unique_id.replace("-", ":") + self._id = f"{endpoint.id}:0x{cluster.cluster_id:04x}" + unique_id = endpoint.unique_id.replace("-", ":") self._unique_id = f"{unique_id}:0x{cluster.cluster_id:04x}" if not hasattr(self, "_value_attribute") and self.REPORT_CONFIG: attr_def: ZCLAttributeDef | None = self.cluster.attributes_by_name.get( @@ -137,28 +137,28 @@ class ZigbeeChannel(LogMixin): self.value_attribute = attr_def.id else: self.value_attribute = None - self._status = ChannelStatus.CREATED + self._status = ClusterHandlerStatus.CREATED self._cluster.add_listener(self) self.data_cache: dict[str, Enum] = {} @property def id(self) -> str: - """Return channel id unique for this device only.""" + """Return cluster handler id unique for this device only.""" return self._id @property def generic_id(self): - """Return the generic id for this channel.""" + """Return the generic id for this cluster handler.""" return self._generic_id @property def unique_id(self): - """Return the unique id for this channel.""" + """Return the unique id for this cluster handler.""" return self._unique_id @property def cluster(self): - """Return the zigpy cluster for this channel.""" + """Return the zigpy cluster for this cluster handler.""" return self._cluster @property @@ -168,7 +168,7 @@ class ZigbeeChannel(LogMixin): @property def status(self): - """Return the status of the channel.""" + """Return the status of the cluster handler.""" return self._status def __hash__(self) -> int: @@ -178,7 +178,7 @@ class ZigbeeChannel(LogMixin): @callback def async_send_signal(self, signal: str, *args: Any) -> None: """Send a signal through hass dispatcher.""" - self._ch_pool.async_send_signal(signal, *args) + self._endpoint.async_send_signal(signal, *args) async def bind(self): """Bind a zigbee cluster. @@ -190,11 +190,11 @@ class ZigbeeChannel(LogMixin): res = await self.cluster.bind() self.debug("bound '%s' cluster: %s", self.cluster.ep_attribute, res[0]) async_dispatcher_send( - self._ch_pool.hass, - ZHA_CHANNEL_MSG, + self._endpoint.device.hass, + ZHA_CLUSTER_HANDLER_MSG, { - ATTR_TYPE: ZHA_CHANNEL_MSG_BIND, - ZHA_CHANNEL_MSG_DATA: { + ATTR_TYPE: ZHA_CLUSTER_HANDLER_MSG_BIND, + ZHA_CLUSTER_HANDLER_MSG_DATA: { "cluster_name": self.cluster.name, "cluster_id": self.cluster.cluster_id, "success": res[0] == 0, @@ -206,11 +206,11 @@ class ZigbeeChannel(LogMixin): "Failed to bind '%s' cluster: %s", self.cluster.ep_attribute, str(ex) ) async_dispatcher_send( - self._ch_pool.hass, - ZHA_CHANNEL_MSG, + self._endpoint.device.hass, + ZHA_CLUSTER_HANDLER_MSG, { - ATTR_TYPE: ZHA_CHANNEL_MSG_BIND, - ZHA_CHANNEL_MSG_DATA: { + ATTR_TYPE: ZHA_CLUSTER_HANDLER_MSG_BIND, + ZHA_CLUSTER_HANDLER_MSG_DATA: { "cluster_name": self.cluster.name, "cluster_id": self.cluster.cluster_id, "success": False, @@ -226,8 +226,11 @@ class ZigbeeChannel(LogMixin): """ event_data = {} kwargs = {} - if self.cluster.cluster_id >= 0xFC00 and self._ch_pool.manufacturer_code: - kwargs["manufacturer"] = self._ch_pool.manufacturer_code + if ( + self.cluster.cluster_id >= 0xFC00 + and self._endpoint.device.manufacturer_code + ): + kwargs["manufacturer"] = self._endpoint.device.manufacturer_code for attr_report in self.REPORT_CONFIG: attr, config = attr_report["attr"], attr_report["config"] @@ -272,11 +275,11 @@ class ZigbeeChannel(LogMixin): ) async_dispatcher_send( - self._ch_pool.hass, - ZHA_CHANNEL_MSG, + self._endpoint.device.hass, + ZHA_CLUSTER_HANDLER_MSG, { - ATTR_TYPE: ZHA_CHANNEL_MSG_CFG_RPT, - ZHA_CHANNEL_MSG_DATA: { + ATTR_TYPE: ZHA_CLUSTER_HANDLER_MSG_CFG_RPT, + ZHA_CLUSTER_HANDLER_MSG_DATA: { "cluster_name": self.cluster.name, "cluster_id": self.cluster.cluster_id, "attributes": event_data, @@ -311,7 +314,6 @@ class ZigbeeChannel(LogMixin): for record in res if record.status != Status.SUCCESS ] - self.debug( "Successfully configured reporting for '%s' on '%s' cluster", set(attrs) - set(failed), @@ -326,43 +328,45 @@ class ZigbeeChannel(LogMixin): async def async_configure(self) -> None: """Set cluster binding and attribute reporting.""" - if not self._ch_pool.skip_configuration: + if not self._endpoint.device.skip_configuration: if self.BIND: self.debug("Performing cluster binding") await self.bind() if self.cluster.is_server: self.debug("Configuring cluster attribute reporting") await self.configure_reporting() - ch_specific_cfg = getattr(self, "async_configure_channel_specific", None) + ch_specific_cfg = getattr( + self, "async_configure_cluster_handler_specific", None + ) if ch_specific_cfg: - self.debug("Performing channel specific configuration") + self.debug("Performing cluster handler specific configuration") await ch_specific_cfg() - self.debug("finished channel configuration") + self.debug("finished cluster handler configuration") else: - self.debug("skipping channel configuration") - self._status = ChannelStatus.CONFIGURED + self.debug("skipping cluster handler configuration") + self._status = ClusterHandlerStatus.CONFIGURED @retryable_req(delays=(1, 1, 3)) async def async_initialize(self, from_cache: bool) -> None: - """Initialize channel.""" - if not from_cache and self._ch_pool.skip_configuration: - self.debug("Skipping channel initialization") - self._status = ChannelStatus.INITIALIZED + """Initialize cluster handler.""" + if not from_cache and self._endpoint.device.skip_configuration: + self.debug("Skipping cluster handler initialization") + self._status = ClusterHandlerStatus.INITIALIZED return - self.debug("initializing channel: from_cache: %s", from_cache) + self.debug("initializing cluster handler: from_cache: %s", from_cache) cached = [a for a, cached in self.ZCL_INIT_ATTRS.items() if cached] uncached = [a for a, cached in self.ZCL_INIT_ATTRS.items() if not cached] uncached.extend([cfg["attr"] for cfg in self.REPORT_CONFIG]) if cached: - self.debug("initializing cached channel attributes: %s", cached) + self.debug("initializing cached cluster handler attributes: %s", cached) await self._get_attributes( True, cached, from_cache=True, only_cache=from_cache ) if uncached: self.debug( - "initializing uncached channel attributes: %s - from cache[%s]", + "initializing uncached cluster handler attributes: %s - from cache[%s]", uncached, from_cache, ) @@ -370,13 +374,17 @@ class ZigbeeChannel(LogMixin): True, uncached, from_cache=from_cache, only_cache=from_cache ) - ch_specific_init = getattr(self, "async_initialize_channel_specific", None) + ch_specific_init = getattr( + self, "async_initialize_cluster_handler_specific", None + ) if ch_specific_init: - self.debug("Performing channel specific initialization: %s", uncached) + self.debug( + "Performing cluster handler specific initialization: %s", uncached + ) await ch_specific_init(from_cache=from_cache) - self.debug("finished channel initialization") - self._status = ChannelStatus.INITIALIZED + self.debug("finished cluster handler initialization") + self._status = ClusterHandlerStatus.INITIALIZED @callback def cluster_command(self, tsn, command_id, args): @@ -411,13 +419,13 @@ class ZigbeeChannel(LogMixin): else: raise TypeError(f"Unexpected zha_send_event {command!r} argument: {arg!r}") - self._ch_pool.zha_send_event( + self._endpoint.device.zha_send_event( { ATTR_UNIQUE_ID: self.unique_id, ATTR_CLUSTER_ID: self.cluster.cluster_id, ATTR_COMMAND: command, # Maintain backwards compatibility with the old zigpy response format - ATTR_ARGS: args, + ATTR_ARGS: args, # type: ignore[dict-item] ATTR_PARAMS: params, } ) @@ -434,7 +442,7 @@ class ZigbeeChannel(LogMixin): async def get_attribute_value(self, attribute, from_cache=True): """Get the value for an attribute.""" manufacturer = None - manufacturer_code = self._ch_pool.manufacturer_code + manufacturer_code = self._endpoint.device.manufacturer_code if self.cluster.cluster_id >= 0xFC00 and manufacturer_code: manufacturer = manufacturer_code result = await safe_read( @@ -455,11 +463,11 @@ class ZigbeeChannel(LogMixin): ) -> dict[int | str, Any]: """Get the values for a list of attributes.""" manufacturer = None - manufacturer_code = self._ch_pool.manufacturer_code + manufacturer_code = self._endpoint.device.manufacturer_code if self.cluster.cluster_id >= 0xFC00 and manufacturer_code: manufacturer = manufacturer_code - chunk = attributes[:ZHA_CHANNEL_READS_PER_REQ] - rest = attributes[ZHA_CHANNEL_READS_PER_REQ:] + chunk = attributes[:ZHA_CLUSTER_HANDLER_READS_PER_REQ] + rest = attributes[ZHA_CLUSTER_HANDLER_READS_PER_REQ:] result = {} while chunk: try: @@ -480,8 +488,8 @@ class ZigbeeChannel(LogMixin): ) if raise_exceptions: raise - chunk = rest[:ZHA_CHANNEL_READS_PER_REQ] - rest = rest[ZHA_CHANNEL_READS_PER_REQ:] + chunk = rest[:ZHA_CLUSTER_HANDLER_READS_PER_REQ] + rest = rest[ZHA_CLUSTER_HANDLER_READS_PER_REQ:] return result get_attributes = partialmethod(_get_attributes, False) @@ -489,7 +497,7 @@ class ZigbeeChannel(LogMixin): def log(self, level, msg, *args, **kwargs): """Log a message.""" msg = f"[%s:%s]: {msg}" - args = (self._ch_pool.nwk, self._id) + args + args = (self._endpoint.device.nwk, self._id) + args _LOGGER.log(level, msg, *args, **kwargs) def __getattr__(self, name): @@ -501,31 +509,31 @@ class ZigbeeChannel(LogMixin): return self.__getattribute__(name) -class ZDOChannel(LogMixin): - """Channel for ZDO events.""" +class ZDOClusterHandler(LogMixin): + """Cluster handler for ZDO events.""" - def __init__(self, cluster, device): - """Initialize ZDOChannel.""" - self.name = CHANNEL_ZDO - self._cluster = cluster + def __init__(self, device): + """Initialize ZDOClusterHandler.""" + self.name = CLUSTER_HANDLER_ZDO + self._cluster = device.device.endpoints[0] self._zha_device = device - self._status = ChannelStatus.CREATED + self._status = ClusterHandlerStatus.CREATED self._unique_id = f"{str(device.ieee)}:{device.name}_ZDO" self._cluster.add_listener(self) @property def unique_id(self): - """Return the unique id for this channel.""" + """Return the unique id for this cluster handler.""" return self._unique_id @property def cluster(self): - """Return the aigpy cluster for this channel.""" + """Return the aigpy cluster for this cluster handler.""" return self._cluster @property def status(self): - """Return the status of the channel.""" + """Return the status of the cluster handler.""" return self._status @callback @@ -537,12 +545,12 @@ class ZDOChannel(LogMixin): """Permit handler.""" async def async_initialize(self, from_cache): - """Initialize channel.""" - self._status = ChannelStatus.INITIALIZED + """Initialize cluster handler.""" + self._status = ClusterHandlerStatus.INITIALIZED async def async_configure(self): - """Configure channel.""" - self._status = ChannelStatus.CONFIGURED + """Configure cluster handler.""" + self._status = ClusterHandlerStatus.CONFIGURED def log(self, level, msg, *args, **kwargs): """Log a message.""" @@ -551,8 +559,8 @@ class ZDOChannel(LogMixin): _LOGGER.log(level, msg, *args, **kwargs) -class ClientChannel(ZigbeeChannel): - """Channel listener for Zigbee client (output) clusters.""" +class ClientClusterHandler(ClusterHandler): + """ClusterHandler for Zigbee client (output) clusters.""" @callback def attribute_updated(self, attrid, value): diff --git a/homeassistant/components/zha/core/channels/closures.py b/homeassistant/components/zha/core/cluster_handlers/closures.py similarity index 85% rename from homeassistant/components/zha/core/channels/closures.py rename to homeassistant/components/zha/core/cluster_handlers/closures.py index de2dcaf38e9..4080e95748a 100644 --- a/homeassistant/components/zha/core/channels/closures.py +++ b/homeassistant/components/zha/core/cluster_handlers/closures.py @@ -1,16 +1,16 @@ -"""Closures channels module for Zigbee Home Automation.""" +"""Closures cluster handlers module for Zigbee Home Automation.""" from zigpy.zcl.clusters import closures from homeassistant.core import callback +from . import AttrReportConfig, ClientClusterHandler, ClusterHandler from .. import registries from ..const import REPORT_CONFIG_IMMEDIATE, SIGNAL_ATTR_UPDATED -from .base import AttrReportConfig, ClientChannel, ZigbeeChannel -@registries.ZIGBEE_CHANNEL_REGISTRY.register(closures.DoorLock.cluster_id) -class DoorLockChannel(ZigbeeChannel): - """Door lock channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(closures.DoorLock.cluster_id) +class DoorLockClusterHandler(ClusterHandler): + """Door lock cluster handler.""" _value_attribute = 0 REPORT_CONFIG = ( @@ -107,19 +107,19 @@ class DoorLockChannel(ZigbeeChannel): return result -@registries.ZIGBEE_CHANNEL_REGISTRY.register(closures.Shade.cluster_id) -class Shade(ZigbeeChannel): - """Shade channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(closures.Shade.cluster_id) +class Shade(ClusterHandler): + """Shade cluster handler.""" -@registries.CLIENT_CHANNELS_REGISTRY.register(closures.WindowCovering.cluster_id) -class WindowCoveringClient(ClientChannel): - """Window client channel.""" +@registries.CLIENT_CLUSTER_HANDLER_REGISTRY.register(closures.WindowCovering.cluster_id) +class WindowCoveringClient(ClientClusterHandler): + """Window client cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(closures.WindowCovering.cluster_id) -class WindowCovering(ZigbeeChannel): - """Window channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(closures.WindowCovering.cluster_id) +class WindowCovering(ClusterHandler): + """Window cluster handler.""" _value_attribute = 8 REPORT_CONFIG = ( diff --git a/homeassistant/components/zha/core/channels/general.py b/homeassistant/components/zha/core/cluster_handlers/general.py similarity index 67% rename from homeassistant/components/zha/core/channels/general.py rename to homeassistant/components/zha/core/cluster_handlers/general.py index 47d0cafb01c..ebd2f9f1d81 100644 --- a/homeassistant/components/zha/core/channels/general.py +++ b/homeassistant/components/zha/core/cluster_handlers/general.py @@ -1,4 +1,4 @@ -"""General channels module for Zigbee Home Automation.""" +"""General cluster handlers module for Zigbee Home Automation.""" from __future__ import annotations import asyncio @@ -14,6 +14,12 @@ from zigpy.zcl.foundation import Status from homeassistant.core import callback from homeassistant.helpers.event import async_call_later +from . import ( + AttrReportConfig, + ClientClusterHandler, + ClusterHandler, + parse_and_log_command, +) from .. import registries from ..const import ( REPORT_CONFIG_ASAP, @@ -27,21 +33,20 @@ from ..const import ( SIGNAL_SET_LEVEL, SIGNAL_UPDATE_DEVICE, ) -from .base import AttrReportConfig, ClientChannel, ZigbeeChannel, parse_and_log_command from .helpers import is_hue_motion_sensor if TYPE_CHECKING: - from . import ChannelPool + from ..endpoint import Endpoint -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Alarms.cluster_id) -class Alarms(ZigbeeChannel): - """Alarms channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Alarms.cluster_id) +class Alarms(ClusterHandler): + """Alarms cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.AnalogInput.cluster_id) -class AnalogInput(ZigbeeChannel): - """Analog Input channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.AnalogInput.cluster_id) +class AnalogInput(ClusterHandler): + """Analog Input cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), @@ -49,9 +54,9 @@ class AnalogInput(ZigbeeChannel): @registries.BINDABLE_CLUSTERS.register(general.AnalogOutput.cluster_id) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.AnalogOutput.cluster_id) -class AnalogOutput(ZigbeeChannel): - """Analog Output channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.AnalogOutput.cluster_id) +class AnalogOutput(ClusterHandler): + """Analog Output cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), @@ -120,24 +125,26 @@ class AnalogOutput(ZigbeeChannel): return False -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.AnalogValue.cluster_id) -class AnalogValue(ZigbeeChannel): - """Analog Value channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.AnalogValue.cluster_id) +class AnalogValue(ClusterHandler): + """Analog Value cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.ApplianceControl.cluster_id) -class ApplianceContorl(ZigbeeChannel): - """Appliance Control channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + general.ApplianceControl.cluster_id +) +class ApplianceContorl(ClusterHandler): + """Appliance Control cluster handler.""" -@registries.CHANNEL_ONLY_CLUSTERS.register(general.Basic.cluster_id) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Basic.cluster_id) -class BasicChannel(ZigbeeChannel): - """Channel to interact with the basic cluster.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(general.Basic.cluster_id) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Basic.cluster_id) +class BasicClusterHandler(ClusterHandler): + """Cluster handler to interact with the basic cluster.""" UNKNOWN = 0 BATTERY = 3 @@ -153,9 +160,9 @@ class BasicChannel(ZigbeeChannel): 6: "Emergency mains and transfer switch", } - def __init__(self, cluster: zigpy.zcl.Cluster, ch_pool: ChannelPool) -> None: - """Initialize Basic channel.""" - super().__init__(cluster, ch_pool) + def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None: + """Initialize Basic cluster handler.""" + super().__init__(cluster, endpoint) if is_hue_motion_sensor(self) and self.cluster.endpoint.endpoint_id == 2: self.ZCL_INIT_ATTRS = ( # pylint: disable=invalid-name self.ZCL_INIT_ATTRS.copy() @@ -169,41 +176,43 @@ class BasicChannel(ZigbeeChannel): self.ZCL_INIT_ATTRS["transmit_power"] = True -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.BinaryInput.cluster_id) -class BinaryInput(ZigbeeChannel): - """Binary Input channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.BinaryInput.cluster_id) +class BinaryInput(ClusterHandler): + """Binary Input cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.BinaryOutput.cluster_id) -class BinaryOutput(ZigbeeChannel): - """Binary Output channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.BinaryOutput.cluster_id) +class BinaryOutput(ClusterHandler): + """Binary Output cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.BinaryValue.cluster_id) -class BinaryValue(ZigbeeChannel): - """Binary Value channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.BinaryValue.cluster_id) +class BinaryValue(ClusterHandler): + """Binary Value cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Commissioning.cluster_id) -class Commissioning(ZigbeeChannel): - """Commissioning channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Commissioning.cluster_id) +class Commissioning(ClusterHandler): + """Commissioning cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.DeviceTemperature.cluster_id) -class DeviceTemperature(ZigbeeChannel): - """Device Temperature channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + general.DeviceTemperature.cluster_id +) +class DeviceTemperature(ClusterHandler): + """Device Temperature cluster handler.""" REPORT_CONFIG = ( { @@ -213,23 +222,23 @@ class DeviceTemperature(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.GreenPowerProxy.cluster_id) -class GreenPowerProxy(ZigbeeChannel): - """Green Power Proxy channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.GreenPowerProxy.cluster_id) +class GreenPowerProxy(ClusterHandler): + """Green Power Proxy cluster handler.""" BIND: bool = False -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Groups.cluster_id) -class Groups(ZigbeeChannel): - """Groups channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Groups.cluster_id) +class Groups(ClusterHandler): + """Groups cluster handler.""" BIND: bool = False -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Identify.cluster_id) -class Identify(ZigbeeChannel): - """Identify channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Identify.cluster_id) +class Identify(ClusterHandler): + """Identify cluster handler.""" BIND: bool = False @@ -242,15 +251,15 @@ class Identify(ZigbeeChannel): self.async_send_signal(f"{self.unique_id}_{cmd}", args[0]) -@registries.CLIENT_CHANNELS_REGISTRY.register(general.LevelControl.cluster_id) -class LevelControlClientChannel(ClientChannel): +@registries.CLIENT_CLUSTER_HANDLER_REGISTRY.register(general.LevelControl.cluster_id) +class LevelControlClientClusterHandler(ClientClusterHandler): """LevelControl client cluster.""" @registries.BINDABLE_CLUSTERS.register(general.LevelControl.cluster_id) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.LevelControl.cluster_id) -class LevelControlChannel(ZigbeeChannel): - """Channel for the LevelControl Zigbee cluster.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.LevelControl.cluster_id) +class LevelControlClusterHandler(ClusterHandler): + """Cluster handler for the LevelControl Zigbee cluster.""" CURRENT_LEVEL = 0 REPORT_CONFIG = (AttrReportConfig(attr="current_level", config=REPORT_CONFIG_ASAP),) @@ -299,42 +308,44 @@ class LevelControlChannel(ZigbeeChannel): self.async_send_signal(f"{self.unique_id}_{command}", level) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.MultistateInput.cluster_id) -class MultistateInput(ZigbeeChannel): - """Multistate Input channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.MultistateInput.cluster_id) +class MultistateInput(ClusterHandler): + """Multistate Input cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.MultistateOutput.cluster_id) -class MultistateOutput(ZigbeeChannel): - """Multistate Output channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + general.MultistateOutput.cluster_id +) +class MultistateOutput(ClusterHandler): + """Multistate Output cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.MultistateValue.cluster_id) -class MultistateValue(ZigbeeChannel): - """Multistate Value channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.MultistateValue.cluster_id) +class MultistateValue(ClusterHandler): + """Multistate Value cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="present_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.CLIENT_CHANNELS_REGISTRY.register(general.OnOff.cluster_id) -class OnOffClientChannel(ClientChannel): - """OnOff client channel.""" +@registries.CLIENT_CLUSTER_HANDLER_REGISTRY.register(general.OnOff.cluster_id) +class OnOffClientClusterHandler(ClientClusterHandler): + """OnOff client cluster handler.""" @registries.BINDABLE_CLUSTERS.register(general.OnOff.cluster_id) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.OnOff.cluster_id) -class OnOffChannel(ZigbeeChannel): - """Channel for the OnOff Zigbee cluster.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.OnOff.cluster_id) +class OnOffClusterHandler(ClusterHandler): + """Cluster handler for the OnOff Zigbee cluster.""" ON_OFF = 0 REPORT_CONFIG = (AttrReportConfig(attr="on_off", config=REPORT_CONFIG_IMMEDIATE),) @@ -342,9 +353,9 @@ class OnOffChannel(ZigbeeChannel): "start_up_on_off": True, } - def __init__(self, cluster: zigpy.zcl.Cluster, ch_pool: ChannelPool) -> None: - """Initialize OnOffChannel.""" - super().__init__(cluster, ch_pool) + def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None: + """Initialize OnOffClusterHandler.""" + super().__init__(cluster, endpoint) self._off_listener = None if self.cluster.endpoint.model in ( @@ -404,7 +415,7 @@ class OnOffChannel(ZigbeeChannel): self.cluster.update_attribute(self.ON_OFF, t.Bool.true) if on_time > 0: self._off_listener = async_call_later( - self._ch_pool.hass, + self._endpoint.device.hass, (on_time / 10), # value is in 10ths of a second self.set_to_off, ) @@ -426,24 +437,26 @@ class OnOffChannel(ZigbeeChannel): ) async def async_update(self): - """Initialize channel.""" + """Initialize cluster handler.""" if self.cluster.is_client: return - from_cache = not self._ch_pool.is_mains_powered + from_cache = not self._endpoint.device.is_mains_powered self.debug("attempting to update onoff state - from cache: %s", from_cache) await self.get_attribute_value(self.ON_OFF, from_cache=from_cache) await super().async_update() -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.OnOffConfiguration.cluster_id) -class OnOffConfiguration(ZigbeeChannel): - """OnOff Configuration channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + general.OnOffConfiguration.cluster_id +) +class OnOffConfiguration(ClusterHandler): + """OnOff Configuration cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Ota.cluster_id) -@registries.CLIENT_CHANNELS_REGISTRY.register(general.Ota.cluster_id) -class Ota(ClientChannel): - """OTA Channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Ota.cluster_id) +@registries.CLIENT_CLUSTER_HANDLER_REGISTRY.register(general.Ota.cluster_id) +class Ota(ClientClusterHandler): + """OTA cluster handler.""" BIND: bool = False @@ -457,21 +470,21 @@ class Ota(ClientChannel): else: cmd_name = command_id - signal_id = self._ch_pool.unique_id.split("-")[0] + signal_id = self._endpoint.unique_id.split("-")[0] if cmd_name == "query_next_image": assert args self.async_send_signal(SIGNAL_UPDATE_DEVICE.format(signal_id), args[3]) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Partition.cluster_id) -class Partition(ZigbeeChannel): - """Partition channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Partition.cluster_id) +class Partition(ClusterHandler): + """Partition cluster handler.""" -@registries.CHANNEL_ONLY_CLUSTERS.register(general.PollControl.cluster_id) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.PollControl.cluster_id) -class PollControl(ZigbeeChannel): - """Poll Control channel.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(general.PollControl.cluster_id) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.PollControl.cluster_id) +class PollControl(ClusterHandler): + """Poll Control cluster handler.""" CHECKIN_INTERVAL = 55 * 60 * 4 # 55min CHECKIN_FAST_POLL_TIMEOUT = 2 * 4 # 2s @@ -480,8 +493,8 @@ class PollControl(ZigbeeChannel): 4476, } # IKEA - async def async_configure_channel_specific(self) -> None: - """Configure channel: set check-in interval.""" + async def async_configure_cluster_handler_specific(self) -> None: + """Configure cluster handler: set check-in interval.""" try: res = await self.cluster.write_attributes( {"checkin_interval": self.CHECKIN_INTERVAL} @@ -508,7 +521,7 @@ class PollControl(ZigbeeChannel): async def check_in_response(self, tsn: int) -> None: """Respond to checkin command.""" await self.checkin_response(True, self.CHECKIN_FAST_POLL_TIMEOUT, tsn=tsn) - if self._ch_pool.manufacturer_code not in self._IGNORED_MANUFACTURER_ID: + if self._endpoint.device.manufacturer_code not in self._IGNORED_MANUFACTURER_ID: await self.set_long_poll_interval(self.LONG_POLL) await self.fast_poll_stop() @@ -518,9 +531,11 @@ class PollControl(ZigbeeChannel): self._IGNORED_MANUFACTURER_ID.add(manufacturer_code) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.PowerConfiguration.cluster_id) -class PowerConfigurationChannel(ZigbeeChannel): - """Channel for the zigbee power configuration cluster.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + general.PowerConfiguration.cluster_id +) +class PowerConfigurationCLusterHandler(ClusterHandler): + """Cluster handler for the zigbee power configuration cluster.""" REPORT_CONFIG = ( AttrReportConfig(attr="battery_voltage", config=REPORT_CONFIG_BATTERY_SAVE), @@ -529,8 +544,8 @@ class PowerConfigurationChannel(ZigbeeChannel): ), ) - def async_initialize_channel_specific(self, from_cache: bool) -> Coroutine: - """Initialize channel specific attrs.""" + def async_initialize_cluster_handler_specific(self, from_cache: bool) -> Coroutine: + """Initialize cluster handler specific attrs.""" attributes = [ "battery_size", "battery_quantity", @@ -540,26 +555,26 @@ class PowerConfigurationChannel(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.PowerProfile.cluster_id) -class PowerProfile(ZigbeeChannel): - """Power Profile channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.PowerProfile.cluster_id) +class PowerProfile(ClusterHandler): + """Power Profile cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.RSSILocation.cluster_id) -class RSSILocation(ZigbeeChannel): - """RSSI Location channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.RSSILocation.cluster_id) +class RSSILocation(ClusterHandler): + """RSSI Location cluster handler.""" -@registries.CLIENT_CHANNELS_REGISTRY.register(general.Scenes.cluster_id) -class ScenesClientChannel(ClientChannel): - """Scenes channel.""" +@registries.CLIENT_CLUSTER_HANDLER_REGISTRY.register(general.Scenes.cluster_id) +class ScenesClientClusterHandler(ClientClusterHandler): + """Scenes cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Scenes.cluster_id) -class Scenes(ZigbeeChannel): - """Scenes channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Scenes.cluster_id) +class Scenes(ClusterHandler): + """Scenes cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Time.cluster_id) -class Time(ZigbeeChannel): - """Time channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(general.Time.cluster_id) +class Time(ClusterHandler): + """Time cluster handler.""" diff --git a/homeassistant/components/zha/core/cluster_handlers/helpers.py b/homeassistant/components/zha/core/cluster_handlers/helpers.py new file mode 100644 index 00000000000..17bc5763977 --- /dev/null +++ b/homeassistant/components/zha/core/cluster_handlers/helpers.py @@ -0,0 +1,15 @@ +"""Helpers for use with ZHA Zigbee cluster handlers.""" +from . import ClusterHandler + + +def is_hue_motion_sensor(cluster_handler: ClusterHandler) -> bool: + """Return true if the manufacturer and model match known Hue motion sensor models.""" + return cluster_handler.cluster.endpoint.manufacturer in ( + "Philips", + "Signify Netherlands B.V.", + ) and cluster_handler.cluster.endpoint.model in ( + "SML001", + "SML002", + "SML003", + "SML004", + ) diff --git a/homeassistant/components/zha/core/channels/homeautomation.py b/homeassistant/components/zha/core/cluster_handlers/homeautomation.py similarity index 78% rename from homeassistant/components/zha/core/channels/homeautomation.py rename to homeassistant/components/zha/core/cluster_handlers/homeautomation.py index 69295ef6f81..981ed08ba00 100644 --- a/homeassistant/components/zha/core/channels/homeautomation.py +++ b/homeassistant/components/zha/core/cluster_handlers/homeautomation.py @@ -1,53 +1,55 @@ -"""Home automation channels module for Zigbee Home Automation.""" +"""Home automation cluster handlers module for Zigbee Home Automation.""" from __future__ import annotations import enum from zigpy.zcl.clusters import homeautomation +from . import AttrReportConfig, ClusterHandler from .. import registries from ..const import ( - CHANNEL_ELECTRICAL_MEASUREMENT, + CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT, REPORT_CONFIG_DEFAULT, REPORT_CONFIG_OP, SIGNAL_ATTR_UPDATED, ) -from .base import AttrReportConfig, ZigbeeChannel -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( homeautomation.ApplianceEventAlerts.cluster_id ) -class ApplianceEventAlerts(ZigbeeChannel): - """Appliance Event Alerts channel.""" +class ApplianceEventAlerts(ClusterHandler): + """Appliance Event Alerts cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( homeautomation.ApplianceIdentification.cluster_id ) -class ApplianceIdentification(ZigbeeChannel): - """Appliance Identification channel.""" +class ApplianceIdentification(ClusterHandler): + """Appliance Identification cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( homeautomation.ApplianceStatistics.cluster_id ) -class ApplianceStatistics(ZigbeeChannel): - """Appliance Statistics channel.""" +class ApplianceStatistics(ClusterHandler): + """Appliance Statistics cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(homeautomation.Diagnostic.cluster_id) -class Diagnostic(ZigbeeChannel): - """Diagnostic channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + homeautomation.Diagnostic.cluster_id +) +class Diagnostic(ClusterHandler): + """Diagnostic cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( homeautomation.ElectricalMeasurement.cluster_id ) -class ElectricalMeasurementChannel(ZigbeeChannel): - """Channel that polls active power level.""" +class ElectricalMeasurementClusterHandler(ClusterHandler): + """Cluster handler that polls active power level.""" - CHANNEL_NAME = CHANNEL_ELECTRICAL_MEASUREMENT + CLUSTER_HANDLER_NAME = CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT class MeasurementType(enum.IntFlag): """Measurement types.""" @@ -91,7 +93,7 @@ class ElectricalMeasurementChannel(ZigbeeChannel): """Retrieve latest state.""" self.debug("async_update") - # This is a polling channel. Don't allow cache. + # This is a polling cluster handler. Don't allow cache. attrs = [ a["attr"] for a in self.REPORT_CONFIG @@ -165,8 +167,8 @@ class ElectricalMeasurementChannel(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( homeautomation.MeterIdentification.cluster_id ) -class MeterIdentification(ZigbeeChannel): - """Metering Identification channel.""" +class MeterIdentification(ClusterHandler): + """Metering Identification cluster handler.""" diff --git a/homeassistant/components/zha/core/channels/hvac.py b/homeassistant/components/zha/core/cluster_handlers/hvac.py similarity index 91% rename from homeassistant/components/zha/core/channels/hvac.py rename to homeassistant/components/zha/core/cluster_handlers/hvac.py index 4a73a643b75..94154564e8c 100644 --- a/homeassistant/components/zha/core/channels/hvac.py +++ b/homeassistant/components/zha/core/cluster_handlers/hvac.py @@ -1,4 +1,4 @@ -"""HVAC channels module for Zigbee Home Automation. +"""HVAC cluster handlers module for Zigbee Home Automation. For more details about this component, please refer to the documentation at https://home-assistant.io/integrations/zha/ @@ -14,6 +14,7 @@ from zigpy.zcl.foundation import Status from homeassistant.core import callback +from . import AttrReportConfig, ClusterHandler from .. import registries from ..const import ( REPORT_CONFIG_MAX_INT, @@ -21,7 +22,6 @@ from ..const import ( REPORT_CONFIG_OP, SIGNAL_ATTR_UPDATED, ) -from .base import AttrReportConfig, ZigbeeChannel AttributeUpdateRecord = namedtuple("AttributeUpdateRecord", "attr_id, attr_name, value") REPORT_CONFIG_CLIMATE = (REPORT_CONFIG_MIN_INT, REPORT_CONFIG_MAX_INT, 25) @@ -29,14 +29,14 @@ REPORT_CONFIG_CLIMATE_DEMAND = (REPORT_CONFIG_MIN_INT, REPORT_CONFIG_MAX_INT, 5) REPORT_CONFIG_CLIMATE_DISCRETE = (REPORT_CONFIG_MIN_INT, REPORT_CONFIG_MAX_INT, 1) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(hvac.Dehumidification.cluster_id) -class Dehumidification(ZigbeeChannel): - """Dehumidification channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(hvac.Dehumidification.cluster_id) +class Dehumidification(ClusterHandler): + """Dehumidification cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(hvac.Fan.cluster_id) -class FanChannel(ZigbeeChannel): - """Fan channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(hvac.Fan.cluster_id) +class FanClusterHandler(ClusterHandler): + """Fan cluster handler.""" _value_attribute = 0 @@ -79,14 +79,14 @@ class FanChannel(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(hvac.Pump.cluster_id) -class Pump(ZigbeeChannel): - """Pump channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(hvac.Pump.cluster_id) +class Pump(ClusterHandler): + """Pump cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(hvac.Thermostat.cluster_id) -class ThermostatChannel(ZigbeeChannel): - """Thermostat channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(hvac.Thermostat.cluster_id) +class ThermostatClusterHandler(ClusterHandler): + """Thermostat cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="local_temperature", config=REPORT_CONFIG_CLIMATE), @@ -314,6 +314,6 @@ class ThermostatChannel(ZigbeeChannel): return all(record.status == Status.SUCCESS for record in res[0]) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(hvac.UserInterface.cluster_id) -class UserInterface(ZigbeeChannel): - """User interface (thermostat) channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(hvac.UserInterface.cluster_id) +class UserInterface(ClusterHandler): + """User interface (thermostat) cluster handler.""" diff --git a/homeassistant/components/zha/core/channels/lighting.py b/homeassistant/components/zha/core/cluster_handlers/lighting.py similarity index 80% rename from homeassistant/components/zha/core/channels/lighting.py rename to homeassistant/components/zha/core/cluster_handlers/lighting.py index 55d77d507fd..56f3c701aa1 100644 --- a/homeassistant/components/zha/core/channels/lighting.py +++ b/homeassistant/components/zha/core/cluster_handlers/lighting.py @@ -1,29 +1,29 @@ -"""Lighting channels module for Zigbee Home Automation.""" +"""Lighting cluster handlers module for Zigbee Home Automation.""" from __future__ import annotations from functools import cached_property from zigpy.zcl.clusters import lighting +from . import AttrReportConfig, ClientClusterHandler, ClusterHandler from .. import registries from ..const import REPORT_CONFIG_DEFAULT -from .base import AttrReportConfig, ClientChannel, ZigbeeChannel -@registries.ZIGBEE_CHANNEL_REGISTRY.register(lighting.Ballast.cluster_id) -class Ballast(ZigbeeChannel): - """Ballast channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(lighting.Ballast.cluster_id) +class Ballast(ClusterHandler): + """Ballast cluster handler.""" -@registries.CLIENT_CHANNELS_REGISTRY.register(lighting.Color.cluster_id) -class ColorClientChannel(ClientChannel): - """Color client channel.""" +@registries.CLIENT_CLUSTER_HANDLER_REGISTRY.register(lighting.Color.cluster_id) +class ColorClientClusterHandler(ClientClusterHandler): + """Color client cluster handler.""" @registries.BINDABLE_CLUSTERS.register(lighting.Color.cluster_id) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(lighting.Color.cluster_id) -class ColorChannel(ZigbeeChannel): - """Color channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(lighting.Color.cluster_id) +class ColorClusterHandler(ClusterHandler): + """Color cluster handler.""" CAPABILITIES_COLOR_XY = 0x08 CAPABILITIES_COLOR_TEMP = 0x10 @@ -98,7 +98,7 @@ class ColorChannel(ZigbeeChannel): @property def min_mireds(self) -> int: - """Return the coldest color_temp that this channel supports.""" + """Return the coldest color_temp that this cluster handler supports.""" min_mireds = self.cluster.get("color_temp_physical_min", self.MIN_MIREDS) if min_mireds == 0: self.warning( @@ -113,7 +113,7 @@ class ColorChannel(ZigbeeChannel): @property def max_mireds(self) -> int: - """Return the warmest color_temp that this channel supports.""" + """Return the warmest color_temp that this cluster handler supports.""" max_mireds = self.cluster.get("color_temp_physical_max", self.MAX_MIREDS) if max_mireds == 0: self.warning( @@ -128,7 +128,7 @@ class ColorChannel(ZigbeeChannel): @property def hs_supported(self) -> bool: - """Return True if the channel supports hue and saturation.""" + """Return True if the cluster handler supports hue and saturation.""" return ( self.color_capabilities is not None and lighting.Color.ColorCapabilities.Hue_and_saturation @@ -137,7 +137,7 @@ class ColorChannel(ZigbeeChannel): @property def enhanced_hue_supported(self) -> bool: - """Return True if the channel supports enhanced hue and saturation.""" + """Return True if the cluster handler supports enhanced hue and saturation.""" return ( self.color_capabilities is not None and lighting.Color.ColorCapabilities.Enhanced_hue in self.color_capabilities @@ -145,7 +145,7 @@ class ColorChannel(ZigbeeChannel): @property def xy_supported(self) -> bool: - """Return True if the channel supports xy.""" + """Return True if the cluster handler supports xy.""" return ( self.color_capabilities is not None and lighting.Color.ColorCapabilities.XY_attributes @@ -154,7 +154,7 @@ class ColorChannel(ZigbeeChannel): @property def color_temp_supported(self) -> bool: - """Return True if the channel supports color temperature.""" + """Return True if the cluster handler supports color temperature.""" return ( self.color_capabilities is not None and lighting.Color.ColorCapabilities.Color_temperature @@ -163,7 +163,7 @@ class ColorChannel(ZigbeeChannel): @property def color_loop_supported(self) -> bool: - """Return True if the channel supports color loop.""" + """Return True if the cluster handler supports color loop.""" return ( self.color_capabilities is not None and lighting.Color.ColorCapabilities.Color_loop in self.color_capabilities @@ -171,10 +171,10 @@ class ColorChannel(ZigbeeChannel): @property def options(self) -> lighting.Color.Options: - """Return ZCL options of the channel.""" + """Return ZCL options of the cluster handler.""" return lighting.Color.Options(self.cluster.get("options", 0)) @property def execute_if_off_supported(self) -> bool: - """Return True if the channel can execute commands when off.""" + """Return True if the cluster handler can execute commands when off.""" return lighting.Color.Options.Execute_if_off in self.options diff --git a/homeassistant/components/zha/core/channels/lightlink.py b/homeassistant/components/zha/core/cluster_handlers/lightlink.py similarity index 69% rename from homeassistant/components/zha/core/channels/lightlink.py rename to homeassistant/components/zha/core/cluster_handlers/lightlink.py index cd3fc00ac28..437a4b4ecf8 100644 --- a/homeassistant/components/zha/core/channels/lightlink.py +++ b/homeassistant/components/zha/core/cluster_handlers/lightlink.py @@ -1,29 +1,29 @@ -"""Lightlink channels module for Zigbee Home Automation.""" +"""Lightlink cluster handlers module for Zigbee Home Automation.""" import asyncio import zigpy.exceptions from zigpy.zcl.clusters import lightlink from zigpy.zcl.foundation import GENERAL_COMMANDS, GeneralCommand +from . import ClusterHandler, ClusterHandlerStatus from .. import registries -from .base import ChannelStatus, ZigbeeChannel -@registries.CHANNEL_ONLY_CLUSTERS.register(lightlink.LightLink.cluster_id) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(lightlink.LightLink.cluster_id) -class LightLink(ZigbeeChannel): - """Lightlink channel.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(lightlink.LightLink.cluster_id) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(lightlink.LightLink.cluster_id) +class LightLink(ClusterHandler): + """Lightlink cluster handler.""" BIND: bool = False async def async_configure(self) -> None: """Add Coordinator to LightLink group.""" - if self._ch_pool.skip_configuration: - self._status = ChannelStatus.CONFIGURED + if self._endpoint.device.skip_configuration: + self._status = ClusterHandlerStatus.CONFIGURED return - application = self._ch_pool.endpoint.device.application + application = self._endpoint.zigpy_endpoint.device.application try: coordinator = application.get_device(application.state.node_info.ieee) except KeyError: diff --git a/homeassistant/components/zha/core/channels/manufacturerspecific.py b/homeassistant/components/zha/core/cluster_handlers/manufacturerspecific.py similarity index 78% rename from homeassistant/components/zha/core/channels/manufacturerspecific.py rename to homeassistant/components/zha/core/cluster_handlers/manufacturerspecific.py index 20848453e2a..e4d91a82fe8 100644 --- a/homeassistant/components/zha/core/channels/manufacturerspecific.py +++ b/homeassistant/components/zha/core/cluster_handlers/manufacturerspecific.py @@ -1,4 +1,4 @@ -"""Manufacturer specific channels module for Zigbee Home Automation.""" +"""Manufacturer specific cluster handlers module for Zigbee Home Automation.""" from __future__ import annotations import logging @@ -10,6 +10,7 @@ import zigpy.zcl from homeassistant.core import callback +from . import AttrReportConfig, ClientClusterHandler, ClusterHandler from .. import registries from ..const import ( ATTR_ATTRIBUTE_ID, @@ -23,17 +24,18 @@ from ..const import ( SIGNAL_ATTR_UPDATED, UNKNOWN, ) -from .base import AttrReportConfig, ClientChannel, ZigbeeChannel if TYPE_CHECKING: - from . import ChannelPool + from ..endpoint import Endpoint _LOGGER = logging.getLogger(__name__) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(registries.SMARTTHINGS_HUMIDITY_CLUSTER) -class SmartThingsHumidity(ZigbeeChannel): - """Smart Things Humidity channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + registries.SMARTTHINGS_HUMIDITY_CLUSTER +) +class SmartThingsHumidity(ClusterHandler): + """Smart Things Humidity cluster handler.""" REPORT_CONFIG = ( { @@ -43,32 +45,34 @@ class SmartThingsHumidity(ZigbeeChannel): ) -@registries.CHANNEL_ONLY_CLUSTERS.register(0xFD00) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(0xFD00) -class OsramButton(ZigbeeChannel): - """Osram button channel.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(0xFD00) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(0xFD00) +class OsramButton(ClusterHandler): + """Osram button cluster handler.""" REPORT_CONFIG = () -@registries.CHANNEL_ONLY_CLUSTERS.register(registries.PHILLIPS_REMOTE_CLUSTER) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(registries.PHILLIPS_REMOTE_CLUSTER) -class PhillipsRemote(ZigbeeChannel): - """Phillips remote channel.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(registries.PHILLIPS_REMOTE_CLUSTER) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(registries.PHILLIPS_REMOTE_CLUSTER) +class PhillipsRemote(ClusterHandler): + """Phillips remote cluster handler.""" REPORT_CONFIG = () -@registries.CHANNEL_ONLY_CLUSTERS.register(registries.TUYA_MANUFACTURER_CLUSTER) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(registries.TUYA_MANUFACTURER_CLUSTER) -class TuyaChannel(ZigbeeChannel): - """Channel for the Tuya manufacturer Zigbee cluster.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(registries.TUYA_MANUFACTURER_CLUSTER) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + registries.TUYA_MANUFACTURER_CLUSTER +) +class TuyaClusterHandler(ClusterHandler): + """Cluster handler for the Tuya manufacturer Zigbee cluster.""" REPORT_CONFIG = () - def __init__(self, cluster: zigpy.zcl.Cluster, ch_pool: ChannelPool) -> None: - """Initialize TuyaChannel.""" - super().__init__(cluster, ch_pool) + def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None: + """Initialize TuyaClusterHandler.""" + super().__init__(cluster, endpoint) if self.cluster.endpoint.manufacturer in ( "_TZE200_7tdtqgwv", @@ -94,16 +98,16 @@ class TuyaChannel(ZigbeeChannel): } -@registries.CHANNEL_ONLY_CLUSTERS.register(0xFCC0) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(0xFCC0) -class OppleRemote(ZigbeeChannel): - """Opple channel.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(0xFCC0) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(0xFCC0) +class OppleRemote(ClusterHandler): + """Opple cluster handler.""" REPORT_CONFIG = () - def __init__(self, cluster: zigpy.zcl.Cluster, ch_pool: ChannelPool) -> None: - """Initialize Opple channel.""" - super().__init__(cluster, ch_pool) + def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None: + """Initialize Opple cluster handler.""" + super().__init__(cluster, endpoint) if self.cluster.endpoint.model == "lumi.motion.ac02": self.ZCL_INIT_ATTRS = { # pylint: disable=invalid-name "detection_interval": True, @@ -162,8 +166,8 @@ class OppleRemote(ZigbeeChannel): "linkage_alarm": True, } - async def async_initialize_channel_specific(self, from_cache: bool) -> None: - """Initialize channel specific.""" + async def async_initialize_cluster_handler_specific(self, from_cache: bool) -> None: + """Initialize cluster handler specific.""" if self.cluster.endpoint.model in ("lumi.motion.ac02", "lumi.motion.agl04"): interval = self.cluster.get("detection_interval", self.cluster.get(0x0102)) if interval is not None: @@ -171,11 +175,11 @@ class OppleRemote(ZigbeeChannel): self.cluster.endpoint.ias_zone.reset_s = int(interval) -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( registries.SMARTTHINGS_ACCELERATION_CLUSTER ) -class SmartThingsAcceleration(ZigbeeChannel): - """Smart Things Acceleration channel.""" +class SmartThingsAcceleration(ClusterHandler): + """Smart Things Acceleration cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="acceleration", config=REPORT_CONFIG_ASAP), @@ -211,9 +215,9 @@ class SmartThingsAcceleration(ZigbeeChannel): ) -@registries.CLIENT_CHANNELS_REGISTRY.register(0xFC31) -class InovelliNotificationChannel(ClientChannel): - """Inovelli Notification channel.""" +@registries.CLIENT_CLUSTER_HANDLER_REGISTRY.register(0xFC31) +class InovelliNotificationClusterHandler(ClientClusterHandler): + """Inovelli Notification cluster handler.""" @callback def attribute_updated(self, attrid, value): @@ -224,9 +228,9 @@ class InovelliNotificationChannel(ClientChannel): """Handle a cluster command received on this cluster.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(0xFC31) -class InovelliConfigEntityChannel(ZigbeeChannel): - """Inovelli Configuration Entity channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(0xFC31) +class InovelliConfigEntityClusterHandler(ClusterHandler): + """Inovelli Configuration Entity cluster handler.""" REPORT_CONFIG = () ZCL_INIT_ATTRS = { @@ -307,10 +311,12 @@ class InovelliConfigEntityChannel(ZigbeeChannel): ) -@registries.CHANNEL_ONLY_CLUSTERS.register(registries.IKEA_AIR_PURIFIER_CLUSTER) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(registries.IKEA_AIR_PURIFIER_CLUSTER) -class IkeaAirPurifierChannel(ZigbeeChannel): - """IKEA Air Purifier channel.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(registries.IKEA_AIR_PURIFIER_CLUSTER) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + registries.IKEA_AIR_PURIFIER_CLUSTER +) +class IkeaAirPurifierClusterHandler(ClusterHandler): + """IKEA Air Purifier cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="filter_run_time", config=REPORT_CONFIG_DEFAULT), @@ -360,9 +366,9 @@ class IkeaAirPurifierChannel(ZigbeeChannel): ) -@registries.CHANNEL_ONLY_CLUSTERS.register(0xFC80) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(0xFC80) -class IkeaRemote(ZigbeeChannel): - """Ikea Matter remote channel.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(0xFC80) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(0xFC80) +class IkeaRemote(ClusterHandler): + """Ikea Matter remote cluster handler.""" REPORT_CONFIG = () diff --git a/homeassistant/components/zha/core/channels/measurement.py b/homeassistant/components/zha/core/cluster_handlers/measurement.py similarity index 52% rename from homeassistant/components/zha/core/channels/measurement.py rename to homeassistant/components/zha/core/cluster_handlers/measurement.py index be61a75962e..8b882a299f6 100644 --- a/homeassistant/components/zha/core/channels/measurement.py +++ b/homeassistant/components/zha/core/cluster_handlers/measurement.py @@ -1,4 +1,4 @@ -"""Measurement channels module for Zigbee Home Automation.""" +"""Measurement cluster handlers module for Zigbee Home Automation.""" from __future__ import annotations from typing import TYPE_CHECKING @@ -6,6 +6,7 @@ from typing import TYPE_CHECKING import zigpy.zcl from zigpy.zcl.clusters import measurement +from . import AttrReportConfig, ClusterHandler from .. import registries from ..const import ( REPORT_CONFIG_DEFAULT, @@ -13,55 +14,58 @@ from ..const import ( REPORT_CONFIG_MAX_INT, REPORT_CONFIG_MIN_INT, ) -from .base import AttrReportConfig, ZigbeeChannel from .helpers import is_hue_motion_sensor if TYPE_CHECKING: - from . import ChannelPool + from ..endpoint import Endpoint -@registries.ZIGBEE_CHANNEL_REGISTRY.register(measurement.FlowMeasurement.cluster_id) -class FlowMeasurement(ZigbeeChannel): - """Flow Measurement channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + measurement.FlowMeasurement.cluster_id +) +class FlowMeasurement(ClusterHandler): + """Flow Measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="measured_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( measurement.IlluminanceLevelSensing.cluster_id ) -class IlluminanceLevelSensing(ZigbeeChannel): - """Illuminance Level Sensing channel.""" +class IlluminanceLevelSensing(ClusterHandler): + """Illuminance Level Sensing cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="level_status", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( measurement.IlluminanceMeasurement.cluster_id ) -class IlluminanceMeasurement(ZigbeeChannel): - """Illuminance Measurement channel.""" +class IlluminanceMeasurement(ClusterHandler): + """Illuminance Measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="measured_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(measurement.OccupancySensing.cluster_id) -class OccupancySensing(ZigbeeChannel): - """Occupancy Sensing channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + measurement.OccupancySensing.cluster_id +) +class OccupancySensing(ClusterHandler): + """Occupancy Sensing cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="occupancy", config=REPORT_CONFIG_IMMEDIATE), ) - def __init__(self, cluster: zigpy.zcl.Cluster, ch_pool: ChannelPool) -> None: - """Initialize Occupancy channel.""" - super().__init__(cluster, ch_pool) + def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None: + """Initialize Occupancy cluster handler.""" + super().__init__(cluster, endpoint) if is_hue_motion_sensor(self): self.ZCL_INIT_ATTRS = ( # pylint: disable=invalid-name self.ZCL_INIT_ATTRS.copy() @@ -69,18 +73,22 @@ class OccupancySensing(ZigbeeChannel): self.ZCL_INIT_ATTRS["sensitivity"] = True -@registries.ZIGBEE_CHANNEL_REGISTRY.register(measurement.PressureMeasurement.cluster_id) -class PressureMeasurement(ZigbeeChannel): - """Pressure measurement channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + measurement.PressureMeasurement.cluster_id +) +class PressureMeasurement(ClusterHandler): + """Pressure measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="measured_value", config=REPORT_CONFIG_DEFAULT), ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(measurement.RelativeHumidity.cluster_id) -class RelativeHumidity(ZigbeeChannel): - """Relative Humidity measurement channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + measurement.RelativeHumidity.cluster_id +) +class RelativeHumidity(ClusterHandler): + """Relative Humidity measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig( @@ -90,9 +98,11 @@ class RelativeHumidity(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(measurement.SoilMoisture.cluster_id) -class SoilMoisture(ZigbeeChannel): - """Soil Moisture measurement channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + measurement.SoilMoisture.cluster_id +) +class SoilMoisture(ClusterHandler): + """Soil Moisture measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig( @@ -102,9 +112,9 @@ class SoilMoisture(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(measurement.LeafWetness.cluster_id) -class LeafWetness(ZigbeeChannel): - """Leaf Wetness measurement channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(measurement.LeafWetness.cluster_id) +class LeafWetness(ClusterHandler): + """Leaf Wetness measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig( @@ -114,11 +124,11 @@ class LeafWetness(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( measurement.TemperatureMeasurement.cluster_id ) -class TemperatureMeasurement(ZigbeeChannel): - """Temperature measurement channel.""" +class TemperatureMeasurement(ClusterHandler): + """Temperature measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig( @@ -128,11 +138,11 @@ class TemperatureMeasurement(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( measurement.CarbonMonoxideConcentration.cluster_id ) -class CarbonMonoxideConcentration(ZigbeeChannel): - """Carbon Monoxide measurement channel.""" +class CarbonMonoxideConcentration(ClusterHandler): + """Carbon Monoxide measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig( @@ -142,11 +152,11 @@ class CarbonMonoxideConcentration(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( measurement.CarbonDioxideConcentration.cluster_id ) -class CarbonDioxideConcentration(ZigbeeChannel): - """Carbon Dioxide measurement channel.""" +class CarbonDioxideConcentration(ClusterHandler): + """Carbon Dioxide measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig( @@ -156,9 +166,9 @@ class CarbonDioxideConcentration(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(measurement.PM25.cluster_id) -class PM25(ZigbeeChannel): - """Particulate Matter 2.5 microns or less measurement channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(measurement.PM25.cluster_id) +class PM25(ClusterHandler): + """Particulate Matter 2.5 microns or less measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig( @@ -168,11 +178,11 @@ class PM25(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register( +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( measurement.FormaldehydeConcentration.cluster_id ) -class FormaldehydeConcentration(ZigbeeChannel): - """Formaldehyde measurement channel.""" +class FormaldehydeConcentration(ClusterHandler): + """Formaldehyde measurement cluster handler.""" REPORT_CONFIG = ( AttrReportConfig( diff --git a/homeassistant/components/zha/core/cluster_handlers/protocol.py b/homeassistant/components/zha/core/cluster_handlers/protocol.py new file mode 100644 index 00000000000..6398a8875b6 --- /dev/null +++ b/homeassistant/components/zha/core/cluster_handlers/protocol.py @@ -0,0 +1,143 @@ +"""Protocol cluster handlers module for Zigbee Home Automation.""" +from zigpy.zcl.clusters import protocol + +from . import ClusterHandler +from .. import registries + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.AnalogInputExtended.cluster_id +) +class AnalogInputExtended(ClusterHandler): + """Analog Input Extended cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.AnalogInputRegular.cluster_id +) +class AnalogInputRegular(ClusterHandler): + """Analog Input Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.AnalogOutputExtended.cluster_id +) +class AnalogOutputExtended(ClusterHandler): + """Analog Output Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.AnalogOutputRegular.cluster_id +) +class AnalogOutputRegular(ClusterHandler): + """Analog Output Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.AnalogValueExtended.cluster_id +) +class AnalogValueExtended(ClusterHandler): + """Analog Value Extended edition cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.AnalogValueRegular.cluster_id +) +class AnalogValueRegular(ClusterHandler): + """Analog Value Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.BacnetProtocolTunnel.cluster_id +) +class BacnetProtocolTunnel(ClusterHandler): + """Bacnet Protocol Tunnel cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.BinaryInputExtended.cluster_id +) +class BinaryInputExtended(ClusterHandler): + """Binary Input Extended cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.BinaryInputRegular.cluster_id +) +class BinaryInputRegular(ClusterHandler): + """Binary Input Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.BinaryOutputExtended.cluster_id +) +class BinaryOutputExtended(ClusterHandler): + """Binary Output Extended cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.BinaryOutputRegular.cluster_id +) +class BinaryOutputRegular(ClusterHandler): + """Binary Output Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.BinaryValueExtended.cluster_id +) +class BinaryValueExtended(ClusterHandler): + """Binary Value Extended cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.BinaryValueRegular.cluster_id +) +class BinaryValueRegular(ClusterHandler): + """Binary Value Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(protocol.GenericTunnel.cluster_id) +class GenericTunnel(ClusterHandler): + """Generic Tunnel cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.MultistateInputExtended.cluster_id +) +class MultiStateInputExtended(ClusterHandler): + """Multistate Input Extended cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.MultistateInputRegular.cluster_id +) +class MultiStateInputRegular(ClusterHandler): + """Multistate Input Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.MultistateOutputExtended.cluster_id +) +class MultiStateOutputExtended(ClusterHandler): + """Multistate Output Extended cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.MultistateOutputRegular.cluster_id +) +class MultiStateOutputRegular(ClusterHandler): + """Multistate Output Regular cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.MultistateValueExtended.cluster_id +) +class MultiStateValueExtended(ClusterHandler): + """Multistate Value Extended cluster handler.""" + + +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + protocol.MultistateValueRegular.cluster_id +) +class MultiStateValueRegular(ClusterHandler): + """Multistate Value Regular cluster handler.""" diff --git a/homeassistant/components/zha/core/channels/security.py b/homeassistant/components/zha/core/cluster_handlers/security.py similarity index 90% rename from homeassistant/components/zha/core/channels/security.py rename to homeassistant/components/zha/core/cluster_handlers/security.py index 5ecce49267c..7e4951ad672 100644 --- a/homeassistant/components/zha/core/channels/security.py +++ b/homeassistant/components/zha/core/cluster_handlers/security.py @@ -1,4 +1,4 @@ -"""Security channels module for Zigbee Home Automation. +"""Security cluster handlers module for Zigbee Home Automation. For more details about this component, please refer to the documentation at https://home-assistant.io/integrations/zha/ @@ -15,6 +15,7 @@ from zigpy.zcl.clusters.security import IasAce as AceCluster, IasZone from homeassistant.core import callback +from . import ClusterHandler, ClusterHandlerStatus from .. import registries from ..const import ( SIGNAL_ATTR_UPDATED, @@ -24,10 +25,9 @@ from ..const import ( WARNING_DEVICE_STROBE_HIGH, WARNING_DEVICE_STROBE_YES, ) -from .base import ChannelStatus, ZigbeeChannel if TYPE_CHECKING: - from . import ChannelPool + from ..endpoint import Endpoint IAS_ACE_ARM = 0x0000 # ("arm", (t.enum8, t.CharacterString, t.uint8_t), False), IAS_ACE_BYPASS = 0x0001 # ("bypass", (t.LVList(t.uint8_t), t.CharacterString), False), @@ -46,13 +46,13 @@ SIGNAL_ARMED_STATE_CHANGED = "zha_armed_state_changed" SIGNAL_ALARM_TRIGGERED = "zha_armed_triggered" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(AceCluster.cluster_id) -class IasAce(ZigbeeChannel): - """IAS Ancillary Control Equipment channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(AceCluster.cluster_id) +class IasAce(ClusterHandler): + """IAS Ancillary Control Equipment cluster handler.""" - def __init__(self, cluster: zigpy.zcl.Cluster, ch_pool: ChannelPool) -> None: - """Initialize IAS Ancillary Control Equipment channel.""" - super().__init__(cluster, ch_pool) + def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None: + """Initialize IAS Ancillary Control Equipment cluster handler.""" + super().__init__(cluster, endpoint) self.command_map: dict[int, Callable[..., Any]] = { IAS_ACE_ARM: self.arm, IAS_ACE_BYPASS: self._bypass, @@ -105,7 +105,7 @@ class IasAce(ZigbeeChannel): ) zigbee_reply = self.arm_map[mode](code) - self._ch_pool.hass.async_create_task(zigbee_reply) + self._endpoint.device.hass.async_create_task(zigbee_reply) if self.invalid_tries >= self.max_invalid_tries: self.alarm_status = AceCluster.AlarmStatus.Emergency @@ -228,7 +228,7 @@ class IasAce(ZigbeeChannel): AceCluster.AudibleNotification.Default_Sound, self.alarm_status, ) - self._ch_pool.hass.async_create_task(response) + self._endpoint.device.hass.async_create_task(response) def _send_panel_status_changed(self) -> None: """Handle the IAS ACE panel status changed command.""" @@ -238,7 +238,7 @@ class IasAce(ZigbeeChannel): AceCluster.AudibleNotification.Default_Sound, self.alarm_status, ) - self._ch_pool.hass.async_create_task(response) + self._endpoint.device.hass.async_create_task(response) def _get_bypassed_zone_list(self): """Handle the IAS ACE bypassed zone list command.""" @@ -249,10 +249,10 @@ class IasAce(ZigbeeChannel): """Handle the IAS ACE zone status command.""" -@registries.CHANNEL_ONLY_CLUSTERS.register(security.IasWd.cluster_id) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(security.IasWd.cluster_id) -class IasWd(ZigbeeChannel): - """IAS Warning Device channel.""" +@registries.CLUSTER_HANDLER_ONLY_CLUSTERS.register(security.IasWd.cluster_id) +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(security.IasWd.cluster_id) +class IasWd(ClusterHandler): + """IAS Warning Device cluster handler.""" @staticmethod def set_bit(destination_value, destination_bit, source_value, source_bit): @@ -332,9 +332,9 @@ class IasWd(ZigbeeChannel): ) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(IasZone.cluster_id) -class IASZoneChannel(ZigbeeChannel): - """Channel for the IASZone Zigbee cluster.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(IasZone.cluster_id) +class IASZoneClusterHandler(ClusterHandler): + """Cluster handler for the IASZone Zigbee cluster.""" ZCL_INIT_ATTRS = {"zone_status": False, "zone_state": True, "zone_type": True} @@ -356,11 +356,11 @@ class IASZoneChannel(ZigbeeChannel): async def async_configure(self): """Configure IAS device.""" await self.get_attribute_value("zone_type", from_cache=False) - if self._ch_pool.skip_configuration: - self.debug("skipping IASZoneChannel configuration") + if self._endpoint.device.skip_configuration: + self.debug("skipping IASZoneClusterHandler configuration") return - self.debug("started IASZoneChannel configuration") + self.debug("started IASZoneClusterHandler configuration") await self.bind() ieee = self.cluster.endpoint.device.application.state.node_info.ieee @@ -384,8 +384,8 @@ class IASZoneChannel(ZigbeeChannel): self.debug("Sending pro-active IAS enroll response") self._cluster.create_catching_task(self._cluster.enroll_response(0, 0)) - self._status = ChannelStatus.CONFIGURED - self.debug("finished IASZoneChannel configuration") + self._status = ClusterHandlerStatus.CONFIGURED + self.debug("finished IASZoneClusterHandler configuration") @callback def attribute_updated(self, attrid, value): diff --git a/homeassistant/components/zha/core/channels/smartenergy.py b/homeassistant/components/zha/core/cluster_handlers/smartenergy.py similarity index 74% rename from homeassistant/components/zha/core/channels/smartenergy.py rename to homeassistant/components/zha/core/cluster_handlers/smartenergy.py index 03d11356f0a..1cb647ea313 100644 --- a/homeassistant/components/zha/core/channels/smartenergy.py +++ b/homeassistant/components/zha/core/cluster_handlers/smartenergy.py @@ -1,4 +1,4 @@ -"""Smart energy channels module for Zigbee Home Automation.""" +"""Smart energy cluster handlers module for Zigbee Home Automation.""" from __future__ import annotations import enum @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING import zigpy.zcl from zigpy.zcl.clusters import smartenergy +from . import AttrReportConfig, ClusterHandler from .. import registries from ..const import ( REPORT_CONFIG_ASAP, @@ -15,55 +16,60 @@ from ..const import ( REPORT_CONFIG_OP, SIGNAL_ATTR_UPDATED, ) -from .base import AttrReportConfig, ZigbeeChannel if TYPE_CHECKING: - from . import ChannelPool + from ..endpoint import Endpoint -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.Calendar.cluster_id) -class Calendar(ZigbeeChannel): - """Calendar channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.Calendar.cluster_id) +class Calendar(ClusterHandler): + """Calendar cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.DeviceManagement.cluster_id) -class DeviceManagement(ZigbeeChannel): - """Device Management channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + smartenergy.DeviceManagement.cluster_id +) +class DeviceManagement(ClusterHandler): + """Device Management cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.Drlc.cluster_id) -class Drlc(ZigbeeChannel): - """Demand Response and Load Control channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.Drlc.cluster_id) +class Drlc(ClusterHandler): + """Demand Response and Load Control cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.EnergyManagement.cluster_id) -class EnergyManagement(ZigbeeChannel): - """Energy Management channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + smartenergy.EnergyManagement.cluster_id +) +class EnergyManagement(ClusterHandler): + """Energy Management cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.Events.cluster_id) -class Events(ZigbeeChannel): - """Event channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.Events.cluster_id) +class Events(ClusterHandler): + """Event cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.KeyEstablishment.cluster_id) -class KeyEstablishment(ZigbeeChannel): - """Key Establishment channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register( + smartenergy.KeyEstablishment.cluster_id +) +class KeyEstablishment(ClusterHandler): + """Key Establishment cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.MduPairing.cluster_id) -class MduPairing(ZigbeeChannel): - """Pairing channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.MduPairing.cluster_id) +class MduPairing(ClusterHandler): + """Pairing cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.Messaging.cluster_id) -class Messaging(ZigbeeChannel): - """Messaging channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.Messaging.cluster_id) +class Messaging(ClusterHandler): + """Messaging cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.Metering.cluster_id) -class Metering(ZigbeeChannel): - """Metering channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.Metering.cluster_id) +class Metering(ClusterHandler): + """Metering cluster handler.""" REPORT_CONFIG = ( AttrReportConfig(attr="instantaneous_demand", config=REPORT_CONFIG_OP), @@ -137,9 +143,9 @@ class Metering(ZigbeeChannel): DEMAND = 0 SUMMATION = 1 - def __init__(self, cluster: zigpy.zcl.Cluster, ch_pool: ChannelPool) -> None: + def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None: """Initialize Metering.""" - super().__init__(cluster, ch_pool) + super().__init__(cluster, endpoint) self._format_spec: str | None = None self._summa_format: str | None = None @@ -176,7 +182,7 @@ class Metering(ZigbeeChannel): """Return unit of measurement.""" return self.cluster.get("unit_of_measure") - async def async_initialize_channel_specific(self, from_cache: bool) -> None: + async def async_initialize_cluster_handler_specific(self, from_cache: bool) -> None: """Fetch config from device and updates format specifier.""" fmting = self.cluster.get( @@ -249,16 +255,16 @@ class Metering(ZigbeeChannel): summa_formatter = partialmethod(_formatter_function, FormatSelector.SUMMATION) -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.Prepayment.cluster_id) -class Prepayment(ZigbeeChannel): - """Prepayment channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.Prepayment.cluster_id) +class Prepayment(ClusterHandler): + """Prepayment cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.Price.cluster_id) -class Price(ZigbeeChannel): - """Price channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.Price.cluster_id) +class Price(ClusterHandler): + """Price cluster handler.""" -@registries.ZIGBEE_CHANNEL_REGISTRY.register(smartenergy.Tunneling.cluster_id) -class Tunneling(ZigbeeChannel): - """Tunneling channel.""" +@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(smartenergy.Tunneling.cluster_id) +class Tunneling(ClusterHandler): + """Tunneling cluster handler.""" diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 6423723d326..de4272032d8 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -64,39 +64,39 @@ ATTR_WARNING_DEVICE_STROBE_INTENSITY = "intensity" BAUD_RATES = [2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, 128000, 256000] BINDINGS = "bindings" -CHANNEL_ACCELEROMETER = "accelerometer" -CHANNEL_BINARY_INPUT = "binary_input" -CHANNEL_ANALOG_INPUT = "analog_input" -CHANNEL_ANALOG_OUTPUT = "analog_output" -CHANNEL_ATTRIBUTE = "attribute" -CHANNEL_BASIC = "basic" -CHANNEL_COLOR = "light_color" -CHANNEL_COVER = "window_covering" -CHANNEL_DEVICE_TEMPERATURE = "device_temperature" -CHANNEL_DOORLOCK = "door_lock" -CHANNEL_ELECTRICAL_MEASUREMENT = "electrical_measurement" -CHANNEL_EVENT_RELAY = "event_relay" -CHANNEL_FAN = "fan" -CHANNEL_HUMIDITY = "humidity" -CHANNEL_SOIL_MOISTURE = "soil_moisture" -CHANNEL_LEAF_WETNESS = "leaf_wetness" -CHANNEL_IAS_ACE = "ias_ace" -CHANNEL_IAS_WD = "ias_wd" -CHANNEL_IDENTIFY = "identify" -CHANNEL_ILLUMINANCE = "illuminance" -CHANNEL_LEVEL = ATTR_LEVEL -CHANNEL_MULTISTATE_INPUT = "multistate_input" -CHANNEL_OCCUPANCY = "occupancy" -CHANNEL_ON_OFF = "on_off" -CHANNEL_POWER_CONFIGURATION = "power" -CHANNEL_PRESSURE = "pressure" -CHANNEL_SHADE = "shade" -CHANNEL_SMARTENERGY_METERING = "smartenergy_metering" -CHANNEL_TEMPERATURE = "temperature" -CHANNEL_THERMOSTAT = "thermostat" -CHANNEL_ZDO = "zdo" -CHANNEL_ZONE = ZONE = "ias_zone" -CHANNEL_INOVELLI = "inovelli_vzm31sn_cluster" +CLUSTER_HANDLER_ACCELEROMETER = "accelerometer" +CLUSTER_HANDLER_BINARY_INPUT = "binary_input" +CLUSTER_HANDLER_ANALOG_INPUT = "analog_input" +CLUSTER_HANDLER_ANALOG_OUTPUT = "analog_output" +CLUSTER_HANDLER_ATTRIBUTE = "attribute" +CLUSTER_HANDLER_BASIC = "basic" +CLUSTER_HANDLER_COLOR = "light_color" +CLUSTER_HANDLER_COVER = "window_covering" +CLUSTER_HANDLER_DEVICE_TEMPERATURE = "device_temperature" +CLUSTER_HANDLER_DOORLOCK = "door_lock" +CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT = "electrical_measurement" +CLUSTER_HANDLER_EVENT_RELAY = "event_relay" +CLUSTER_HANDLER_FAN = "fan" +CLUSTER_HANDLER_HUMIDITY = "humidity" +CLUSTER_HANDLER_SOIL_MOISTURE = "soil_moisture" +CLUSTER_HANDLER_LEAF_WETNESS = "leaf_wetness" +CLUSTER_HANDLER_IAS_ACE = "ias_ace" +CLUSTER_HANDLER_IAS_WD = "ias_wd" +CLUSTER_HANDLER_IDENTIFY = "identify" +CLUSTER_HANDLER_ILLUMINANCE = "illuminance" +CLUSTER_HANDLER_LEVEL = ATTR_LEVEL +CLUSTER_HANDLER_MULTISTATE_INPUT = "multistate_input" +CLUSTER_HANDLER_OCCUPANCY = "occupancy" +CLUSTER_HANDLER_ON_OFF = "on_off" +CLUSTER_HANDLER_POWER_CONFIGURATION = "power" +CLUSTER_HANDLER_PRESSURE = "pressure" +CLUSTER_HANDLER_SHADE = "shade" +CLUSTER_HANDLER_SMARTENERGY_METERING = "smartenergy_metering" +CLUSTER_HANDLER_TEMPERATURE = "temperature" +CLUSTER_HANDLER_THERMOSTAT = "thermostat" +CLUSTER_HANDLER_ZDO = "zdo" +CLUSTER_HANDLER_ZONE = ZONE = "ias_zone" +CLUSTER_HANDLER_INOVELLI = "inovelli_vzm31sn_cluster" CLUSTER_COMMAND_SERVER = "server" CLUSTER_COMMANDS_CLIENT = "client_commands" @@ -330,15 +330,15 @@ REPORT_CONFIG_OP = ( SENSOR_ACCELERATION = "acceleration" SENSOR_BATTERY = "battery" -SENSOR_ELECTRICAL_MEASUREMENT = CHANNEL_ELECTRICAL_MEASUREMENT +SENSOR_ELECTRICAL_MEASUREMENT = CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT SENSOR_GENERIC = "generic" -SENSOR_HUMIDITY = CHANNEL_HUMIDITY -SENSOR_ILLUMINANCE = CHANNEL_ILLUMINANCE +SENSOR_HUMIDITY = CLUSTER_HANDLER_HUMIDITY +SENSOR_ILLUMINANCE = CLUSTER_HANDLER_ILLUMINANCE SENSOR_METERING = "metering" -SENSOR_OCCUPANCY = CHANNEL_OCCUPANCY +SENSOR_OCCUPANCY = CLUSTER_HANDLER_OCCUPANCY SENSOR_OPENING = "opening" -SENSOR_PRESSURE = CHANNEL_PRESSURE -SENSOR_TEMPERATURE = CHANNEL_TEMPERATURE +SENSOR_PRESSURE = CLUSTER_HANDLER_PRESSURE +SENSOR_TEMPERATURE = CLUSTER_HANDLER_TEMPERATURE SENSOR_TYPE = "sensor_type" SIGNAL_ADD_ENTITIES = "zha_add_new_entities" @@ -381,12 +381,12 @@ WARNING_DEVICE_SQUAWK_MODE_ARMED = 0 WARNING_DEVICE_SQUAWK_MODE_DISARMED = 1 ZHA_DISCOVERY_NEW = "zha_discovery_new_{}" -ZHA_CHANNEL_MSG = "zha_channel_message" -ZHA_CHANNEL_MSG_BIND = "zha_channel_bind" -ZHA_CHANNEL_MSG_CFG_RPT = "zha_channel_configure_reporting" -ZHA_CHANNEL_MSG_DATA = "zha_channel_msg_data" -ZHA_CHANNEL_CFG_DONE = "zha_channel_cfg_done" -ZHA_CHANNEL_READS_PER_REQ = 5 +ZHA_CLUSTER_HANDLER_MSG = "zha_channel_message" +ZHA_CLUSTER_HANDLER_MSG_BIND = "zha_channel_bind" +ZHA_CLUSTER_HANDLER_MSG_CFG_RPT = "zha_channel_configure_reporting" +ZHA_CLUSTER_HANDLER_MSG_DATA = "zha_channel_msg_data" +ZHA_CLUSTER_HANDLER_CFG_DONE = "zha_channel_cfg_done" +ZHA_CLUSTER_HANDLER_READS_PER_REQ = 5 ZHA_EVENT = "zha_event" ZHA_GW_MSG = "zha_gateway_message" ZHA_GW_MSG_DEVICE_FULL_INIT = "device_fully_initialized" diff --git a/homeassistant/components/zha/core/decorators.py b/homeassistant/components/zha/core/decorators.py index 5cf9322170f..71bfd510bea 100644 --- a/homeassistant/components/zha/core/decorators.py +++ b/homeassistant/components/zha/core/decorators.py @@ -13,10 +13,10 @@ class DictRegistry(dict[int | str, _TypeT]): def register(self, name: int | str) -> Callable[[_TypeT], _TypeT]: """Return decorator to register item with a specific name.""" - def decorator(channel: _TypeT) -> _TypeT: - """Register decorated channel or item.""" - self[name] = channel - return channel + def decorator(cluster_handler: _TypeT) -> _TypeT: + """Register decorated cluster handler or item.""" + self[name] = cluster_handler + return cluster_handler return decorator @@ -27,9 +27,9 @@ class SetRegistry(set[int | str]): def register(self, name: int | str) -> Callable[[_TypeT], _TypeT]: """Return decorator to register item with a specific name.""" - def decorator(channel: _TypeT) -> _TypeT: - """Register decorated channel or item.""" + def decorator(cluster_handler: _TypeT) -> _TypeT: + """Register decorated cluster handler or item.""" self.add(name) - return channel + return cluster_handler return decorator diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index 9d40314e061..139acb23923 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -23,7 +23,7 @@ from zigpy.zcl.clusters.general import Groups, Identify from zigpy.zcl.foundation import Status as ZclStatus, ZCLCommandDef import zigpy.zdo.types as zdo_types -from homeassistant.const import ATTR_COMMAND, ATTR_NAME +from homeassistant.const import ATTR_COMMAND, ATTR_DEVICE_ID, ATTR_NAME from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.dispatcher import ( @@ -32,7 +32,8 @@ from homeassistant.helpers.dispatcher import ( ) from homeassistant.helpers.event import async_track_time_interval -from . import channels +from . import const +from .cluster_handlers import ClusterHandler, ZDOClusterHandler from .const import ( ATTR_ACTIVE_COORDINATOR, ATTR_ARGS, @@ -81,6 +82,7 @@ from .const import ( UNKNOWN_MODEL, ZHA_OPTIONS, ) +from .endpoint import Endpoint from .helpers import LogMixin, async_get_zha_config_value, convert_to_zcl_values if TYPE_CHECKING: @@ -139,14 +141,26 @@ class ZHADevice(LogMixin): CONF_DEFAULT_CONSIDER_UNAVAILABLE_BATTERY, ) - keep_alive_interval = random.randint(*_UPDATE_ALIVE_INTERVAL) - self.unsubs.append( - async_track_time_interval( - self.hass, self._check_available, timedelta(seconds=keep_alive_interval) - ) - ) + self._zdo_handler: ZDOClusterHandler = ZDOClusterHandler(self) + self._power_config_ch: ClusterHandler | None = None + self._identify_ch: ClusterHandler | None = None + self._basic_ch: ClusterHandler | None = None self.status: DeviceStatus = DeviceStatus.CREATED - self._channels = channels.Channels(self) + + self._endpoints: dict[int, Endpoint] = {} + for ep_id, endpoint in zigpy_device.endpoints.items(): + if ep_id != 0: + self._endpoints[ep_id] = Endpoint.new(endpoint, self) + + if not self.is_coordinator: + keep_alive_interval = random.randint(*_UPDATE_ALIVE_INTERVAL) + self.unsubs.append( + async_track_time_interval( + self.hass, + self._check_available, + timedelta(seconds=keep_alive_interval), + ) + ) @property def device_id(self) -> str: @@ -162,17 +176,6 @@ class ZHADevice(LogMixin): """Return underlying Zigpy device.""" return self._zigpy_device - @property - def channels(self) -> channels.Channels: - """Return ZHA channels.""" - return self._channels - - @channels.setter - def channels(self, value: channels.Channels) -> None: - """Channels setter.""" - assert isinstance(value, channels.Channels) - self._channels = value - @property def name(self) -> str: """Return device name.""" @@ -335,12 +338,62 @@ class ZHADevice(LogMixin): """Set device availability.""" self._available = new_availability + @property + def power_configuration_ch(self) -> ClusterHandler | None: + """Return power configuration cluster handler.""" + return self._power_config_ch + + @power_configuration_ch.setter + def power_configuration_ch(self, cluster_handler: ClusterHandler) -> None: + """Power configuration cluster handler setter.""" + if self._power_config_ch is None: + self._power_config_ch = cluster_handler + + @property + def basic_ch(self) -> ClusterHandler | None: + """Return basic cluster handler.""" + return self._basic_ch + + @basic_ch.setter + def basic_ch(self, cluster_handler: ClusterHandler) -> None: + """Set the basic cluster handler.""" + if self._basic_ch is None: + self._basic_ch = cluster_handler + + @property + def identify_ch(self) -> ClusterHandler | None: + """Return power configuration cluster handler.""" + return self._identify_ch + + @identify_ch.setter + def identify_ch(self, cluster_handler: ClusterHandler) -> None: + """Power configuration cluster handler setter.""" + if self._identify_ch is None: + self._identify_ch = cluster_handler + + @property + def zdo_cluster_handler(self) -> ZDOClusterHandler: + """Return ZDO cluster handler.""" + return self._zdo_handler + + @property + def endpoints(self) -> dict[int, Endpoint]: + """Return the endpoints for this device.""" + return self._endpoints + @property def zigbee_signature(self) -> dict[str, Any]: """Get zigbee signature for this device.""" return { ATTR_NODE_DESCRIPTOR: str(self._zigpy_device.node_desc), - ATTR_ENDPOINTS: self._channels.zigbee_signature, + ATTR_ENDPOINTS: { + signature[0]: signature[1] + for signature in [ + endpoint.zigbee_signature for endpoint in self._endpoints.values() + ] + }, + ATTR_MANUFACTURER: self.manufacturer, + ATTR_MODEL: self.model, } @classmethod @@ -353,11 +406,10 @@ class ZHADevice(LogMixin): ) -> Self: """Create new device.""" zha_dev = cls(hass, zigpy_dev, gateway) - zha_dev.channels = channels.Channels.new(zha_dev) zha_dev.unsubs.append( async_dispatcher_connect( hass, - SIGNAL_UPDATE_DEVICE.format(zha_dev.channels.unique_id), + SIGNAL_UPDATE_DEVICE.format(str(zha_dev.ieee)), zha_dev.async_update_sw_build_id, ) ) @@ -393,7 +445,7 @@ class ZHADevice(LogMixin): if ( self._checkins_missed_count >= _CHECKIN_GRACE_PERIODS or self.manufacturer == "LUMI" - or not self._channels.pools + or not self._endpoints ): self.debug( ( @@ -410,14 +462,13 @@ class ZHADevice(LogMixin): "Attempting to checkin with device - missed checkins: %s", self._checkins_missed_count, ) - try: - pool = self._channels.pools[0] - basic_ch = pool.all_channels[f"{pool.id}:0x0000"] - except KeyError: + if not self.basic_ch: self.debug("does not have a mandatory basic cluster") self.update_available(False) return - res = await basic_ch.get_attribute_value(ATTR_MANUFACTURER, from_cache=False) + res = await self.basic_ch.get_attribute_value( + ATTR_MANUFACTURER, from_cache=False + ) if res is not None: self._checkins_missed_count = 0 @@ -435,22 +486,35 @@ class ZHADevice(LogMixin): availability_changed = self.available ^ available self.available = available if availability_changed and available: - # reinit channels then signal entities + # reinit cluster handlers then signal entities self.debug( "Device availability changed and device became available," - " reinitializing channels" + " reinitializing cluster handlers" ) self.hass.async_create_task(self._async_became_available()) return if availability_changed and not available: self.debug("Device availability changed and device became unavailable") - self._channels.zha_send_event( + self.zha_send_event( { "device_event_type": "device_offline", }, ) async_dispatcher_send(self.hass, f"{self._available_signal}_entity") + @callback + def zha_send_event(self, event_data: dict[str, str | int]) -> None: + """Relay events to hass.""" + self.hass.bus.async_fire( + const.ZHA_EVENT, + { + const.ATTR_DEVICE_IEEE: str(self.ieee), + const.ATTR_UNIQUE_ID: str(self.ieee), + ATTR_DEVICE_ID: self.device_id, + **event_data, + }, + ) + async def _async_became_available(self) -> None: """Update device availability and signal entities.""" await self.async_initialize(False) @@ -489,23 +553,41 @@ class ZHADevice(LogMixin): True, ) self.debug("started configuration") - await self._channels.async_configure() + await self._zdo_handler.async_configure() + self._zdo_handler.debug("'async_configure' stage succeeded") + await asyncio.gather( + *(endpoint.async_configure() for endpoint in self._endpoints.values()) + ) + async_dispatcher_send( + self.hass, + const.ZHA_CLUSTER_HANDLER_MSG, + { + const.ATTR_TYPE: const.ZHA_CLUSTER_HANDLER_CFG_DONE, + }, + ) self.debug("completed configuration") if ( should_identify - and self._channels.identify_ch is not None + and self.identify_ch is not None and not self.skip_configuration ): - await self._channels.identify_ch.trigger_effect( + await self.identify_ch.trigger_effect( effect_id=Identify.EffectIdentifier.Okay, effect_variant=Identify.EffectVariant.Default, ) async def async_initialize(self, from_cache: bool = False) -> None: - """Initialize channels.""" + """Initialize cluster handlers.""" self.debug("started initialization") - await self._channels.async_initialize(from_cache) + await self._zdo_handler.async_initialize(from_cache) + self._zdo_handler.debug("'async_initialize' stage succeeded") + await asyncio.gather( + *( + endpoint.async_initialize(from_cache) + for endpoint in self._endpoints.values() + ) + ) self.debug("power source: %s", self.power_source) self.status = DeviceStatus.INITIALIZED self.debug("completed initialization") diff --git a/homeassistant/components/zha/core/discovery.py b/homeassistant/components/zha/core/discovery.py index d256b98cfb1..e8b6f5f8304 100644 --- a/homeassistant/components/zha/core/discovery.py +++ b/homeassistant/components/zha/core/discovery.py @@ -33,12 +33,27 @@ from .. import ( # noqa: F401 pylint: disable=unused-import, siren, switch, ) -from .channels import base + +# importing cluster handlers updates registries +from .cluster_handlers import ( # noqa: F401 pylint: disable=unused-import, + ClusterHandler, + closures, + general, + homeautomation, + hvac, + lighting, + lightlink, + manufacturerspecific, + measurement, + protocol, + security, + smartenergy, +) if TYPE_CHECKING: from ..entity import ZhaEntity - from .channels import ChannelPool from .device import ZHADevice + from .endpoint import Endpoint from .gateway import ZHAGateway from .group import ZHAGroup @@ -51,7 +66,7 @@ async def async_add_entities( entities: list[ tuple[ type[ZhaEntity], - tuple[str, ZHADevice, list[base.ZigbeeChannel]], + tuple[str, ZHADevice, list[ClusterHandler]], ] ], ) -> None: @@ -65,49 +80,56 @@ async def async_add_entities( class ProbeEndpoint: - """All discovered channels and entities of an endpoint.""" + """All discovered cluster handlers and entities of an endpoint.""" def __init__(self) -> None: """Initialize instance.""" self._device_configs: ConfigType = {} @callback - def discover_entities(self, channel_pool: ChannelPool) -> None: + def discover_entities(self, endpoint: Endpoint) -> None: """Process an endpoint on a zigpy device.""" - self.discover_by_device_type(channel_pool) - self.discover_multi_entities(channel_pool) - self.discover_by_cluster_id(channel_pool) - self.discover_multi_entities(channel_pool, config_diagnostic_entities=True) + _LOGGER.debug( + "Discovering entities for endpoint: %s-%s", + str(endpoint.device.ieee), + endpoint.id, + ) + self.discover_by_device_type(endpoint) + self.discover_multi_entities(endpoint) + self.discover_by_cluster_id(endpoint) + self.discover_multi_entities(endpoint, config_diagnostic_entities=True) zha_regs.ZHA_ENTITIES.clean_up() @callback - def discover_by_device_type(self, channel_pool: ChannelPool) -> None: + def discover_by_device_type(self, endpoint: Endpoint) -> None: """Process an endpoint on a zigpy device.""" - unique_id = channel_pool.unique_id + unique_id = endpoint.unique_id - component: str | None = self._device_configs.get(unique_id, {}).get(CONF_TYPE) - if component is None: - ep_profile_id = channel_pool.endpoint.profile_id - ep_device_type = channel_pool.endpoint.device_type - component = zha_regs.DEVICE_CLASS[ep_profile_id].get(ep_device_type) + platform: str | None = self._device_configs.get(unique_id, {}).get(CONF_TYPE) + if platform is None: + ep_profile_id = endpoint.zigpy_endpoint.profile_id + ep_device_type = endpoint.zigpy_endpoint.device_type + platform = zha_regs.DEVICE_CLASS[ep_profile_id].get(ep_device_type) - if component and component in zha_const.PLATFORMS: - channels = channel_pool.unclaimed_channels() - entity_class, claimed = zha_regs.ZHA_ENTITIES.get_entity( - component, - channel_pool.manufacturer, - channel_pool.model, - channels, - channel_pool.quirk_class, + if platform and platform in zha_const.PLATFORMS: + cluster_handlers = endpoint.unclaimed_cluster_handlers() + platform_entity_class, claimed = zha_regs.ZHA_ENTITIES.get_entity( + platform, + endpoint.device.manufacturer, + endpoint.device.model, + cluster_handlers, + endpoint.device.quirk_class, ) - if entity_class is None: + if platform_entity_class is None: return - channel_pool.claim_channels(claimed) - channel_pool.async_new_entity(component, entity_class, unique_id, claimed) + endpoint.claim_cluster_handlers(claimed) + endpoint.async_new_entity( + platform, platform_entity_class, unique_id, claimed + ) @callback - def discover_by_cluster_id(self, channel_pool: ChannelPool) -> None: + def discover_by_cluster_id(self, endpoint: Endpoint) -> None: """Process an endpoint on a zigpy device.""" items = zha_regs.SINGLE_INPUT_CLUSTER_DEVICE_CLASS.items() @@ -116,124 +138,127 @@ class ProbeEndpoint: for cluster_class, match in items if not isinstance(cluster_class, int) } - remaining_channels = channel_pool.unclaimed_channels() - for channel in remaining_channels: - if channel.cluster.cluster_id in zha_regs.CHANNEL_ONLY_CLUSTERS: - channel_pool.claim_channels([channel]) + remaining_cluster_handlers = endpoint.unclaimed_cluster_handlers() + for cluster_handler in remaining_cluster_handlers: + if ( + cluster_handler.cluster.cluster_id + in zha_regs.CLUSTER_HANDLER_ONLY_CLUSTERS + ): + endpoint.claim_cluster_handlers([cluster_handler]) continue - component = zha_regs.SINGLE_INPUT_CLUSTER_DEVICE_CLASS.get( - channel.cluster.cluster_id + platform = zha_regs.SINGLE_INPUT_CLUSTER_DEVICE_CLASS.get( + cluster_handler.cluster.cluster_id ) - if component is None: + if platform is None: for cluster_class, match in single_input_clusters.items(): - if isinstance(channel.cluster, cluster_class): - component = match + if isinstance(cluster_handler.cluster, cluster_class): + platform = match break - self.probe_single_cluster(component, channel, channel_pool) + self.probe_single_cluster(platform, cluster_handler, endpoint) # until we can get rid of registries - self.handle_on_off_output_cluster_exception(channel_pool) + self.handle_on_off_output_cluster_exception(endpoint) @staticmethod def probe_single_cluster( - component: Platform | None, - channel: base.ZigbeeChannel, - ep_channels: ChannelPool, + platform: Platform | None, + cluster_handler: ClusterHandler, + endpoint: Endpoint, ) -> None: """Probe specified cluster for specific component.""" - if component is None or component not in zha_const.PLATFORMS: + if platform is None or platform not in zha_const.PLATFORMS: return - channel_list = [channel] - unique_id = f"{ep_channels.unique_id}-{channel.cluster.cluster_id}" + cluster_handler_list = [cluster_handler] + unique_id = f"{endpoint.unique_id}-{cluster_handler.cluster.cluster_id}" entity_class, claimed = zha_regs.ZHA_ENTITIES.get_entity( - component, - ep_channels.manufacturer, - ep_channels.model, - channel_list, - ep_channels.quirk_class, + platform, + endpoint.device.manufacturer, + endpoint.device.model, + cluster_handler_list, + endpoint.device.quirk_class, ) if entity_class is None: return - ep_channels.claim_channels(claimed) - ep_channels.async_new_entity(component, entity_class, unique_id, claimed) + endpoint.claim_cluster_handlers(claimed) + endpoint.async_new_entity(platform, entity_class, unique_id, claimed) - def handle_on_off_output_cluster_exception(self, ep_channels: ChannelPool) -> None: + def handle_on_off_output_cluster_exception(self, endpoint: Endpoint) -> None: """Process output clusters of the endpoint.""" - profile_id = ep_channels.endpoint.profile_id - device_type = ep_channels.endpoint.device_type + profile_id = endpoint.zigpy_endpoint.profile_id + device_type = endpoint.zigpy_endpoint.device_type if device_type in zha_regs.REMOTE_DEVICE_TYPES.get(profile_id, []): return - for cluster_id, cluster in ep_channels.endpoint.out_clusters.items(): - component = zha_regs.SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS.get( + for cluster_id, cluster in endpoint.zigpy_endpoint.out_clusters.items(): + platform = zha_regs.SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS.get( cluster.cluster_id ) - if component is None: + if platform is None: continue - channel_class = zha_regs.ZIGBEE_CHANNEL_REGISTRY.get( - cluster_id, base.ZigbeeChannel + cluster_handler_class = zha_regs.ZIGBEE_CLUSTER_HANDLER_REGISTRY.get( + cluster_id, ClusterHandler ) - channel = channel_class(cluster, ep_channels) - self.probe_single_cluster(component, channel, ep_channels) + cluster_handler = cluster_handler_class(cluster, endpoint) + self.probe_single_cluster(platform, cluster_handler, endpoint) @staticmethod @callback def discover_multi_entities( - channel_pool: ChannelPool, + endpoint: Endpoint, config_diagnostic_entities: bool = False, ) -> None: """Process an endpoint on and discover multiple entities.""" - ep_profile_id = channel_pool.endpoint.profile_id - ep_device_type = channel_pool.endpoint.device_type + ep_profile_id = endpoint.zigpy_endpoint.profile_id + ep_device_type = endpoint.zigpy_endpoint.device_type cmpt_by_dev_type = zha_regs.DEVICE_CLASS[ep_profile_id].get(ep_device_type) if config_diagnostic_entities: matches, claimed = zha_regs.ZHA_ENTITIES.get_config_diagnostic_entity( - channel_pool.manufacturer, - channel_pool.model, - list(channel_pool.all_channels.values()), - channel_pool.quirk_class, + endpoint.device.manufacturer, + endpoint.device.model, + list(endpoint.all_cluster_handlers.values()), + endpoint.device.quirk_class, ) else: matches, claimed = zha_regs.ZHA_ENTITIES.get_multi_entity( - channel_pool.manufacturer, - channel_pool.model, - channel_pool.unclaimed_channels(), - channel_pool.quirk_class, + endpoint.device.manufacturer, + endpoint.device.model, + endpoint.unclaimed_cluster_handlers(), + endpoint.device.quirk_class, ) - channel_pool.claim_channels(claimed) - for component, ent_n_chan_list in matches.items(): - for entity_and_channel in ent_n_chan_list: + endpoint.claim_cluster_handlers(claimed) + for platform, ent_n_handler_list in matches.items(): + for entity_and_handler in ent_n_handler_list: _LOGGER.debug( "'%s' component -> '%s' using %s", - component, - entity_and_channel.entity_class.__name__, - [ch.name for ch in entity_and_channel.claimed_channel], + platform, + entity_and_handler.entity_class.__name__, + [ch.name for ch in entity_and_handler.claimed_cluster_handlers], ) - for component, ent_n_chan_list in matches.items(): - for entity_and_channel in ent_n_chan_list: - if component == cmpt_by_dev_type: + for platform, ent_n_handler_list in matches.items(): + for entity_and_handler in ent_n_handler_list: + if platform == cmpt_by_dev_type: # for well known device types, like thermostats we'll take only 1st class - channel_pool.async_new_entity( - component, - entity_and_channel.entity_class, - channel_pool.unique_id, - entity_and_channel.claimed_channel, + endpoint.async_new_entity( + platform, + entity_and_handler.entity_class, + endpoint.unique_id, + entity_and_handler.claimed_cluster_handlers, ) break - first_ch = entity_and_channel.claimed_channel[0] - channel_pool.async_new_entity( - component, - entity_and_channel.entity_class, - f"{channel_pool.unique_id}-{first_ch.cluster.cluster_id}", - entity_and_channel.claimed_channel, + first_ch = entity_and_handler.claimed_cluster_handlers[0] + endpoint.async_new_entity( + platform, + entity_and_handler.entity_class, + f"{endpoint.unique_id}-{first_ch.cluster.cluster_id}", + entity_and_handler.claimed_cluster_handlers, ) def initialize(self, hass: HomeAssistant) -> None: diff --git a/homeassistant/components/zha/core/endpoint.py b/homeassistant/components/zha/core/endpoint.py new file mode 100644 index 00000000000..713c06fe45f --- /dev/null +++ b/homeassistant/components/zha/core/endpoint.py @@ -0,0 +1,220 @@ +"""Representation of a Zigbee endpoint for zha.""" +from __future__ import annotations + +import asyncio +from collections.abc import Callable +import logging +from typing import TYPE_CHECKING, Any, Final, TypeVar + +import zigpy +from zigpy.typing import EndpointType as ZigpyEndpointType + +from homeassistant.const import Platform +from homeassistant.core import callback +from homeassistant.helpers.dispatcher import async_dispatcher_send + +from . import const, discovery, registries +from .cluster_handlers import ClusterHandler +from .cluster_handlers.general import MultistateInput + +if TYPE_CHECKING: + from .cluster_handlers import ClientClusterHandler + from .device import ZHADevice + +ATTR_DEVICE_TYPE: Final[str] = "device_type" +ATTR_PROFILE_ID: Final[str] = "profile_id" +ATTR_IN_CLUSTERS: Final[str] = "input_clusters" +ATTR_OUT_CLUSTERS: Final[str] = "output_clusters" + +_LOGGER = logging.getLogger(__name__) +CALLABLE_T = TypeVar("CALLABLE_T", bound=Callable) # pylint: disable=invalid-name + + +class Endpoint: + """Endpoint for a zha device.""" + + def __init__(self, zigpy_endpoint: ZigpyEndpointType, device: ZHADevice) -> None: + """Initialize instance.""" + assert zigpy_endpoint is not None + assert device is not None + self._zigpy_endpoint: ZigpyEndpointType = zigpy_endpoint + self._device: ZHADevice = device + self._all_cluster_handlers: dict[str, ClusterHandler] = {} + self._claimed_cluster_handlers: dict[str, ClusterHandler] = {} + self._client_cluster_handlers: dict[str, ClientClusterHandler] = {} + self._unique_id: str = f"{str(device.ieee)}-{zigpy_endpoint.endpoint_id}" + + @property + def device(self) -> ZHADevice: + """Return the device this endpoint belongs to.""" + return self._device + + @property + def all_cluster_handlers(self) -> dict[str, ClusterHandler]: + """All server cluster handlers of an endpoint.""" + return self._all_cluster_handlers + + @property + def claimed_cluster_handlers(self) -> dict[str, ClusterHandler]: + """Cluster handlers in use.""" + return self._claimed_cluster_handlers + + @property + def client_cluster_handlers(self) -> dict[str, ClientClusterHandler]: + """Return a dict of client cluster handlers.""" + return self._client_cluster_handlers + + @property + def zigpy_endpoint(self) -> ZigpyEndpointType: + """Return endpoint of zigpy device.""" + return self._zigpy_endpoint + + @property + def id(self) -> int: + """Return endpoint id.""" + return self._zigpy_endpoint.endpoint_id + + @property + def unique_id(self) -> str: + """Return the unique id for this endpoint.""" + return self._unique_id + + @property + def zigbee_signature(self) -> tuple[int, dict[str, Any]]: + """Get the zigbee signature for the endpoint this pool represents.""" + return ( + self.id, + { + ATTR_PROFILE_ID: f"0x{self._zigpy_endpoint.profile_id:04x}" + if self._zigpy_endpoint.profile_id is not None + else "", + ATTR_DEVICE_TYPE: f"0x{self._zigpy_endpoint.device_type:04x}" + if self._zigpy_endpoint.device_type is not None + else "", + ATTR_IN_CLUSTERS: [ + f"0x{cluster_id:04x}" + for cluster_id in sorted(self._zigpy_endpoint.in_clusters) + ], + ATTR_OUT_CLUSTERS: [ + f"0x{cluster_id:04x}" + for cluster_id in sorted(self._zigpy_endpoint.out_clusters) + ], + }, + ) + + @classmethod + def new(cls, zigpy_endpoint: ZigpyEndpointType, device: ZHADevice) -> Endpoint: + """Create new endpoint and populate cluster handlers.""" + endpoint = cls(zigpy_endpoint, device) + endpoint.add_all_cluster_handlers() + endpoint.add_client_cluster_handlers() + if not device.is_coordinator: + discovery.PROBE.discover_entities(endpoint) + return endpoint + + def add_all_cluster_handlers(self) -> None: + """Create and add cluster handlers for all input clusters.""" + for cluster_id, cluster in self.zigpy_endpoint.in_clusters.items(): + cluster_handler_class = registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.get( + cluster_id, ClusterHandler + ) + _LOGGER.info( + "Creating cluster handler for cluster id: %s class: %s", + cluster_id, + cluster_handler_class, + ) + # really ugly hack to deal with xiaomi using the door lock cluster + # incorrectly. + if ( + hasattr(cluster, "ep_attribute") + and cluster_id == zigpy.zcl.clusters.closures.DoorLock.cluster_id + and cluster.ep_attribute == "multistate_input" + ): + cluster_handler_class = MultistateInput + # end of ugly hack + cluster_handler = cluster_handler_class(cluster, self) + if cluster_handler.name == const.CLUSTER_HANDLER_POWER_CONFIGURATION: + self._device.power_configuration_ch = cluster_handler + elif cluster_handler.name == const.CLUSTER_HANDLER_IDENTIFY: + self._device.identify_ch = cluster_handler + elif cluster_handler.name == const.CLUSTER_HANDLER_BASIC: + self._device.basic_ch = cluster_handler + self._all_cluster_handlers[cluster_handler.id] = cluster_handler + + def add_client_cluster_handlers(self) -> None: + """Create client cluster handlers for all output clusters if in the registry.""" + for ( + cluster_id, + cluster_handler_class, + ) in registries.CLIENT_CLUSTER_HANDLER_REGISTRY.items(): + cluster = self.zigpy_endpoint.out_clusters.get(cluster_id) + if cluster is not None: + cluster_handler = cluster_handler_class(cluster, self) + self.client_cluster_handlers[cluster_handler.id] = cluster_handler + + async def async_initialize(self, from_cache: bool = False) -> None: + """Initialize claimed cluster handlers.""" + await self._execute_handler_tasks("async_initialize", from_cache) + + async def async_configure(self) -> None: + """Configure claimed cluster handlers.""" + await self._execute_handler_tasks("async_configure") + + async def _execute_handler_tasks(self, func_name: str, *args: Any) -> None: + """Add a throttled cluster handler task and swallow exceptions.""" + cluster_handlers = [ + *self.claimed_cluster_handlers.values(), + *self.client_cluster_handlers.values(), + ] + tasks = [getattr(ch, func_name)(*args) for ch in cluster_handlers] + results = await asyncio.gather(*tasks, return_exceptions=True) + for cluster_handler, outcome in zip(cluster_handlers, results): + if isinstance(outcome, Exception): + cluster_handler.warning( + "'%s' stage failed: %s", func_name, str(outcome), exc_info=outcome + ) + continue + cluster_handler.debug("'%s' stage succeeded", func_name) + + def async_new_entity( + self, + platform: Platform | str, + entity_class: CALLABLE_T, + unique_id: str, + cluster_handlers: list[ClusterHandler], + ) -> None: + """Create a new entity.""" + from .device import DeviceStatus # pylint: disable=import-outside-toplevel + + if self.device.status == DeviceStatus.INITIALIZED: + return + + self.device.hass.data[const.DATA_ZHA][platform].append( + (entity_class, (unique_id, self.device, cluster_handlers)) + ) + + @callback + def async_send_signal(self, signal: str, *args: Any) -> None: + """Send a signal through hass dispatcher.""" + async_dispatcher_send(self.device.hass, signal, *args) + + def send_event(self, signal: dict[str, Any]) -> None: + """Broadcast an event from this endpoint.""" + signal["endpoint"] = { + "id": self.id, + "unique_id": self.unique_id, + } + self.device.zha_send_event(signal) + + def claim_cluster_handlers(self, cluster_handlers: list[ClusterHandler]) -> None: + """Claim cluster handlers.""" + self.claimed_cluster_handlers.update({ch.id: ch for ch in cluster_handlers}) + + def unclaimed_cluster_handlers(self) -> list[ClusterHandler]: + """Return a list of available (unclaimed) cluster handlers.""" + claimed = set(self.claimed_cluster_handlers) + available = set(self.all_cluster_handlers) + return [ + self.all_cluster_handlers[cluster_id] + for cluster_id in (available - claimed) + ] diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 8858ea69590..4b9089e4690 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -93,7 +93,7 @@ if TYPE_CHECKING: from logging import Filter, LogRecord from ..entity import ZhaEntity - from .channels.base import ZigbeeChannel + from .cluster_handlers import ClusterHandler _LogFilterType = Filter | Callable[[LogRecord], bool] @@ -105,7 +105,7 @@ class EntityReference(NamedTuple): reference_id: str zha_device: ZHADevice - cluster_channels: dict[str, ZigbeeChannel] + cluster_handlers: dict[str, ClusterHandler] device_info: DeviceInfo remove_future: asyncio.Future[Any] @@ -520,7 +520,7 @@ class ZHAGateway: ieee: EUI64, reference_id: str, zha_device: ZHADevice, - cluster_channels: dict[str, ZigbeeChannel], + cluster_handlers: dict[str, ClusterHandler], device_info: DeviceInfo, remove_future: asyncio.Future[Any], ): @@ -529,7 +529,7 @@ class ZHAGateway: EntityReference( reference_id=reference_id, zha_device=zha_device, - cluster_channels=cluster_channels, + cluster_handlers=cluster_handlers, device_info=device_info, remove_future=remove_future, ) diff --git a/homeassistant/components/zha/core/group.py b/homeassistant/components/zha/core/group.py index 82997dc2a53..ebea2f4ac41 100644 --- a/homeassistant/components/zha/core/group.py +++ b/homeassistant/components/zha/core/group.py @@ -89,7 +89,7 @@ class ZHAGroupMember(LogMixin): entity_ref.reference_id, )._asdict() for entity_ref in zha_device_registry.get(self.device.ieee) - if list(entity_ref.cluster_channels.values())[ + if list(entity_ref.cluster_handlers.values())[ 0 ].cluster.endpoint.endpoint_id == self.endpoint_id diff --git a/homeassistant/components/zha/core/helpers.py b/homeassistant/components/zha/core/helpers.py index 526af1a7e49..a86700fdfeb 100644 --- a/homeassistant/components/zha/core/helpers.py +++ b/homeassistant/components/zha/core/helpers.py @@ -336,17 +336,17 @@ def retryable_req( def decorator(func): @functools.wraps(func) - async def wrapper(channel, *args, **kwargs): + async def wrapper(cluster_handler, *args, **kwargs): exceptions = (zigpy.exceptions.ZigbeeException, asyncio.TimeoutError) try_count, errors = 1, [] for delay in itertools.chain(delays, [None]): try: - return await func(channel, *args, **kwargs) + return await func(cluster_handler, *args, **kwargs) except exceptions as ex: errors.append(ex) if delay: delay = uniform(delay * 0.75, delay * 1.25) - channel.debug( + cluster_handler.debug( "%s: retryable request #%d failed: %s. Retrying in %ss", func.__name__, try_count, @@ -356,7 +356,7 @@ def retryable_req( try_count += 1 await asyncio.sleep(delay) else: - channel.warning( + cluster_handler.warning( "%s: all attempts have failed: %s", func.__name__, errors ) if raise_: diff --git a/homeassistant/components/zha/core/registries.py b/homeassistant/components/zha/core/registries.py index a7504ae7a96..0c7369f15e7 100644 --- a/homeassistant/components/zha/core/registries.py +++ b/homeassistant/components/zha/core/registries.py @@ -14,13 +14,11 @@ from zigpy.types.named import EUI64 from homeassistant.const import Platform -# importing channels updates registries -from . import channels as zha_channels # noqa: F401 pylint: disable=unused-import from .decorators import DictRegistry, SetRegistry if TYPE_CHECKING: from ..entity import ZhaEntity, ZhaGroupEntity - from .channels.base import ClientChannel, ZigbeeChannel + from .cluster_handlers import ClientClusterHandler, ClusterHandler _ZhaEntityT = TypeVar("_ZhaEntityT", bound=type["ZhaEntity"]) @@ -75,7 +73,6 @@ SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS = { } BINDABLE_CLUSTERS = SetRegistry() -CHANNEL_ONLY_CLUSTERS = SetRegistry() DEVICE_CLASS = { zigpy.profiles.zha.PROFILE_ID: { @@ -108,8 +105,11 @@ DEVICE_CLASS = { } DEVICE_CLASS = collections.defaultdict(dict, DEVICE_CLASS) -CLIENT_CHANNELS_REGISTRY: DictRegistry[type[ClientChannel]] = DictRegistry() -ZIGBEE_CHANNEL_REGISTRY: DictRegistry[type[ZigbeeChannel]] = DictRegistry() +CLUSTER_HANDLER_ONLY_CLUSTERS = SetRegistry() +CLIENT_CLUSTER_HANDLER_REGISTRY: DictRegistry[ + type[ClientClusterHandler] +] = DictRegistry() +ZIGBEE_CLUSTER_HANDLER_REGISTRY: DictRegistry[type[ClusterHandler]] = DictRegistry() def set_or_callable(value) -> frozenset[str] | Callable: @@ -129,9 +129,9 @@ def _get_empty_frozenset() -> frozenset[str]: @attr.s(frozen=True) class MatchRule: - """Match a ZHA Entity to a channel name or generic id.""" + """Match a ZHA Entity to a cluster handler name or generic id.""" - channel_names: frozenset[str] = attr.ib( + cluster_handler_names: frozenset[str] = attr.ib( factory=frozenset, converter=set_or_callable ) generic_ids: frozenset[str] = attr.ib(factory=frozenset, converter=set_or_callable) @@ -141,7 +141,7 @@ class MatchRule: models: frozenset[str] | Callable = attr.ib( factory=_get_empty_frozenset, converter=set_or_callable ) - aux_channels: frozenset[str] | Callable = attr.ib( + aux_cluster_handlers: frozenset[str] | Callable = attr.ib( factory=_get_empty_frozenset, converter=set_or_callable ) quirk_classes: frozenset[str] | Callable = attr.ib( @@ -157,9 +157,9 @@ class MatchRule: and have a priority over manufacturer matching rules and rules matching a single model/manufacturer get a better priority over rules matching multiple models/manufacturers. And any model or manufacturers matching rules get better - priority over rules matching only channels. - But in case of a channel name/channel id matching, we give rules matching - multiple channels a better priority over rules matching a single channel. + priority over rules matching only cluster handlers. + But in case of a cluster handler name/cluster handler id matching, we give rules matching + multiple cluster handlers a better priority over rules matching a single cluster handler. """ weight = 0 if self.quirk_classes: @@ -175,51 +175,57 @@ class MatchRule: 1 if callable(self.manufacturers) else len(self.manufacturers) ) - weight += 10 * len(self.channel_names) + weight += 10 * len(self.cluster_handler_names) weight += 5 * len(self.generic_ids) - if isinstance(self.aux_channels, frozenset): - weight += 1 * len(self.aux_channels) + if isinstance(self.aux_cluster_handlers, frozenset): + weight += 1 * len(self.aux_cluster_handlers) return weight - def claim_channels(self, channel_pool: list[ZigbeeChannel]) -> list[ZigbeeChannel]: - """Return a list of channels this rule matches + aux channels.""" + def claim_cluster_handlers( + self, cluster_handlers: list[ClusterHandler] + ) -> list[ClusterHandler]: + """Return a list of cluster handlers this rule matches + aux cluster handlers.""" claimed = [] - if isinstance(self.channel_names, frozenset): - claimed.extend([ch for ch in channel_pool if ch.name in self.channel_names]) + if isinstance(self.cluster_handler_names, frozenset): + claimed.extend( + [ch for ch in cluster_handlers if ch.name in self.cluster_handler_names] + ) if isinstance(self.generic_ids, frozenset): claimed.extend( - [ch for ch in channel_pool if ch.generic_id in self.generic_ids] + [ch for ch in cluster_handlers if ch.generic_id in self.generic_ids] + ) + if isinstance(self.aux_cluster_handlers, frozenset): + claimed.extend( + [ch for ch in cluster_handlers if ch.name in self.aux_cluster_handlers] ) - if isinstance(self.aux_channels, frozenset): - claimed.extend([ch for ch in channel_pool if ch.name in self.aux_channels]) return claimed def strict_matched( - self, manufacturer: str, model: str, channels: list, quirk_class: str + self, manufacturer: str, model: str, cluster_handlers: list, quirk_class: str ) -> bool: """Return True if this device matches the criteria.""" - return all(self._matched(manufacturer, model, channels, quirk_class)) + return all(self._matched(manufacturer, model, cluster_handlers, quirk_class)) def loose_matched( - self, manufacturer: str, model: str, channels: list, quirk_class: str + self, manufacturer: str, model: str, cluster_handlers: list, quirk_class: str ) -> bool: """Return True if this device matches the criteria.""" - return any(self._matched(manufacturer, model, channels, quirk_class)) + return any(self._matched(manufacturer, model, cluster_handlers, quirk_class)) def _matched( - self, manufacturer: str, model: str, channels: list, quirk_class: str + self, manufacturer: str, model: str, cluster_handlers: list, quirk_class: str ) -> list: """Return a list of field matches.""" if not any(attr.asdict(self).values()): return [False] matches = [] - if self.channel_names: - channel_names = {ch.name for ch in channels} - matches.append(self.channel_names.issubset(channel_names)) + if self.cluster_handler_names: + cluster_handler_names = {ch.name for ch in cluster_handlers} + matches.append(self.cluster_handler_names.issubset(cluster_handler_names)) if self.generic_ids: - all_generic_ids = {ch.generic_id for ch in channels} + all_generic_ids = {ch.generic_id for ch in cluster_handlers} matches.append(self.generic_ids.issubset(all_generic_ids)) if self.manufacturers: @@ -244,15 +250,15 @@ class MatchRule: @dataclasses.dataclass -class EntityClassAndChannels: - """Container for entity class and corresponding channels.""" +class EntityClassAndClusterHandlers: + """Container for entity class and corresponding cluster handlers.""" entity_class: type[ZhaEntity] - claimed_channel: list[ZigbeeChannel] + claimed_cluster_handlers: list[ClusterHandler] class ZHAEntityRegistry: - """Channel to ZHA Entity mapping.""" + """Cluster handler to ZHA Entity mapping.""" def __init__(self) -> None: """Initialize Registry instance.""" @@ -279,15 +285,15 @@ class ZHAEntityRegistry: component: str, manufacturer: str, model: str, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], quirk_class: str, default: type[ZhaEntity] | None = None, - ) -> tuple[type[ZhaEntity] | None, list[ZigbeeChannel]]: - """Match a ZHA Channels to a ZHA Entity class.""" + ) -> tuple[type[ZhaEntity] | None, list[ClusterHandler]]: + """Match a ZHA ClusterHandler to a ZHA Entity class.""" matches = self._strict_registry[component] for match in sorted(matches, key=lambda x: x.weight, reverse=True): - if match.strict_matched(manufacturer, model, channels, quirk_class): - claimed = match.claim_channels(channels) + if match.strict_matched(manufacturer, model, cluster_handlers, quirk_class): + claimed = match.claim_cluster_handlers(cluster_handlers) return self._strict_registry[component][match], claimed return default, [] @@ -296,21 +302,27 @@ class ZHAEntityRegistry: self, manufacturer: str, model: str, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], quirk_class: str, - ) -> tuple[dict[str, list[EntityClassAndChannels]], list[ZigbeeChannel]]: - """Match ZHA Channels to potentially multiple ZHA Entity classes.""" - result: dict[str, list[EntityClassAndChannels]] = collections.defaultdict(list) - all_claimed: set[ZigbeeChannel] = set() + ) -> tuple[dict[str, list[EntityClassAndClusterHandlers]], list[ClusterHandler]]: + """Match ZHA cluster handlers to potentially multiple ZHA Entity classes.""" + result: dict[ + str, list[EntityClassAndClusterHandlers] + ] = collections.defaultdict(list) + all_claimed: set[ClusterHandler] = set() for component, stop_match_groups in self._multi_entity_registry.items(): for stop_match_grp, matches in stop_match_groups.items(): sorted_matches = sorted(matches, key=lambda x: x.weight, reverse=True) for match in sorted_matches: - if match.strict_matched(manufacturer, model, channels, quirk_class): - claimed = match.claim_channels(channels) + if match.strict_matched( + manufacturer, model, cluster_handlers, quirk_class + ): + claimed = match.claim_cluster_handlers(cluster_handlers) for ent_class in stop_match_groups[stop_match_grp][match]: - ent_n_channels = EntityClassAndChannels(ent_class, claimed) - result[component].append(ent_n_channels) + ent_n_cluster_handlers = EntityClassAndClusterHandlers( + ent_class, claimed + ) + result[component].append(ent_n_cluster_handlers) all_claimed |= set(claimed) if stop_match_grp: break @@ -321,12 +333,14 @@ class ZHAEntityRegistry: self, manufacturer: str, model: str, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], quirk_class: str, - ) -> tuple[dict[str, list[EntityClassAndChannels]], list[ZigbeeChannel]]: - """Match ZHA Channels to potentially multiple ZHA Entity classes.""" - result: dict[str, list[EntityClassAndChannels]] = collections.defaultdict(list) - all_claimed: set[ZigbeeChannel] = set() + ) -> tuple[dict[str, list[EntityClassAndClusterHandlers]], list[ClusterHandler]]: + """Match ZHA cluster handlers to potentially multiple ZHA Entity classes.""" + result: dict[ + str, list[EntityClassAndClusterHandlers] + ] = collections.defaultdict(list) + all_claimed: set[ClusterHandler] = set() for ( component, stop_match_groups, @@ -334,11 +348,15 @@ class ZHAEntityRegistry: for stop_match_grp, matches in stop_match_groups.items(): sorted_matches = sorted(matches, key=lambda x: x.weight, reverse=True) for match in sorted_matches: - if match.strict_matched(manufacturer, model, channels, quirk_class): - claimed = match.claim_channels(channels) + if match.strict_matched( + manufacturer, model, cluster_handlers, quirk_class + ): + claimed = match.claim_cluster_handlers(cluster_handlers) for ent_class in stop_match_groups[stop_match_grp][match]: - ent_n_channels = EntityClassAndChannels(ent_class, claimed) - result[component].append(ent_n_channels) + ent_n_cluster_handlers = EntityClassAndClusterHandlers( + ent_class, claimed + ) + result[component].append(ent_n_cluster_handlers) all_claimed |= set(claimed) if stop_match_grp: break @@ -352,21 +370,21 @@ class ZHAEntityRegistry: def strict_match( self, component: str, - channel_names: set[str] | str | None = None, + cluster_handler_names: set[str] | str | None = None, generic_ids: set[str] | str | None = None, manufacturers: Callable | set[str] | str | None = None, models: Callable | set[str] | str | None = None, - aux_channels: Callable | set[str] | str | None = None, + aux_cluster_handlers: Callable | set[str] | str | None = None, quirk_classes: set[str] | str | None = None, ) -> Callable[[_ZhaEntityT], _ZhaEntityT]: """Decorate a strict match rule.""" rule = MatchRule( - channel_names, + cluster_handler_names, generic_ids, manufacturers, models, - aux_channels, + aux_cluster_handlers, quirk_classes, ) @@ -383,22 +401,22 @@ class ZHAEntityRegistry: def multipass_match( self, component: str, - channel_names: set[str] | str | None = None, + cluster_handler_names: set[str] | str | None = None, generic_ids: set[str] | str | None = None, manufacturers: Callable | set[str] | str | None = None, models: Callable | set[str] | str | None = None, - aux_channels: Callable | set[str] | str | None = None, + aux_cluster_handlers: Callable | set[str] | str | None = None, stop_on_match_group: int | str | None = None, quirk_classes: set[str] | str | None = None, ) -> Callable[[_ZhaEntityT], _ZhaEntityT]: """Decorate a loose match rule.""" rule = MatchRule( - channel_names, + cluster_handler_names, generic_ids, manufacturers, models, - aux_channels, + aux_cluster_handlers, quirk_classes, ) @@ -407,7 +425,7 @@ class ZHAEntityRegistry: All non empty fields of a match rule must match. """ - # group the rules by channels + # group the rules by cluster handlers self._multi_entity_registry[component][stop_on_match_group][rule].append( zha_entity ) @@ -418,22 +436,22 @@ class ZHAEntityRegistry: def config_diagnostic_match( self, component: str, - channel_names: set[str] | str | None = None, + cluster_handler_names: set[str] | str | None = None, generic_ids: set[str] | str | None = None, manufacturers: Callable | set[str] | str | None = None, models: Callable | set[str] | str | None = None, - aux_channels: Callable | set[str] | str | None = None, + aux_cluster_handlers: Callable | set[str] | str | None = None, stop_on_match_group: int | str | None = None, quirk_classes: set[str] | str | None = None, ) -> Callable[[_ZhaEntityT], _ZhaEntityT]: """Decorate a loose match rule.""" rule = MatchRule( - channel_names, + cluster_handler_names, generic_ids, manufacturers, models, - aux_channels, + aux_cluster_handlers, quirk_classes, ) @@ -442,7 +460,7 @@ class ZHAEntityRegistry: All non-empty fields of a match rule must match. """ - # group the rules by channels + # group the rules by cluster handlers self._config_diagnostic_entity_registry[component][stop_on_match_group][ rule ].append(zha_entity) diff --git a/homeassistant/components/zha/cover.py b/homeassistant/components/zha/cover.py index f6c67e6981d..f26fcef5295 100644 --- a/homeassistant/components/zha/cover.py +++ b/homeassistant/components/zha/cover.py @@ -28,10 +28,10 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .core import discovery from .core.const import ( - CHANNEL_COVER, - CHANNEL_LEVEL, - CHANNEL_ON_OFF, - CHANNEL_SHADE, + CLUSTER_HANDLER_COVER, + CLUSTER_HANDLER_LEVEL, + CLUSTER_HANDLER_ON_OFF, + CLUSTER_HANDLER_SHADE, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED, @@ -41,7 +41,7 @@ from .core.registries import ZHA_ENTITIES from .entity import ZhaEntity if TYPE_CHECKING: - from .core.channels.base import ZigbeeChannel + from .core.cluster_handlers import ClusterHandler from .core.device import ZHADevice _LOGGER = logging.getLogger(__name__) @@ -67,21 +67,21 @@ async def async_setup_entry( config_entry.async_on_unload(unsub) -@MULTI_MATCH(channel_names=CHANNEL_COVER) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_COVER) class ZhaCover(ZhaEntity, CoverEntity): """Representation of a ZHA cover.""" - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Init this sensor.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._cover_channel = self.cluster_channels.get(CHANNEL_COVER) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._cover_cluster_handler = self.cluster_handlers.get(CLUSTER_HANDLER_COVER) self._current_position = None async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._cover_channel, SIGNAL_ATTR_UPDATED, self.async_set_position + self._cover_cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_position ) @callback @@ -118,7 +118,7 @@ class ZhaCover(ZhaEntity, CoverEntity): @callback def async_set_position(self, attr_id, attr_name, value): - """Handle position update from channel.""" + """Handle position update from cluster handler.""" _LOGGER.debug("setting position: %s", value) self._current_position = 100 - value if self._current_position == 0: @@ -129,27 +129,27 @@ class ZhaCover(ZhaEntity, CoverEntity): @callback def async_update_state(self, state): - """Handle state update from channel.""" + """Handle state update from cluster handler.""" _LOGGER.debug("state=%s", state) self._state = state self.async_write_ha_state() async def async_open_cover(self, **kwargs: Any) -> None: """Open the window cover.""" - res = await self._cover_channel.up_open() + res = await self._cover_cluster_handler.up_open() if not isinstance(res, Exception) and res[1] is Status.SUCCESS: self.async_update_state(STATE_OPENING) async def async_close_cover(self, **kwargs: Any) -> None: """Close the window cover.""" - res = await self._cover_channel.down_close() + res = await self._cover_cluster_handler.down_close() if not isinstance(res, Exception) and res[1] is Status.SUCCESS: self.async_update_state(STATE_CLOSING) async def async_set_cover_position(self, **kwargs: Any) -> None: """Move the roller shutter to a specific position.""" new_pos = kwargs[ATTR_POSITION] - res = await self._cover_channel.go_to_lift_percentage(100 - new_pos) + res = await self._cover_cluster_handler.go_to_lift_percentage(100 - new_pos) if not isinstance(res, Exception) and res[1] is Status.SUCCESS: self.async_update_state( STATE_CLOSING if new_pos < self._current_position else STATE_OPENING @@ -157,7 +157,7 @@ class ZhaCover(ZhaEntity, CoverEntity): async def async_stop_cover(self, **kwargs: Any) -> None: """Stop the window cover.""" - res = await self._cover_channel.stop() + res = await self._cover_cluster_handler.stop() if not isinstance(res, Exception) and res[1] is Status.SUCCESS: self._state = STATE_OPEN if self._current_position > 0 else STATE_CLOSED self.async_write_ha_state() @@ -170,8 +170,8 @@ class ZhaCover(ZhaEntity, CoverEntity): async def async_get_state(self, from_cache=True): """Fetch the current state.""" _LOGGER.debug("polling current state") - if self._cover_channel: - pos = await self._cover_channel.get_attribute_value( + if self._cover_cluster_handler: + pos = await self._cover_cluster_handler.get_attribute_value( "current_position_lift_percentage", from_cache=from_cache ) _LOGGER.debug("read pos=%s", pos) @@ -186,7 +186,13 @@ class ZhaCover(ZhaEntity, CoverEntity): self._state = None -@MULTI_MATCH(channel_names={CHANNEL_LEVEL, CHANNEL_ON_OFF, CHANNEL_SHADE}) +@MULTI_MATCH( + cluster_handler_names={ + CLUSTER_HANDLER_LEVEL, + CLUSTER_HANDLER_ON_OFF, + CLUSTER_HANDLER_SHADE, + } +) class Shade(ZhaEntity, CoverEntity): """ZHA Shade.""" @@ -196,13 +202,13 @@ class Shade(ZhaEntity, CoverEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs, ) -> None: """Initialize the ZHA light.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._on_off_channel = self.cluster_channels[CHANNEL_ON_OFF] - self._level_channel = self.cluster_channels[CHANNEL_LEVEL] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._on_off_cluster_handler = self.cluster_handlers[CLUSTER_HANDLER_ON_OFF] + self._level_cluster_handler = self.cluster_handlers[CLUSTER_HANDLER_LEVEL] self._position: int | None = None self._is_open: bool | None = None @@ -225,10 +231,12 @@ class Shade(ZhaEntity, CoverEntity): """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._on_off_channel, SIGNAL_ATTR_UPDATED, self.async_set_open_closed + self._on_off_cluster_handler, + SIGNAL_ATTR_UPDATED, + self.async_set_open_closed, ) self.async_accept_signal( - self._level_channel, SIGNAL_SET_LEVEL, self.async_set_level + self._level_cluster_handler, SIGNAL_SET_LEVEL, self.async_set_level ) @callback @@ -253,7 +261,7 @@ class Shade(ZhaEntity, CoverEntity): async def async_open_cover(self, **kwargs: Any) -> None: """Open the window cover.""" - res = await self._on_off_channel.on() + res = await self._on_off_cluster_handler.on() if isinstance(res, Exception) or res[1] != Status.SUCCESS: self.debug("couldn't open cover: %s", res) return @@ -263,7 +271,7 @@ class Shade(ZhaEntity, CoverEntity): async def async_close_cover(self, **kwargs: Any) -> None: """Close the window cover.""" - res = await self._on_off_channel.off() + res = await self._on_off_cluster_handler.off() if isinstance(res, Exception) or res[1] != Status.SUCCESS: self.debug("couldn't open cover: %s", res) return @@ -274,7 +282,7 @@ class Shade(ZhaEntity, CoverEntity): async def async_set_cover_position(self, **kwargs: Any) -> None: """Move the roller shutter to a specific position.""" new_pos = kwargs[ATTR_POSITION] - res = await self._level_channel.move_to_level_with_on_off( + res = await self._level_cluster_handler.move_to_level_with_on_off( new_pos * 255 / 100, 1 ) @@ -287,14 +295,15 @@ class Shade(ZhaEntity, CoverEntity): async def async_stop_cover(self, **kwargs: Any) -> None: """Stop the cover.""" - res = await self._level_channel.stop() + res = await self._level_cluster_handler.stop() if isinstance(res, Exception) or res[1] != Status.SUCCESS: self.debug("couldn't stop cover: %s", res) return @MULTI_MATCH( - channel_names={CHANNEL_LEVEL, CHANNEL_ON_OFF}, manufacturers="Keen Home Inc" + cluster_handler_names={CLUSTER_HANDLER_LEVEL, CLUSTER_HANDLER_ON_OFF}, + manufacturers="Keen Home Inc", ) class KeenVent(Shade): """Keen vent cover.""" @@ -305,8 +314,10 @@ class KeenVent(Shade): """Open the cover.""" position = self._position or 100 tasks = [ - self._level_channel.move_to_level_with_on_off(position * 255 / 100, 1), - self._on_off_channel.on(), + self._level_cluster_handler.move_to_level_with_on_off( + position * 255 / 100, 1 + ), + self._on_off_cluster_handler.on(), ] results = await asyncio.gather(*tasks, return_exceptions=True) if any(isinstance(result, Exception) for result in results): diff --git a/homeassistant/components/zha/device_action.py b/homeassistant/components/zha/device_action.py index 25a01f45baa..d393cfb1471 100644 --- a/homeassistant/components/zha/device_action.py +++ b/homeassistant/components/zha/device_action.py @@ -12,8 +12,11 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.typing import ConfigType, TemplateVarsType from . import DOMAIN -from .core.channels.manufacturerspecific import AllLEDEffectType, SingleLEDEffectType -from .core.const import CHANNEL_IAS_WD, CHANNEL_INOVELLI +from .core.cluster_handlers.manufacturerspecific import ( + AllLEDEffectType, + SingleLEDEffectType, +) +from .core.const import CLUSTER_HANDLER_IAS_WD, CLUSTER_HANDLER_INOVELLI from .core.helpers import async_get_zha_device from .websocket_api import SERVICE_WARNING_DEVICE_SQUAWK, SERVICE_WARNING_DEVICE_WARN @@ -25,7 +28,7 @@ ATTR_DATA = "data" ATTR_IEEE = "ieee" CONF_ZHA_ACTION_TYPE = "zha_action_type" ZHA_ACTION_TYPE_SERVICE_CALL = "service_call" -ZHA_ACTION_TYPE_CHANNEL_COMMAND = "channel_command" +ZHA_ACTION_TYPE_CLUSTER_HANDLER_COMMAND = "cluster_handler_command" INOVELLI_ALL_LED_EFFECT = "issue_all_led_effect" INOVELLI_INDIVIDUAL_LED_EFFECT = "issue_individual_led_effect" @@ -67,11 +70,11 @@ ACTION_SCHEMA = vol.Any( ) DEVICE_ACTIONS = { - CHANNEL_IAS_WD: [ + CLUSTER_HANDLER_IAS_WD: [ {CONF_TYPE: ACTION_SQUAWK, CONF_DOMAIN: DOMAIN}, {CONF_TYPE: ACTION_WARN, CONF_DOMAIN: DOMAIN}, ], - CHANNEL_INOVELLI: [ + CLUSTER_HANDLER_INOVELLI: [ {CONF_TYPE: INOVELLI_ALL_LED_EFFECT, CONF_DOMAIN: DOMAIN}, {CONF_TYPE: INOVELLI_INDIVIDUAL_LED_EFFECT, CONF_DOMAIN: DOMAIN}, ], @@ -80,8 +83,8 @@ DEVICE_ACTIONS = { DEVICE_ACTION_TYPES = { ACTION_SQUAWK: ZHA_ACTION_TYPE_SERVICE_CALL, ACTION_WARN: ZHA_ACTION_TYPE_SERVICE_CALL, - INOVELLI_ALL_LED_EFFECT: ZHA_ACTION_TYPE_CHANNEL_COMMAND, - INOVELLI_INDIVIDUAL_LED_EFFECT: ZHA_ACTION_TYPE_CHANNEL_COMMAND, + INOVELLI_ALL_LED_EFFECT: ZHA_ACTION_TYPE_CLUSTER_HANDLER_COMMAND, + INOVELLI_INDIVIDUAL_LED_EFFECT: ZHA_ACTION_TYPE_CLUSTER_HANDLER_COMMAND, } DEVICE_ACTION_SCHEMAS = { @@ -109,9 +112,9 @@ SERVICE_NAMES = { ACTION_WARN: SERVICE_WARNING_DEVICE_WARN, } -CHANNEL_MAPPINGS = { - INOVELLI_ALL_LED_EFFECT: CHANNEL_INOVELLI, - INOVELLI_INDIVIDUAL_LED_EFFECT: CHANNEL_INOVELLI, +CLUSTER_HANDLER_MAPPINGS = { + INOVELLI_ALL_LED_EFFECT: CLUSTER_HANDLER_INOVELLI, + INOVELLI_INDIVIDUAL_LED_EFFECT: CLUSTER_HANDLER_INOVELLI, } @@ -144,16 +147,16 @@ async def async_get_actions( zha_device = async_get_zha_device(hass, device_id) except (KeyError, AttributeError): return [] - cluster_channels = [ + cluster_handlers = [ ch.name - for pool in zha_device.channels.pools - for ch in pool.claimed_channels.values() + for endpoint in zha_device.endpoints.values() + for ch in endpoint.claimed_cluster_handlers.values() ] actions = [ action - for channel, channel_actions in DEVICE_ACTIONS.items() - for action in channel_actions - if channel in cluster_channels + for cluster_handler, cluster_handler_actions in DEVICE_ACTIONS.items() + for action in cluster_handler_actions + if cluster_handler in cluster_handlers ] for action in actions: action[CONF_DEVICE_ID] = device_id @@ -188,42 +191,42 @@ async def _execute_service_based_action( ) -async def _execute_channel_command_based_action( +async def _execute_cluster_handler_command_based_action( hass: HomeAssistant, config: dict[str, Any], variables: TemplateVarsType, context: Context | None, ) -> None: action_type = config[CONF_TYPE] - channel_name = CHANNEL_MAPPINGS[action_type] + cluster_handler_name = CLUSTER_HANDLER_MAPPINGS[action_type] try: zha_device = async_get_zha_device(hass, config[CONF_DEVICE_ID]) except (KeyError, AttributeError): return - action_channel = None - for pool in zha_device.channels.pools: - for channel in pool.all_channels.values(): - if channel.name == channel_name: - action_channel = channel + action_cluster_handler = None + for endpoint in zha_device.endpoints.values(): + for cluster_handler in endpoint.all_cluster_handlers.values(): + if cluster_handler.name == cluster_handler_name: + action_cluster_handler = cluster_handler break - if action_channel is None: + if action_cluster_handler is None: raise InvalidDeviceAutomationConfig( - f"Unable to execute channel action - channel: {channel_name} action:" + f"Unable to execute cluster handler action - cluster handler: {cluster_handler_name} action:" f" {action_type}" ) - if not hasattr(action_channel, action_type): + if not hasattr(action_cluster_handler, action_type): raise InvalidDeviceAutomationConfig( - f"Unable to execute channel action - channel: {channel_name} action:" + f"Unable to execute cluster handler - cluster handler: {cluster_handler_name} action:" f" {action_type}" ) - await getattr(action_channel, action_type)(**config) + await getattr(action_cluster_handler, action_type)(**config) ZHA_ACTION_TYPES = { ZHA_ACTION_TYPE_SERVICE_CALL: _execute_service_based_action, - ZHA_ACTION_TYPE_CHANNEL_COMMAND: _execute_channel_command_based_action, + ZHA_ACTION_TYPE_CLUSTER_HANDLER_COMMAND: _execute_cluster_handler_command_based_action, } diff --git a/homeassistant/components/zha/device_tracker.py b/homeassistant/components/zha/device_tracker.py index 1a636ce65a2..83843802fe1 100644 --- a/homeassistant/components/zha/device_tracker.py +++ b/homeassistant/components/zha/device_tracker.py @@ -14,7 +14,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .core import discovery from .core.const import ( - CHANNEL_POWER_CONFIGURATION, + CLUSTER_HANDLER_POWER_CONFIGURATION, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED, @@ -44,16 +44,18 @@ async def async_setup_entry( config_entry.async_on_unload(unsub) -@STRICT_MATCH(channel_names=CHANNEL_POWER_CONFIGURATION) +@STRICT_MATCH(cluster_handler_names=CLUSTER_HANDLER_POWER_CONFIGURATION) class ZHADeviceScannerEntity(ScannerEntity, ZhaEntity): """Represent a tracked device.""" _attr_should_poll = True # BaseZhaEntity defaults to False - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Initialize the ZHA device tracker.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._battery_channel = self.cluster_channels.get(CHANNEL_POWER_CONFIGURATION) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._battery_cluster_handler = self.cluster_handlers.get( + CLUSTER_HANDLER_POWER_CONFIGURATION + ) self._connected = False self._keepalive_interval = 60 self._battery_level = None @@ -61,9 +63,9 @@ class ZHADeviceScannerEntity(ScannerEntity, ZhaEntity): async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() - if self._battery_channel: + if self._battery_cluster_handler: self.async_accept_signal( - self._battery_channel, + self._battery_cluster_handler, SIGNAL_ATTR_UPDATED, self.async_battery_percentage_remaining_updated, ) diff --git a/homeassistant/components/zha/entity.py b/homeassistant/components/zha/entity.py index 8e0b58a8721..e07092a379c 100644 --- a/homeassistant/components/zha/entity.py +++ b/homeassistant/components/zha/entity.py @@ -34,7 +34,7 @@ from .core.const import ( from .core.helpers import LogMixin if TYPE_CHECKING: - from .core.channels.base import ZigbeeChannel + from .core.cluster_handlers import ClusterHandler from .core.device import ZHADevice _LOGGER = logging.getLogger(__name__) @@ -122,19 +122,19 @@ class BaseZhaEntity(LogMixin, entity.Entity): @callback def async_accept_signal( self, - channel: ZigbeeChannel | None, + cluster_handler: ClusterHandler | None, signal: str, func: Callable[..., Any], signal_override=False, ): - """Accept a signal from a channel.""" + """Accept a signal from a cluster handler.""" unsub = None if signal_override: unsub = async_dispatcher_connect(self.hass, signal, func) else: - assert channel + assert cluster_handler unsub = async_dispatcher_connect( - self.hass, f"{channel.unique_id}_{signal}", func + self.hass, f"{cluster_handler.unique_id}_{signal}", func ) self._unsubs.append(unsub) @@ -152,7 +152,7 @@ class ZhaEntity(BaseZhaEntity, RestoreEntity): """Initialize subclass. :param id_suffix: suffix to add to the unique_id of the entity. Used for multi - entities using the same channel/cluster id for the entity. + entities using the same cluster handler/cluster id for the entity. """ super().__init_subclass__(**kwargs) if id_suffix: @@ -162,7 +162,7 @@ class ZhaEntity(BaseZhaEntity, RestoreEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init ZHA entity.""" @@ -174,23 +174,23 @@ class ZhaEntity(BaseZhaEntity, RestoreEntity): .replace("sensor", "") .capitalize() ) - self.cluster_channels: dict[str, ZigbeeChannel] = {} - for channel in channels: - self.cluster_channels[channel.name] = channel + self.cluster_handlers: dict[str, ClusterHandler] = {} + for cluster_handler in cluster_handlers: + self.cluster_handlers[cluster_handler.name] = cluster_handler @classmethod def create_entity( cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. Return entity if it is a supported configuration, otherwise return None """ - return cls(unique_id, zha_device, channels, **kwargs) + return cls(unique_id, zha_device, cluster_handlers, **kwargs) @property def available(self) -> bool: @@ -220,7 +220,7 @@ class ZhaEntity(BaseZhaEntity, RestoreEntity): self._zha_device.ieee, self.entity_id, self._zha_device, - self.cluster_channels, + self.cluster_handlers, self.device_info, self.remove_future, ) @@ -238,9 +238,9 @@ class ZhaEntity(BaseZhaEntity, RestoreEntity): async def async_update(self) -> None: """Retrieve latest state.""" tasks = [ - channel.async_update() - for channel in self.cluster_channels.values() - if hasattr(channel, "async_update") + cluster_handler.async_update() + for cluster_handler in self.cluster_handlers.values() + if hasattr(cluster_handler, "async_update") ] if tasks: await asyncio.gather(*tasks) diff --git a/homeassistant/components/zha/fan.py b/homeassistant/components/zha/fan.py index 5153d3c4567..8325f1a3b69 100644 --- a/homeassistant/components/zha/fan.py +++ b/homeassistant/components/zha/fan.py @@ -28,7 +28,12 @@ from homeassistant.util.percentage import ( ) from .core import discovery -from .core.const import CHANNEL_FAN, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED +from .core.const import ( + CLUSTER_HANDLER_FAN, + DATA_ZHA, + SIGNAL_ADD_ENTITIES, + SIGNAL_ATTR_UPDATED, +) from .core.registries import ZHA_ENTITIES from .entity import ZhaEntity, ZhaGroupEntity @@ -124,50 +129,52 @@ class BaseFan(FanEntity): @callback def async_set_state(self, attr_id, attr_name, value): - """Handle state update from channel.""" + """Handle state update from cluster handler.""" -@STRICT_MATCH(channel_names=CHANNEL_FAN) +@STRICT_MATCH(cluster_handler_names=CLUSTER_HANDLER_FAN) class ZhaFan(BaseFan, ZhaEntity): """Representation of a ZHA fan.""" - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Init this sensor.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._fan_channel = self.cluster_channels.get(CHANNEL_FAN) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._fan_cluster_handler = self.cluster_handlers.get(CLUSTER_HANDLER_FAN) async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._fan_channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._fan_cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) @property def percentage(self) -> int | None: """Return the current speed percentage.""" if ( - self._fan_channel.fan_mode is None - or self._fan_channel.fan_mode > SPEED_RANGE[1] + self._fan_cluster_handler.fan_mode is None + or self._fan_cluster_handler.fan_mode > SPEED_RANGE[1] ): return None - if self._fan_channel.fan_mode == 0: + if self._fan_cluster_handler.fan_mode == 0: return 0 - return ranged_value_to_percentage(SPEED_RANGE, self._fan_channel.fan_mode) + return ranged_value_to_percentage( + SPEED_RANGE, self._fan_cluster_handler.fan_mode + ) @property def preset_mode(self) -> str | None: """Return the current preset mode.""" - return PRESET_MODES_TO_NAME.get(self._fan_channel.fan_mode) + return PRESET_MODES_TO_NAME.get(self._fan_cluster_handler.fan_mode) @callback def async_set_state(self, attr_id, attr_name, value): - """Handle state update from channel.""" + """Handle state update from cluster handler.""" self.async_write_ha_state() async def _async_set_fan_mode(self, fan_mode: int) -> None: """Set the fan mode for the fan.""" - await self._fan_channel.async_set_speed(fan_mode) + await self._fan_cluster_handler.async_set_speed(fan_mode) self.async_set_state(0, "fan_mode", fan_mode) @@ -182,7 +189,7 @@ class FanGroup(BaseFan, ZhaGroupEntity): super().__init__(entity_ids, unique_id, group_id, zha_device, **kwargs) self._available: bool = False group = self.zha_device.gateway.get_group(self._group_id) - self._fan_channel = group.endpoint[hvac.Fan.cluster_id] + self._fan_cluster_handler = group.endpoint[hvac.Fan.cluster_id] self._percentage = None self._preset_mode = None @@ -199,7 +206,7 @@ class FanGroup(BaseFan, ZhaGroupEntity): async def _async_set_fan_mode(self, fan_mode: int) -> None: """Set the fan mode for the group.""" try: - await self._fan_channel.write_attributes({"fan_mode": fan_mode}) + await self._fan_cluster_handler.write_attributes({"fan_mode": fan_mode}) except ZigbeeException as ex: self.error("Could not set fan mode: %s", ex) self.async_set_state(0, "fan_mode", fan_mode) @@ -250,22 +257,22 @@ IKEA_PRESET_MODES = list(IKEA_NAME_TO_PRESET_MODE) @MULTI_MATCH( - channel_names="ikea_airpurifier", + cluster_handler_names="ikea_airpurifier", models={"STARKVIND Air purifier", "STARKVIND Air purifier table"}, ) class IkeaFan(BaseFan, ZhaEntity): """Representation of a ZHA fan.""" - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Init this sensor.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._fan_channel = self.cluster_channels.get("ikea_airpurifier") + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._fan_cluster_handler = self.cluster_handlers.get("ikea_airpurifier") async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._fan_channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._fan_cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) @property @@ -296,18 +303,20 @@ class IkeaFan(BaseFan, ZhaEntity): def percentage(self) -> int | None: """Return the current speed percentage.""" if ( - self._fan_channel.fan_mode is None - or self._fan_channel.fan_mode > IKEA_SPEED_RANGE[1] + self._fan_cluster_handler.fan_mode is None + or self._fan_cluster_handler.fan_mode > IKEA_SPEED_RANGE[1] ): return None - if self._fan_channel.fan_mode == 0: + if self._fan_cluster_handler.fan_mode == 0: return 0 - return ranged_value_to_percentage(IKEA_SPEED_RANGE, self._fan_channel.fan_mode) + return ranged_value_to_percentage( + IKEA_SPEED_RANGE, self._fan_cluster_handler.fan_mode + ) @property def preset_mode(self) -> str | None: """Return the current preset mode.""" - return IKEA_PRESET_MODES_TO_NAME.get(self._fan_channel.fan_mode) + return IKEA_PRESET_MODES_TO_NAME.get(self._fan_cluster_handler.fan_mode) async def async_turn_on( self, @@ -328,10 +337,10 @@ class IkeaFan(BaseFan, ZhaEntity): @callback def async_set_state(self, attr_id, attr_name, value): - """Handle state update from channel.""" + """Handle state update from cluster handler.""" self.async_write_ha_state() async def _async_set_fan_mode(self, fan_mode: int) -> None: """Set the fan mode for the fan.""" - await self._fan_channel.async_set_speed(fan_mode) + await self._fan_cluster_handler.async_set_speed(fan_mode) self.async_set_state(0, "fan_mode", fan_mode) diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index e7bc059054a..a15c51fff5a 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -39,9 +39,9 @@ from homeassistant.helpers.event import async_call_later, async_track_time_inter from .core import discovery, helpers from .core.const import ( - CHANNEL_COLOR, - CHANNEL_LEVEL, - CHANNEL_ON_OFF, + CLUSTER_HANDLER_COLOR, + CLUSTER_HANDLER_LEVEL, + CLUSTER_HANDLER_ON_OFF, CONF_ALWAYS_PREFER_XY_COLOR_MODE, CONF_DEFAULT_LIGHT_TRANSITION, CONF_ENABLE_ENHANCED_LIGHT_TRANSITION, @@ -130,10 +130,10 @@ class BaseLight(LogMixin, light.LightEntity): self._zha_config_enhanced_light_transition: bool = False self._zha_config_enable_light_transitioning_flag: bool = True self._zha_config_always_prefer_xy_color_mode: bool = True - self._on_off_channel = None - self._level_channel = None - self._color_channel = None - self._identify_channel = None + self._on_off_cluster_handler = None + self._level_cluster_handler = None + self._color_cluster_handler = None + self._identify_cluster_handler = None self._transitioning_individual: bool = False self._transitioning_group: bool = False self._transition_listener: Callable[[], None] | None = None @@ -193,7 +193,8 @@ class BaseLight(LogMixin, light.LightEntity): execute_if_off_supported = ( self._GROUP_SUPPORTS_EXECUTE_IF_OFF if isinstance(self, LightGroup) - else self._color_channel and self._color_channel.execute_if_off_supported + else self._color_cluster_handler + and self._color_cluster_handler.execute_if_off_supported ) set_transition_flag = ( @@ -289,7 +290,7 @@ class BaseLight(LogMixin, light.LightEntity): # If the light is currently off, we first need to turn it on at a low # brightness level with no transition. # After that, we set it to the desired color/temperature with no transition. - result = await self._level_channel.move_to_level_with_on_off( + result = await self._level_cluster_handler.move_to_level_with_on_off( level=DEFAULT_MIN_BRIGHTNESS, transition_time=self._DEFAULT_MIN_TRANSITION_TIME, ) @@ -329,7 +330,7 @@ class BaseLight(LogMixin, light.LightEntity): and not new_color_provided_while_off and brightness_supported(self._attr_supported_color_modes) ): - result = await self._level_channel.move_to_level_with_on_off( + result = await self._level_cluster_handler.move_to_level_with_on_off( level=level, transition_time=duration, ) @@ -353,7 +354,7 @@ class BaseLight(LogMixin, light.LightEntity): # since some lights don't always turn on with move_to_level_with_on_off, # we should call the on command on the on_off cluster # if brightness is not 0. - result = await self._on_off_channel.on() + result = await self._on_off_cluster_handler.on() t_log["on_off"] = result if isinstance(result, Exception) or result[1] is not Status.SUCCESS: # 'On' call failed, but as brightness may still transition @@ -383,7 +384,7 @@ class BaseLight(LogMixin, light.LightEntity): if new_color_provided_while_off: # The light is has the correct color, so we can now transition # it to the correct brightness level. - result = await self._level_channel.move_to_level( + result = await self._level_cluster_handler.move_to_level( level=level, transition_time=duration ) t_log["move_to_level_if_color"] = result @@ -400,7 +401,7 @@ class BaseLight(LogMixin, light.LightEntity): self.async_transition_start_timer(transition_time) if effect == light.EFFECT_COLORLOOP: - result = await self._color_channel.color_loop_set( + result = await self._color_cluster_handler.color_loop_set( update_flags=( Color.ColorLoopUpdateFlags.Action | Color.ColorLoopUpdateFlags.Direction @@ -417,7 +418,7 @@ class BaseLight(LogMixin, light.LightEntity): self._attr_effect == light.EFFECT_COLORLOOP and effect != light.EFFECT_COLORLOOP ): - result = await self._color_channel.color_loop_set( + result = await self._color_cluster_handler.color_loop_set( update_flags=Color.ColorLoopUpdateFlags.Action, action=Color.ColorLoopAction.Deactivate, direction=Color.ColorLoopDirection.Decrement, @@ -428,7 +429,7 @@ class BaseLight(LogMixin, light.LightEntity): self._attr_effect = None if flash is not None: - result = await self._identify_channel.trigger_effect( + result = await self._identify_cluster_handler.trigger_effect( effect_id=FLASH_EFFECTS[flash], effect_variant=Identify.EffectVariant.Default, ) @@ -457,12 +458,12 @@ class BaseLight(LogMixin, light.LightEntity): # is not none looks odd here, but it will override built in bulb # transition times if we pass 0 in here if transition is not None and supports_level: - result = await self._level_channel.move_to_level_with_on_off( + result = await self._level_cluster_handler.move_to_level_with_on_off( level=0, transition_time=(transition * 10 or self._DEFAULT_MIN_TRANSITION_TIME), ) else: - result = await self._on_off_channel.off() + result = await self._on_off_cluster_handler.off() # Pause parsing attribute reports until transition is complete if self._zha_config_enable_light_transitioning_flag: @@ -503,7 +504,7 @@ class BaseLight(LogMixin, light.LightEntity): ) if temperature is not None: - result = await self._color_channel.move_to_color_temp( + result = await self._color_cluster_handler.move_to_color_temp( color_temp_mireds=temperature, transition_time=transition_time, ) @@ -518,16 +519,16 @@ class BaseLight(LogMixin, light.LightEntity): if hs_color is not None: if ( not isinstance(self, LightGroup) - and self._color_channel.enhanced_hue_supported + and self._color_cluster_handler.enhanced_hue_supported ): - result = await self._color_channel.enhanced_move_to_hue_and_saturation( + result = await self._color_cluster_handler.enhanced_move_to_hue_and_saturation( enhanced_hue=int(hs_color[0] * 65535 / 360), saturation=int(hs_color[1] * 2.54), transition_time=transition_time, ) t_log["enhanced_move_to_hue_and_saturation"] = result else: - result = await self._color_channel.move_to_hue_and_saturation( + result = await self._color_cluster_handler.move_to_hue_and_saturation( hue=int(hs_color[0] * 254 / 360), saturation=int(hs_color[1] * 2.54), transition_time=transition_time, @@ -542,7 +543,7 @@ class BaseLight(LogMixin, light.LightEntity): xy_color = None # don't set xy_color if it is also present if xy_color is not None: - result = await self._color_channel.move_to_color( + result = await self._color_cluster_handler.move_to_color( color_x=int(xy_color[0] * 65535), color_y=int(xy_color[1] * 65535), transition_time=transition_time, @@ -620,24 +621,29 @@ class BaseLight(LogMixin, light.LightEntity): ) -@STRICT_MATCH(channel_names=CHANNEL_ON_OFF, aux_channels={CHANNEL_COLOR, CHANNEL_LEVEL}) +@STRICT_MATCH( + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, + aux_cluster_handlers={CLUSTER_HANDLER_COLOR, CLUSTER_HANDLER_LEVEL}, +) class Light(BaseLight, ZhaEntity): """Representation of a ZHA or ZLL light.""" _attr_supported_color_modes: set[ColorMode] _REFRESH_INTERVAL = (45, 75) - def __init__(self, unique_id, zha_device: ZHADevice, channels, **kwargs) -> None: + def __init__( + self, unique_id, zha_device: ZHADevice, cluster_handlers, **kwargs + ) -> None: """Initialize the ZHA light.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._on_off_channel = self.cluster_channels[CHANNEL_ON_OFF] - self._attr_state = bool(self._on_off_channel.on_off) - self._level_channel = self.cluster_channels.get(CHANNEL_LEVEL) - self._color_channel = self.cluster_channels.get(CHANNEL_COLOR) - self._identify_channel = self.zha_device.channels.identify_ch - if self._color_channel: - self._attr_min_mireds: int = self._color_channel.min_mireds - self._attr_max_mireds: int = self._color_channel.max_mireds + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._on_off_cluster_handler = self.cluster_handlers[CLUSTER_HANDLER_ON_OFF] + self._attr_state = bool(self._on_off_cluster_handler.on_off) + self._level_cluster_handler = self.cluster_handlers.get(CLUSTER_HANDLER_LEVEL) + self._color_cluster_handler = self.cluster_handlers.get(CLUSTER_HANDLER_COLOR) + self._identify_cluster_handler = zha_device.identify_ch + if self._color_cluster_handler: + self._attr_min_mireds: int = self._color_cluster_handler.min_mireds + self._attr_max_mireds: int = self._color_cluster_handler.max_mireds self._cancel_refresh_handle: CALLBACK_TYPE | None = None effect_list = [] @@ -649,44 +655,48 @@ class Light(BaseLight, ZhaEntity): ) self._attr_supported_color_modes = {ColorMode.ONOFF} - if self._level_channel: + if self._level_cluster_handler: self._attr_supported_color_modes.add(ColorMode.BRIGHTNESS) self._attr_supported_features |= light.LightEntityFeature.TRANSITION - self._attr_brightness = self._level_channel.current_level + self._attr_brightness = self._level_cluster_handler.current_level - if self._color_channel: - if self._color_channel.color_temp_supported: + if self._color_cluster_handler: + if self._color_cluster_handler.color_temp_supported: self._attr_supported_color_modes.add(ColorMode.COLOR_TEMP) - self._attr_color_temp = self._color_channel.color_temperature + self._attr_color_temp = self._color_cluster_handler.color_temperature - if self._color_channel.xy_supported and ( + if self._color_cluster_handler.xy_supported and ( self._zha_config_always_prefer_xy_color_mode - or not self._color_channel.hs_supported + or not self._color_cluster_handler.hs_supported ): self._attr_supported_color_modes.add(ColorMode.XY) - curr_x = self._color_channel.current_x - curr_y = self._color_channel.current_y + curr_x = self._color_cluster_handler.current_x + curr_y = self._color_cluster_handler.current_y if curr_x is not None and curr_y is not None: self._attr_xy_color = (curr_x / 65535, curr_y / 65535) else: self._attr_xy_color = (0, 0) if ( - self._color_channel.hs_supported + self._color_cluster_handler.hs_supported and not self._zha_config_always_prefer_xy_color_mode ): self._attr_supported_color_modes.add(ColorMode.HS) if ( - self._color_channel.enhanced_hue_supported - and self._color_channel.enhanced_current_hue is not None + self._color_cluster_handler.enhanced_hue_supported + and self._color_cluster_handler.enhanced_current_hue is not None ): - curr_hue = self._color_channel.enhanced_current_hue * 65535 / 360 - elif self._color_channel.current_hue is not None: - curr_hue = self._color_channel.current_hue * 254 / 360 + curr_hue = ( + self._color_cluster_handler.enhanced_current_hue * 65535 / 360 + ) + elif self._color_cluster_handler.current_hue is not None: + curr_hue = self._color_cluster_handler.current_hue * 254 / 360 else: curr_hue = 0 - if (curr_saturation := self._color_channel.current_saturation) is None: + if ( + curr_saturation := self._color_cluster_handler.current_saturation + ) is None: curr_saturation = 0 self._attr_hs_color = ( @@ -694,10 +704,10 @@ class Light(BaseLight, ZhaEntity): int(curr_saturation * 2.54), ) - if self._color_channel.color_loop_supported: + if self._color_cluster_handler.color_loop_supported: self._attr_supported_features |= light.LightEntityFeature.EFFECT effect_list.append(light.EFFECT_COLORLOOP) - if self._color_channel.color_loop_active == 1: + if self._color_cluster_handler.color_loop_active == 1: self._attr_effect = light.EFFECT_COLORLOOP self._attr_supported_color_modes = filter_supported_color_modes( self._attr_supported_color_modes @@ -705,13 +715,16 @@ class Light(BaseLight, ZhaEntity): if len(self._attr_supported_color_modes) == 1: self._attr_color_mode = next(iter(self._attr_supported_color_modes)) else: # Light supports color_temp + hs, determine which mode the light is in - assert self._color_channel - if self._color_channel.color_mode == Color.ColorMode.Color_temperature: + assert self._color_cluster_handler + if ( + self._color_cluster_handler.color_mode + == Color.ColorMode.Color_temperature + ): self._attr_color_mode = ColorMode.COLOR_TEMP else: self._attr_color_mode = ColorMode.XY - if self._identify_channel: + if self._identify_cluster_handler: self._attr_supported_features |= light.LightEntityFeature.FLASH if effect_list: @@ -755,11 +768,11 @@ class Light(BaseLight, ZhaEntity): """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._on_off_channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._on_off_cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) - if self._level_channel: + if self._level_cluster_handler: self.async_accept_signal( - self._level_channel, SIGNAL_SET_LEVEL, self.set_level + self._level_cluster_handler, SIGNAL_SET_LEVEL, self.set_level ) refresh_interval = random.randint(*(x * 60 for x in self._REFRESH_INTERVAL)) self._cancel_refresh_handle = async_track_time_interval( @@ -844,8 +857,8 @@ class Light(BaseLight, ZhaEntity): return self.debug("polling current state") - if self._on_off_channel: - state = await self._on_off_channel.get_attribute_value( + if self._on_off_cluster_handler: + state = await self._on_off_cluster_handler.get_attribute_value( "on_off", from_cache=False ) # check if transition started whilst waiting for polled state @@ -858,8 +871,8 @@ class Light(BaseLight, ZhaEntity): self._off_with_transition = False self._off_brightness = None - if self._level_channel: - level = await self._level_channel.get_attribute_value( + if self._level_cluster_handler: + level = await self._level_cluster_handler.get_attribute_value( "current_level", from_cache=False ) # check if transition started whilst waiting for polled state @@ -868,7 +881,7 @@ class Light(BaseLight, ZhaEntity): if level is not None: self._attr_brightness = level - if self._color_channel: + if self._color_cluster_handler: attributes = [ "color_mode", "current_x", @@ -876,23 +889,23 @@ class Light(BaseLight, ZhaEntity): ] if ( not self._zha_config_always_prefer_xy_color_mode - and self._color_channel.enhanced_hue_supported + and self._color_cluster_handler.enhanced_hue_supported ): attributes.append("enhanced_current_hue") attributes.append("current_saturation") if ( - self._color_channel.hs_supported - and not self._color_channel.enhanced_hue_supported + self._color_cluster_handler.hs_supported + and not self._color_cluster_handler.enhanced_hue_supported and not self._zha_config_always_prefer_xy_color_mode ): attributes.append("current_hue") attributes.append("current_saturation") - if self._color_channel.color_temp_supported: + if self._color_cluster_handler.color_temp_supported: attributes.append("color_temperature") - if self._color_channel.color_loop_supported: + if self._color_cluster_handler.color_loop_supported: attributes.append("color_loop_active") - results = await self._color_channel.get_attributes( + results = await self._color_cluster_handler.get_attributes( attributes, from_cache=False, only_cache=False ) @@ -915,7 +928,7 @@ class Light(BaseLight, ZhaEntity): and not self._zha_config_always_prefer_xy_color_mode ): self._attr_color_mode = ColorMode.HS - if self._color_channel.enhanced_hue_supported: + if self._color_cluster_handler.enhanced_hue_supported: current_hue = results.get("enhanced_current_hue") else: current_hue = results.get("current_hue") @@ -923,7 +936,7 @@ class Light(BaseLight, ZhaEntity): if current_hue is not None and current_saturation is not None: self._attr_hs_color = ( int(current_hue * 360 / 65535) - if self._color_channel.enhanced_hue_supported + if self._color_cluster_handler.enhanced_hue_supported else int(current_hue * 360 / 254), int(current_saturation / 2.54), ) @@ -1036,8 +1049,8 @@ class Light(BaseLight, ZhaEntity): @STRICT_MATCH( - channel_names=CHANNEL_ON_OFF, - aux_channels={CHANNEL_COLOR, CHANNEL_LEVEL}, + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, + aux_cluster_handlers={CLUSTER_HANDLER_COLOR, CLUSTER_HANDLER_LEVEL}, manufacturers={"Philips", "Signify Netherlands B.V."}, ) class HueLight(Light): @@ -1047,8 +1060,8 @@ class HueLight(Light): @STRICT_MATCH( - channel_names=CHANNEL_ON_OFF, - aux_channels={CHANNEL_COLOR, CHANNEL_LEVEL}, + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, + aux_cluster_handlers={CLUSTER_HANDLER_COLOR, CLUSTER_HANDLER_LEVEL}, manufacturers={"Jasco", "Quotra-Vision", "eWeLight", "eWeLink"}, ) class ForceOnLight(Light): @@ -1058,8 +1071,8 @@ class ForceOnLight(Light): @STRICT_MATCH( - channel_names=CHANNEL_ON_OFF, - aux_channels={CHANNEL_COLOR, CHANNEL_LEVEL}, + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, + aux_cluster_handlers={CLUSTER_HANDLER_COLOR, CLUSTER_HANDLER_LEVEL}, manufacturers=DEFAULT_MIN_TRANSITION_MANUFACTURERS, ) class MinTransitionLight(Light): @@ -1089,11 +1102,13 @@ class LightGroup(BaseLight, ZhaGroupEntity): # If at least one member has a color cluster and doesn't support it, # it's not used. for member in group.members: - for pool in member.device.channels.pools: - for channel in pool.all_channels.values(): + for ( + endpoint + ) in member.device._endpoints.values(): # pylint: disable=protected-access + for cluster_handler in endpoint.all_cluster_handlers.values(): if ( - channel.name == CHANNEL_COLOR - and not channel.execute_if_off_supported + cluster_handler.name == CLUSTER_HANDLER_COLOR + and not cluster_handler.execute_if_off_supported ): self._GROUP_SUPPORTS_EXECUTE_IF_OFF = False break @@ -1102,10 +1117,10 @@ class LightGroup(BaseLight, ZhaGroupEntity): member.device.manufacturer in DEFAULT_MIN_TRANSITION_MANUFACTURERS for member in group.members ) - self._on_off_channel = group.endpoint[OnOff.cluster_id] - self._level_channel = group.endpoint[LevelControl.cluster_id] - self._color_channel = group.endpoint[Color.cluster_id] - self._identify_channel = group.endpoint[Identify.cluster_id] + self._on_off_cluster_handler = group.endpoint[OnOff.cluster_id] + self._level_cluster_handler = group.endpoint[LevelControl.cluster_id] + self._color_cluster_handler = group.endpoint[Color.cluster_id] + self._identify_cluster_handler = group.endpoint[Identify.cluster_id] self._debounced_member_refresh: Debouncer | None = None self._zha_config_transition = async_get_zha_config_value( zha_device.gateway.config_entry, diff --git a/homeassistant/components/zha/lock.py b/homeassistant/components/zha/lock.py index 433f662a785..e97bb036324 100644 --- a/homeassistant/components/zha/lock.py +++ b/homeassistant/components/zha/lock.py @@ -19,7 +19,7 @@ from homeassistant.helpers.typing import StateType from .core import discovery from .core.const import ( - CHANNEL_DOORLOCK, + CLUSTER_HANDLER_DOORLOCK, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED, @@ -92,20 +92,22 @@ async def async_setup_entry( ) -@MULTI_MATCH(channel_names=CHANNEL_DOORLOCK) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_DOORLOCK) class ZhaDoorLock(ZhaEntity, LockEntity): """Representation of a ZHA lock.""" - def __init__(self, unique_id, zha_device, channels, **kwargs): + def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs): """Init this sensor.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._doorlock_channel = self.cluster_channels.get(CHANNEL_DOORLOCK) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._doorlock_cluster_handler = self.cluster_handlers.get( + CLUSTER_HANDLER_DOORLOCK + ) async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._doorlock_channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._doorlock_cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) @callback @@ -127,7 +129,7 @@ class ZhaDoorLock(ZhaEntity, LockEntity): async def async_lock(self, **kwargs: Any) -> None: """Lock the lock.""" - result = await self._doorlock_channel.lock_door() + result = await self._doorlock_cluster_handler.lock_door() if isinstance(result, Exception) or result[0] is not Status.SUCCESS: self.error("Error with lock_door: %s", result) return @@ -135,7 +137,7 @@ class ZhaDoorLock(ZhaEntity, LockEntity): async def async_unlock(self, **kwargs: Any) -> None: """Unlock the lock.""" - result = await self._doorlock_channel.unlock_door() + result = await self._doorlock_cluster_handler.unlock_door() if isinstance(result, Exception) or result[0] is not Status.SUCCESS: self.error("Error with unlock_door: %s", result) return @@ -148,14 +150,14 @@ class ZhaDoorLock(ZhaEntity, LockEntity): @callback def async_set_state(self, attr_id, attr_name, value): - """Handle state update from channel.""" + """Handle state update from cluster handler.""" self._state = VALUE_TO_STATE.get(value, self._state) self.async_write_ha_state() async def async_get_state(self, from_cache=True): """Attempt to retrieve state from the lock.""" - if self._doorlock_channel: - state = await self._doorlock_channel.get_attribute_value( + if self._doorlock_cluster_handler: + state = await self._doorlock_cluster_handler.get_attribute_value( "lock_state", from_cache=from_cache ) if state is not None: @@ -167,24 +169,26 @@ class ZhaDoorLock(ZhaEntity, LockEntity): async def async_set_lock_user_code(self, code_slot: int, user_code: str) -> None: """Set the user_code to index X on the lock.""" - if self._doorlock_channel: - await self._doorlock_channel.async_set_user_code(code_slot, user_code) + if self._doorlock_cluster_handler: + await self._doorlock_cluster_handler.async_set_user_code( + code_slot, user_code + ) self.debug("User code at slot %s set", code_slot) async def async_enable_lock_user_code(self, code_slot: int) -> None: """Enable user_code at index X on the lock.""" - if self._doorlock_channel: - await self._doorlock_channel.async_enable_user_code(code_slot) + if self._doorlock_cluster_handler: + await self._doorlock_cluster_handler.async_enable_user_code(code_slot) self.debug("User code at slot %s enabled", code_slot) async def async_disable_lock_user_code(self, code_slot: int) -> None: """Disable user_code at index X on the lock.""" - if self._doorlock_channel: - await self._doorlock_channel.async_disable_user_code(code_slot) + if self._doorlock_cluster_handler: + await self._doorlock_cluster_handler.async_disable_user_code(code_slot) self.debug("User code at slot %s disabled", code_slot) async def async_clear_lock_user_code(self, code_slot: int) -> None: """Clear the user_code at index X on the lock.""" - if self._doorlock_channel: - await self._doorlock_channel.async_clear_user_code(code_slot) + if self._doorlock_cluster_handler: + await self._doorlock_cluster_handler.async_clear_user_code(code_slot) self.debug("User code at slot %s cleared", code_slot) diff --git a/homeassistant/components/zha/number.py b/homeassistant/components/zha/number.py index d35f9c3afad..7c07d2704a9 100644 --- a/homeassistant/components/zha/number.py +++ b/homeassistant/components/zha/number.py @@ -18,11 +18,11 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .core import discovery from .core.const import ( - CHANNEL_ANALOG_OUTPUT, - CHANNEL_BASIC, - CHANNEL_COLOR, - CHANNEL_INOVELLI, - CHANNEL_LEVEL, + CLUSTER_HANDLER_ANALOG_OUTPUT, + CLUSTER_HANDLER_BASIC, + CLUSTER_HANDLER_COLOR, + CLUSTER_HANDLER_INOVELLI, + CLUSTER_HANDLER_LEVEL, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED, @@ -31,7 +31,7 @@ from .core.registries import ZHA_ENTITIES from .entity import ZhaEntity if TYPE_CHECKING: - from .core.channels.base import ZigbeeChannel + from .core.cluster_handlers import ClusterHandler from .core.device import ZHADevice _LOGGER = logging.getLogger(__name__) @@ -275,7 +275,7 @@ async def async_setup_entry( config_entry.async_on_unload(unsub) -@STRICT_MATCH(channel_names=CHANNEL_ANALOG_OUTPUT) +@STRICT_MATCH(cluster_handler_names=CLUSTER_HANDLER_ANALOG_OUTPUT) class ZhaNumber(ZhaEntity, NumberEntity): """Representation of a ZHA Number entity.""" @@ -283,29 +283,33 @@ class ZhaNumber(ZhaEntity, NumberEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this entity.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._analog_output_channel = self.cluster_channels[CHANNEL_ANALOG_OUTPUT] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._analog_output_cluster_handler = self.cluster_handlers[ + CLUSTER_HANDLER_ANALOG_OUTPUT + ] async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._analog_output_channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._analog_output_cluster_handler, + SIGNAL_ATTR_UPDATED, + self.async_set_state, ) @property def native_value(self) -> float | None: """Return the current value.""" - return self._analog_output_channel.present_value + return self._analog_output_cluster_handler.present_value @property def native_min_value(self) -> float: """Return the minimum value.""" - min_present_value = self._analog_output_channel.min_present_value + min_present_value = self._analog_output_cluster_handler.min_present_value if min_present_value is not None: return min_present_value return 0 @@ -313,7 +317,7 @@ class ZhaNumber(ZhaEntity, NumberEntity): @property def native_max_value(self) -> float: """Return the maximum value.""" - max_present_value = self._analog_output_channel.max_present_value + max_present_value = self._analog_output_cluster_handler.max_present_value if max_present_value is not None: return max_present_value return 1023 @@ -321,7 +325,7 @@ class ZhaNumber(ZhaEntity, NumberEntity): @property def native_step(self) -> float | None: """Return the value step.""" - resolution = self._analog_output_channel.resolution + resolution = self._analog_output_cluster_handler.resolution if resolution is not None: return resolution return super().native_step @@ -329,7 +333,7 @@ class ZhaNumber(ZhaEntity, NumberEntity): @property def name(self) -> str: """Return the name of the number entity.""" - description = self._analog_output_channel.description + description = self._analog_output_cluster_handler.description if description is not None and len(description) > 0: return f"{super().name} {description}" return super().name @@ -337,7 +341,7 @@ class ZhaNumber(ZhaEntity, NumberEntity): @property def icon(self) -> str | None: """Return the icon to be used for this entity.""" - application_type = self._analog_output_channel.application_type + application_type = self._analog_output_cluster_handler.application_type if application_type is not None: return ICONS.get(application_type >> 16, super().icon) return super().icon @@ -345,26 +349,26 @@ class ZhaNumber(ZhaEntity, NumberEntity): @property def native_unit_of_measurement(self) -> str | None: """Return the unit the value is expressed in.""" - engineering_units = self._analog_output_channel.engineering_units + engineering_units = self._analog_output_cluster_handler.engineering_units return UNITS.get(engineering_units) @callback def async_set_state(self, attr_id, attr_name, value): - """Handle value update from channel.""" + """Handle value update from cluster handler.""" self.async_write_ha_state() async def async_set_native_value(self, value: float) -> None: """Update the current value from HA.""" num_value = float(value) - if await self._analog_output_channel.async_set_present_value(num_value): + if await self._analog_output_cluster_handler.async_set_present_value(num_value): self.async_write_ha_state() async def async_update(self) -> None: """Attempt to retrieve the state of the entity.""" await super().async_update() _LOGGER.debug("polling current state") - if self._analog_output_channel: - value = await self._analog_output_channel.get_attribute_value( + if self._analog_output_cluster_handler: + value = await self._analog_output_cluster_handler.get_attribute_value( "present_value", from_cache=False ) _LOGGER.debug("read value=%s", value) @@ -383,17 +387,17 @@ class ZHANumberConfigurationEntity(ZhaEntity, NumberEntity): cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. Return entity if it is a supported configuration, otherwise return None """ - channel = channels[0] + cluster_handler = cluster_handlers[0] if ( - cls._zcl_attribute in channel.cluster.unsupported_attributes - or channel.cluster.get(cls._zcl_attribute) is None + cls._zcl_attribute in cluster_handler.cluster.unsupported_attributes + or cluster_handler.cluster.get(cls._zcl_attribute) is None ): _LOGGER.debug( "%s is not supported - skipping %s entity creation", @@ -402,28 +406,31 @@ class ZHANumberConfigurationEntity(ZhaEntity, NumberEntity): ) return None - return cls(unique_id, zha_device, channels, **kwargs) + return cls(unique_id, zha_device, cluster_handlers, **kwargs) def __init__( self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this number configuration entity.""" - self._channel: ZigbeeChannel = channels[0] - super().__init__(unique_id, zha_device, channels, **kwargs) + self._cluster_handler: ClusterHandler = cluster_handlers[0] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) @property def native_value(self) -> float: """Return the current value.""" - return self._channel.cluster.get(self._zcl_attribute) * self._attr_multiplier + return ( + self._cluster_handler.cluster.get(self._zcl_attribute) + * self._attr_multiplier + ) async def async_set_native_value(self, value: float) -> None: """Update the current value from HA.""" try: - res = await self._channel.cluster.write_attributes( + res = await self._cluster_handler.cluster.write_attributes( {self._zcl_attribute: int(value / self._attr_multiplier)} ) except zigpy.exceptions.ZigbeeException as ex: @@ -438,15 +445,16 @@ class ZHANumberConfigurationEntity(ZhaEntity, NumberEntity): """Attempt to retrieve the state of the entity.""" await super().async_update() _LOGGER.debug("polling current state") - if self._channel: - value = await self._channel.get_attribute_value( + if self._cluster_handler: + value = await self._cluster_handler.get_attribute_value( self._zcl_attribute, from_cache=False ) _LOGGER.debug("read value=%s", value) @CONFIG_DIAGNOSTIC_MATCH( - channel_names="opple_cluster", models={"lumi.motion.ac02", "lumi.motion.agl04"} + cluster_handler_names="opple_cluster", + models={"lumi.motion.ac02", "lumi.motion.agl04"}, ) class AqaraMotionDetectionInterval( ZHANumberConfigurationEntity, id_suffix="detection_interval" @@ -459,7 +467,7 @@ class AqaraMotionDetectionInterval( _attr_name = "Detection interval" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_LEVEL) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_LEVEL) class OnOffTransitionTimeConfigurationEntity( ZHANumberConfigurationEntity, id_suffix="on_off_transition_time" ): @@ -471,7 +479,7 @@ class OnOffTransitionTimeConfigurationEntity( _attr_name = "On/Off transition time" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_LEVEL) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_LEVEL) class OnLevelConfigurationEntity(ZHANumberConfigurationEntity, id_suffix="on_level"): """Representation of a ZHA on level configuration entity.""" @@ -481,7 +489,7 @@ class OnLevelConfigurationEntity(ZHANumberConfigurationEntity, id_suffix="on_lev _attr_name = "On level" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_LEVEL) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_LEVEL) class OnTransitionTimeConfigurationEntity( ZHANumberConfigurationEntity, id_suffix="on_transition_time" ): @@ -493,7 +501,7 @@ class OnTransitionTimeConfigurationEntity( _attr_name = "On transition time" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_LEVEL) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_LEVEL) class OffTransitionTimeConfigurationEntity( ZHANumberConfigurationEntity, id_suffix="off_transition_time" ): @@ -505,7 +513,7 @@ class OffTransitionTimeConfigurationEntity( _attr_name = "Off transition time" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_LEVEL) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_LEVEL) class DefaultMoveRateConfigurationEntity( ZHANumberConfigurationEntity, id_suffix="default_move_rate" ): @@ -517,7 +525,7 @@ class DefaultMoveRateConfigurationEntity( _attr_name = "Default move rate" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_LEVEL) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_LEVEL) class StartUpCurrentLevelConfigurationEntity( ZHANumberConfigurationEntity, id_suffix="start_up_current_level" ): @@ -529,7 +537,7 @@ class StartUpCurrentLevelConfigurationEntity( _attr_name = "Start-up current level" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_COLOR) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_COLOR) class StartUpColorTemperatureConfigurationEntity( ZHANumberConfigurationEntity, id_suffix="start_up_color_temperature" ): @@ -544,18 +552,18 @@ class StartUpColorTemperatureConfigurationEntity( self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this ZHA startup color temperature entity.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - if self._channel: - self._attr_native_min_value: float = self._channel.min_mireds - self._attr_native_max_value: float = self._channel.max_mireds + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + if self._cluster_handler: + self._attr_native_min_value: float = self._cluster_handler.min_mireds + self._attr_native_max_value: float = self._cluster_handler.max_mireds @CONFIG_DIAGNOSTIC_MATCH( - channel_names="tuya_manufacturer", + cluster_handler_names="tuya_manufacturer", manufacturers={ "_TZE200_htnnfasr", }, @@ -572,7 +580,7 @@ class TimerDurationMinutes(ZHANumberConfigurationEntity, id_suffix="timer_durati _attr_name = "Timer duration" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="ikea_airpurifier") +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names="ikea_airpurifier") class FilterLifeTime(ZHANumberConfigurationEntity, id_suffix="filter_life_time"): """Representation of a ZHA filter lifetime configuration entity.""" @@ -586,7 +594,7 @@ class FilterLifeTime(ZHANumberConfigurationEntity, id_suffix="filter_life_time") @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_BASIC, + cluster_handler_names=CLUSTER_HANDLER_BASIC, manufacturers={"TexasInstruments"}, models={"ti.router"}, ) @@ -599,7 +607,7 @@ class TiRouterTransmitPower(ZHANumberConfigurationEntity, id_suffix="transmit_po _attr_name = "Transmit power" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliRemoteDimmingUpSpeed( ZHANumberConfigurationEntity, id_suffix="dimming_speed_up_remote" ): @@ -613,7 +621,7 @@ class InovelliRemoteDimmingUpSpeed( _attr_name: str = "Remote dimming up speed" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliButtonDelay(ZHANumberConfigurationEntity, id_suffix="button_delay"): """Inovelli button delay configuration entity.""" @@ -625,7 +633,7 @@ class InovelliButtonDelay(ZHANumberConfigurationEntity, id_suffix="button_delay" _attr_name: str = "Button delay" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliLocalDimmingUpSpeed( ZHANumberConfigurationEntity, id_suffix="dimming_speed_up_local" ): @@ -639,7 +647,7 @@ class InovelliLocalDimmingUpSpeed( _attr_name: str = "Local dimming up speed" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliLocalRampRateOffToOn( ZHANumberConfigurationEntity, id_suffix="ramp_rate_off_to_on_local" ): @@ -653,7 +661,7 @@ class InovelliLocalRampRateOffToOn( _attr_name: str = "Local ramp rate off to on" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliRemoteDimmingSpeedOffToOn( ZHANumberConfigurationEntity, id_suffix="ramp_rate_off_to_on_remote" ): @@ -667,7 +675,7 @@ class InovelliRemoteDimmingSpeedOffToOn( _attr_name: str = "Remote ramp rate off to on" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliRemoteDimmingDownSpeed( ZHANumberConfigurationEntity, id_suffix="dimming_speed_down_remote" ): @@ -681,7 +689,7 @@ class InovelliRemoteDimmingDownSpeed( _attr_name: str = "Remote dimming down speed" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliLocalDimmingDownSpeed( ZHANumberConfigurationEntity, id_suffix="dimming_speed_down_local" ): @@ -695,7 +703,7 @@ class InovelliLocalDimmingDownSpeed( _attr_name: str = "Local dimming down speed" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliLocalRampRateOnToOff( ZHANumberConfigurationEntity, id_suffix="ramp_rate_on_to_off_local" ): @@ -709,7 +717,7 @@ class InovelliLocalRampRateOnToOff( _attr_name: str = "Local ramp rate on to off" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliRemoteDimmingSpeedOnToOff( ZHANumberConfigurationEntity, id_suffix="ramp_rate_on_to_off_remote" ): @@ -723,7 +731,7 @@ class InovelliRemoteDimmingSpeedOnToOff( _attr_name: str = "Remote ramp rate on to off" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliMinimumLoadDimmingLevel( ZHANumberConfigurationEntity, id_suffix="minimum_level" ): @@ -737,7 +745,7 @@ class InovelliMinimumLoadDimmingLevel( _attr_name: str = "Minimum load dimming level" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliMaximumLoadDimmingLevel( ZHANumberConfigurationEntity, id_suffix="maximum_level" ): @@ -751,7 +759,7 @@ class InovelliMaximumLoadDimmingLevel( _attr_name: str = "Maximum load dimming level" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliAutoShutoffTimer( ZHANumberConfigurationEntity, id_suffix="auto_off_timer" ): @@ -765,7 +773,7 @@ class InovelliAutoShutoffTimer( _attr_name: str = "Automatic switch shutoff timer" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliLoadLevelIndicatorTimeout( ZHANumberConfigurationEntity, id_suffix="load_level_indicator_timeout" ): @@ -779,7 +787,7 @@ class InovelliLoadLevelIndicatorTimeout( _attr_name: str = "Load level indicator timeout" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliDefaultAllLEDOnColor( ZHANumberConfigurationEntity, id_suffix="led_color_when_on" ): @@ -793,7 +801,7 @@ class InovelliDefaultAllLEDOnColor( _attr_name: str = "Default all LED on color" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliDefaultAllLEDOffColor( ZHANumberConfigurationEntity, id_suffix="led_color_when_off" ): @@ -807,7 +815,7 @@ class InovelliDefaultAllLEDOffColor( _attr_name: str = "Default all LED off color" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliDefaultAllLEDOnIntensity( ZHANumberConfigurationEntity, id_suffix="led_intensity_when_on" ): @@ -821,7 +829,7 @@ class InovelliDefaultAllLEDOnIntensity( _attr_name: str = "Default all LED on intensity" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliDefaultAllLEDOffIntensity( ZHANumberConfigurationEntity, id_suffix="led_intensity_when_off" ): @@ -835,7 +843,7 @@ class InovelliDefaultAllLEDOffIntensity( _attr_name: str = "Default all LED off intensity" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliDoubleTapUpLevel( ZHANumberConfigurationEntity, id_suffix="double_tap_up_level" ): @@ -849,7 +857,7 @@ class InovelliDoubleTapUpLevel( _attr_name: str = "Double tap up level" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_INOVELLI) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_INOVELLI) class InovelliDoubleTapDownLevel( ZHANumberConfigurationEntity, id_suffix="double_tap_down_level" ): @@ -863,7 +871,9 @@ class InovelliDoubleTapDownLevel( _attr_name: str = "Double tap down level" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"} +) class AqaraPetFeederServingSize(ZHANumberConfigurationEntity, id_suffix="serving_size"): """Aqara pet feeder serving size configuration entity.""" @@ -876,7 +886,9 @@ class AqaraPetFeederServingSize(ZHANumberConfigurationEntity, id_suffix="serving _attr_icon: str = "mdi:counter" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"} +) class AqaraPetFeederPortionWeight( ZHANumberConfigurationEntity, id_suffix="portion_weight" ): @@ -892,7 +904,9 @@ class AqaraPetFeederPortionWeight( _attr_icon: str = "mdi:weight-gram" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"} +) class AqaraThermostatAwayTemp( ZHANumberConfigurationEntity, id_suffix="away_preset_temperature" ): diff --git a/homeassistant/components/zha/select.py b/homeassistant/components/zha/select.py index b352176411a..1bab8a3f2c3 100644 --- a/homeassistant/components/zha/select.py +++ b/homeassistant/components/zha/select.py @@ -20,10 +20,10 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .core import discovery from .core.const import ( - CHANNEL_IAS_WD, - CHANNEL_INOVELLI, - CHANNEL_OCCUPANCY, - CHANNEL_ON_OFF, + CLUSTER_HANDLER_IAS_WD, + CLUSTER_HANDLER_INOVELLI, + CLUSTER_HANDLER_OCCUPANCY, + CLUSTER_HANDLER_ON_OFF, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED, @@ -33,7 +33,7 @@ from .core.registries import ZHA_ENTITIES from .entity import ZhaEntity if TYPE_CHECKING: - from .core.channels.base import ZigbeeChannel + from .core.cluster_handlers import ClusterHandler from .core.device import ZHADevice @@ -74,33 +74,35 @@ class ZHAEnumSelectEntity(ZhaEntity, SelectEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this select entity.""" self._attribute = self._enum.__name__ self._attr_options = [entry.name.replace("_", " ") for entry in self._enum] - self._channel: ZigbeeChannel = channels[0] - super().__init__(unique_id, zha_device, channels, **kwargs) + self._cluster_handler: ClusterHandler = cluster_handlers[0] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) @property def current_option(self) -> str | None: """Return the selected entity option to represent the entity state.""" - option = self._channel.data_cache.get(self._attribute) + option = self._cluster_handler.data_cache.get(self._attribute) if option is None: return None return option.name.replace("_", " ") async def async_select_option(self, option: str) -> None: """Change the selected option.""" - self._channel.data_cache[self._attribute] = self._enum[option.replace(" ", "_")] + self._cluster_handler.data_cache[self._attribute] = self._enum[ + option.replace(" ", "_") + ] self.async_write_ha_state() @callback def async_restore_last_state(self, last_state) -> None: """Restore previous state.""" if last_state.state and last_state.state != STATE_UNKNOWN: - self._channel.data_cache[self._attribute] = self._enum[ + self._cluster_handler.data_cache[self._attribute] = self._enum[ last_state.state.replace(" ", "_") ] @@ -114,7 +116,7 @@ class ZHANonZCLSelectEntity(ZHAEnumSelectEntity): return True -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_IAS_WD) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_IAS_WD) class ZHADefaultToneSelectEntity( ZHANonZCLSelectEntity, id_suffix=IasWd.Warning.WarningMode.__name__ ): @@ -124,7 +126,7 @@ class ZHADefaultToneSelectEntity( _attr_name = "Default siren tone" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_IAS_WD) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_IAS_WD) class ZHADefaultSirenLevelSelectEntity( ZHANonZCLSelectEntity, id_suffix=IasWd.Warning.SirenLevel.__name__ ): @@ -134,7 +136,7 @@ class ZHADefaultSirenLevelSelectEntity( _attr_name = "Default siren level" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_IAS_WD) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_IAS_WD) class ZHADefaultStrobeLevelSelectEntity( ZHANonZCLSelectEntity, id_suffix=IasWd.StrobeLevel.__name__ ): @@ -144,7 +146,7 @@ class ZHADefaultStrobeLevelSelectEntity( _attr_name = "Default strobe level" -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_IAS_WD) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_IAS_WD) class ZHADefaultStrobeSelectEntity(ZHANonZCLSelectEntity, id_suffix=Strobe.__name__): """Representation of a ZHA default siren strobe select entity.""" @@ -164,17 +166,17 @@ class ZCLEnumSelectEntity(ZhaEntity, SelectEntity): cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. Return entity if it is a supported configuration, otherwise return None """ - channel = channels[0] + cluster_handler = cluster_handlers[0] if ( - cls._select_attr in channel.cluster.unsupported_attributes - or channel.cluster.get(cls._select_attr) is None + cls._select_attr in cluster_handler.cluster.unsupported_attributes + or cluster_handler.cluster.get(cls._select_attr) is None ): _LOGGER.debug( "%s is not supported - skipping %s entity creation", @@ -183,24 +185,24 @@ class ZCLEnumSelectEntity(ZhaEntity, SelectEntity): ) return None - return cls(unique_id, zha_device, channels, **kwargs) + return cls(unique_id, zha_device, cluster_handlers, **kwargs) def __init__( self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this select entity.""" self._attr_options = [entry.name.replace("_", " ") for entry in self._enum] - self._channel: ZigbeeChannel = channels[0] - super().__init__(unique_id, zha_device, channels, **kwargs) + self._cluster_handler: ClusterHandler = cluster_handlers[0] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) @property def current_option(self) -> str | None: """Return the selected entity option to represent the entity state.""" - option = self._channel.cluster.get(self._select_attr) + option = self._cluster_handler.cluster.get(self._select_attr) if option is None: return None option = self._enum(option) @@ -208,7 +210,7 @@ class ZCLEnumSelectEntity(ZhaEntity, SelectEntity): async def async_select_option(self, option: str) -> None: """Change the selected option.""" - await self._channel.cluster.write_attributes( + await self._cluster_handler.cluster.write_attributes( {self._select_attr: self._enum[option.replace(" ", "_")]} ) self.async_write_ha_state() @@ -217,16 +219,16 @@ class ZCLEnumSelectEntity(ZhaEntity, SelectEntity): """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) @callback def async_set_state(self, attr_id: int, attr_name: str, value: Any): - """Handle state update from channel.""" + """Handle state update from cluster handler.""" self.async_write_ha_state() -@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_ON_OFF) +@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_ON_OFF) class ZHAStartupOnOffSelectEntity( ZCLEnumSelectEntity, id_suffix=OnOff.StartUpOnOff.__name__ ): @@ -246,11 +248,11 @@ class TuyaPowerOnState(types.enum8): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_ON_OFF, + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, models={"TS011F", "TS0121", "TS0001", "TS0002", "TS0003", "TS0004"}, ) @CONFIG_DIAGNOSTIC_MATCH( - channel_names="tuya_manufacturer", + cluster_handler_names="tuya_manufacturer", manufacturers={ "_TZE200_7tdtqgwv", "_TZE200_amp6tsvy", @@ -287,7 +289,7 @@ class TuyaBacklightMode(types.enum8): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_ON_OFF, + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, models={"TS011F", "TS0121", "TS0001", "TS0002", "TS0003", "TS0004"}, ) class TuyaBacklightModeSelectEntity(ZCLEnumSelectEntity, id_suffix="backlight_mode"): @@ -308,7 +310,7 @@ class MoesBacklightMode(types.enum8): @CONFIG_DIAGNOSTIC_MATCH( - channel_names="tuya_manufacturer", + cluster_handler_names="tuya_manufacturer", manufacturers={ "_TZE200_7tdtqgwv", "_TZE200_amp6tsvy", @@ -345,7 +347,7 @@ class AqaraMotionSensitivities(types.enum8): @CONFIG_DIAGNOSTIC_MATCH( - channel_names="opple_cluster", + cluster_handler_names="opple_cluster", models={"lumi.motion.ac01", "lumi.motion.ac02", "lumi.motion.agl04"}, ) class AqaraMotionSensitivity(ZCLEnumSelectEntity, id_suffix="motion_sensitivity"): @@ -365,7 +367,7 @@ class HueV1MotionSensitivities(types.enum8): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_OCCUPANCY, + cluster_handler_names=CLUSTER_HANDLER_OCCUPANCY, manufacturers={"Philips", "Signify Netherlands B.V."}, models={"SML001"}, ) @@ -388,7 +390,7 @@ class HueV2MotionSensitivities(types.enum8): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_OCCUPANCY, + cluster_handler_names=CLUSTER_HANDLER_OCCUPANCY, manufacturers={"Philips", "Signify Netherlands B.V."}, models={"SML002", "SML003", "SML004"}, ) @@ -407,7 +409,9 @@ class AqaraMonitoringModess(types.enum8): Left_Right = 0x01 -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.motion.ac01"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.motion.ac01"} +) class AqaraMonitoringMode(ZCLEnumSelectEntity, id_suffix="monitoring_mode"): """Representation of a ZHA monitoring mode configuration entity.""" @@ -424,7 +428,9 @@ class AqaraApproachDistances(types.enum8): Near = 0x02 -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.motion.ac01"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.motion.ac01"} +) class AqaraApproachDistance(ZCLEnumSelectEntity, id_suffix="approach_distance"): """Representation of a ZHA approach distance configuration entity.""" @@ -441,7 +447,7 @@ class AqaraE1ReverseDirection(types.enum8): @CONFIG_DIAGNOSTIC_MATCH( - channel_names="window_covering", models={"lumi.curtain.agl001"} + cluster_handler_names="window_covering", models={"lumi.curtain.agl001"} ) class AqaraCurtainMode(ZCLEnumSelectEntity, id_suffix="window_covering_mode"): """Representation of a ZHA curtain mode configuration entity.""" @@ -459,7 +465,7 @@ class InovelliOutputMode(types.enum1): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliOutputModeEntity(ZCLEnumSelectEntity, id_suffix="output_mode"): """Inovelli output mode control.""" @@ -479,7 +485,7 @@ class InovelliSwitchType(types.enum8): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliSwitchTypeEntity(ZCLEnumSelectEntity, id_suffix="switch_type"): """Inovelli switch type control.""" @@ -497,7 +503,7 @@ class InovelliLedScalingMode(types.enum1): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliLedScalingModeEntity(ZCLEnumSelectEntity, id_suffix="led_scaling_mode"): """Inovelli led mode control.""" @@ -515,7 +521,7 @@ class InovelliNonNeutralOutput(types.enum1): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliNonNeutralOutputEntity( ZCLEnumSelectEntity, id_suffix="increased_non_neutral_output" @@ -534,7 +540,9 @@ class AqaraFeedingMode(types.enum8): Schedule = 0x01 -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"} +) class AqaraPetFeederMode(ZCLEnumSelectEntity, id_suffix="feeding_mode"): """Representation of an Aqara pet feeder mode configuration entity.""" @@ -552,7 +560,9 @@ class AqaraThermostatPresetMode(types.enum8): Away = 0x02 -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"} +) class AqaraThermostatPreset(ZCLEnumSelectEntity, id_suffix="preset"): """Representation of an Aqara thermostat preset configuration entity.""" diff --git a/homeassistant/components/zha/sensor.py b/homeassistant/components/zha/sensor.py index a7a090b13af..e4a2c5384a1 100644 --- a/homeassistant/components/zha/sensor.py +++ b/homeassistant/components/zha/sensor.py @@ -46,19 +46,19 @@ from homeassistant.helpers.typing import StateType from .core import discovery from .core.const import ( - CHANNEL_ANALOG_INPUT, - CHANNEL_BASIC, - CHANNEL_DEVICE_TEMPERATURE, - CHANNEL_ELECTRICAL_MEASUREMENT, - CHANNEL_HUMIDITY, - CHANNEL_ILLUMINANCE, - CHANNEL_LEAF_WETNESS, - CHANNEL_POWER_CONFIGURATION, - CHANNEL_PRESSURE, - CHANNEL_SMARTENERGY_METERING, - CHANNEL_SOIL_MOISTURE, - CHANNEL_TEMPERATURE, - CHANNEL_THERMOSTAT, + CLUSTER_HANDLER_ANALOG_INPUT, + CLUSTER_HANDLER_BASIC, + CLUSTER_HANDLER_DEVICE_TEMPERATURE, + CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT, + CLUSTER_HANDLER_HUMIDITY, + CLUSTER_HANDLER_ILLUMINANCE, + CLUSTER_HANDLER_LEAF_WETNESS, + CLUSTER_HANDLER_POWER_CONFIGURATION, + CLUSTER_HANDLER_PRESSURE, + CLUSTER_HANDLER_SMARTENERGY_METERING, + CLUSTER_HANDLER_SOIL_MOISTURE, + CLUSTER_HANDLER_TEMPERATURE, + CLUSTER_HANDLER_THERMOSTAT, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED, @@ -67,7 +67,7 @@ from .core.registries import SMARTTHINGS_HUMIDITY_CLUSTER, ZHA_ENTITIES from .entity import ZhaEntity if TYPE_CHECKING: - from .core.channels.base import ZigbeeChannel + from .core.cluster_handlers import ClusterHandler from .core.device import ZHADevice PARALLEL_UPDATES = 5 @@ -88,7 +88,9 @@ BATTERY_SIZES = { 255: "Unknown", } -CHANNEL_ST_HUMIDITY_CLUSTER = f"channel_0x{SMARTTHINGS_HUMIDITY_CLUSTER:04x}" +CLUSTER_HANDLER_ST_HUMIDITY_CLUSTER = ( + f"cluster_handler_0x{SMARTTHINGS_HUMIDITY_CLUSTER:04x}" +) STRICT_MATCH = functools.partial(ZHA_ENTITIES.strict_match, Platform.SENSOR) MULTI_MATCH = functools.partial(ZHA_ENTITIES.multipass_match, Platform.SENSOR) @@ -125,50 +127,50 @@ class Sensor(ZhaEntity, SensorEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this sensor.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._channel: ZigbeeChannel = channels[0] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._cluster_handler: ClusterHandler = cluster_handlers[0] @classmethod def create_entity( cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. Return entity if it is a supported configuration, otherwise return None """ - channel = channels[0] - if cls.SENSOR_ATTR in channel.cluster.unsupported_attributes: + cluster_handler = cluster_handlers[0] + if cls.SENSOR_ATTR in cluster_handler.cluster.unsupported_attributes: return None - return cls(unique_id, zha_device, channels, **kwargs) + return cls(unique_id, zha_device, cluster_handlers, **kwargs) async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) @property def native_value(self) -> StateType: """Return the state of the entity.""" assert self.SENSOR_ATTR is not None - raw_state = self._channel.cluster.get(self.SENSOR_ATTR) + raw_state = self._cluster_handler.cluster.get(self.SENSOR_ATTR) if raw_state is None: return None return self.formatter(raw_state) @callback def async_set_state(self, attr_id: int, attr_name: str, value: Any) -> None: - """Handle state update from channel.""" + """Handle state update from cluster handler.""" self.async_write_ha_state() def formatter(self, value: int | enum.IntEnum) -> int | float | str | None: @@ -181,9 +183,9 @@ class Sensor(ZhaEntity, SensorEntity): @MULTI_MATCH( - channel_names=CHANNEL_ANALOG_INPUT, + cluster_handler_names=CLUSTER_HANDLER_ANALOG_INPUT, manufacturers="Digi", - stop_on_match_group=CHANNEL_ANALOG_INPUT, + stop_on_match_group=CLUSTER_HANDLER_ANALOG_INPUT, ) class AnalogInput(Sensor): """Sensor that displays analog input values.""" @@ -191,7 +193,7 @@ class AnalogInput(Sensor): SENSOR_ATTR = "present_value" -@MULTI_MATCH(channel_names=CHANNEL_POWER_CONFIGURATION) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_POWER_CONFIGURATION) class Battery(Sensor): """Battery sensor of power configuration cluster.""" @@ -207,7 +209,7 @@ class Battery(Sensor): cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. @@ -216,7 +218,9 @@ class Battery(Sensor): battery_percent_remaining attribute, but zha-device-handlers takes care of it so create the entity regardless """ - return cls(unique_id, zha_device, channels, **kwargs) + if zha_device.is_mains_powered: + return None + return cls(unique_id, zha_device, cluster_handlers, **kwargs) @staticmethod def formatter(value: int) -> int | None: # pylint: disable=arguments-differ @@ -231,19 +235,19 @@ class Battery(Sensor): def extra_state_attributes(self) -> dict[str, Any]: """Return device state attrs for battery sensors.""" state_attrs = {} - battery_size = self._channel.cluster.get("battery_size") + battery_size = self._cluster_handler.cluster.get("battery_size") if battery_size is not None: state_attrs["battery_size"] = BATTERY_SIZES.get(battery_size, "Unknown") - battery_quantity = self._channel.cluster.get("battery_quantity") + battery_quantity = self._cluster_handler.cluster.get("battery_quantity") if battery_quantity is not None: state_attrs["battery_quantity"] = battery_quantity - battery_voltage = self._channel.cluster.get("battery_voltage") + battery_voltage = self._cluster_handler.cluster.get("battery_voltage") if battery_voltage is not None: state_attrs["battery_voltage"] = round(battery_voltage / 10, 2) return state_attrs -@MULTI_MATCH(channel_names=CHANNEL_ELECTRICAL_MEASUREMENT) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT) class ElectricalMeasurement(Sensor): """Active power measurement.""" @@ -259,19 +263,21 @@ class ElectricalMeasurement(Sensor): def extra_state_attributes(self) -> dict[str, Any]: """Return device state attrs for sensor.""" attrs = {} - if self._channel.measurement_type is not None: - attrs["measurement_type"] = self._channel.measurement_type + if self._cluster_handler.measurement_type is not None: + attrs["measurement_type"] = self._cluster_handler.measurement_type max_attr_name = f"{self.SENSOR_ATTR}_max" - if (max_v := self._channel.cluster.get(max_attr_name)) is not None: + if (max_v := self._cluster_handler.cluster.get(max_attr_name)) is not None: attrs[max_attr_name] = str(self.formatter(max_v)) return attrs def formatter(self, value: int) -> int | float: """Return 'normalized' value.""" - multiplier = getattr(self._channel, f"{self._div_mul_prefix}_multiplier") - divisor = getattr(self._channel, f"{self._div_mul_prefix}_divisor") + multiplier = getattr( + self._cluster_handler, f"{self._div_mul_prefix}_multiplier" + ) + divisor = getattr(self._cluster_handler, f"{self._div_mul_prefix}_divisor") value = float(value * multiplier) / divisor if value < 100 and divisor > 1: return round(value, self._decimals) @@ -284,7 +290,7 @@ class ElectricalMeasurement(Sensor): await super().async_update() -@MULTI_MATCH(channel_names=CHANNEL_ELECTRICAL_MEASUREMENT) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT) class ElectricalMeasurementApparentPower( ElectricalMeasurement, id_suffix="apparent_power" ): @@ -298,7 +304,7 @@ class ElectricalMeasurementApparentPower( _div_mul_prefix = "ac_power" -@MULTI_MATCH(channel_names=CHANNEL_ELECTRICAL_MEASUREMENT) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT) class ElectricalMeasurementRMSCurrent(ElectricalMeasurement, id_suffix="rms_current"): """RMS current measurement.""" @@ -310,7 +316,7 @@ class ElectricalMeasurementRMSCurrent(ElectricalMeasurement, id_suffix="rms_curr _div_mul_prefix = "ac_current" -@MULTI_MATCH(channel_names=CHANNEL_ELECTRICAL_MEASUREMENT) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT) class ElectricalMeasurementRMSVoltage(ElectricalMeasurement, id_suffix="rms_voltage"): """RMS Voltage measurement.""" @@ -322,7 +328,7 @@ class ElectricalMeasurementRMSVoltage(ElectricalMeasurement, id_suffix="rms_volt _div_mul_prefix = "ac_voltage" -@MULTI_MATCH(channel_names=CHANNEL_ELECTRICAL_MEASUREMENT) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT) class ElectricalMeasurementFrequency(ElectricalMeasurement, id_suffix="ac_frequency"): """Frequency measurement.""" @@ -334,7 +340,7 @@ class ElectricalMeasurementFrequency(ElectricalMeasurement, id_suffix="ac_freque _div_mul_prefix = "ac_frequency" -@MULTI_MATCH(channel_names=CHANNEL_ELECTRICAL_MEASUREMENT) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT) class ElectricalMeasurementPowerFactor(ElectricalMeasurement, id_suffix="power_factor"): """Frequency measurement.""" @@ -346,9 +352,13 @@ class ElectricalMeasurementPowerFactor(ElectricalMeasurement, id_suffix="power_f @MULTI_MATCH( - generic_ids=CHANNEL_ST_HUMIDITY_CLUSTER, stop_on_match_group=CHANNEL_HUMIDITY + generic_ids=CLUSTER_HANDLER_ST_HUMIDITY_CLUSTER, + stop_on_match_group=CLUSTER_HANDLER_HUMIDITY, +) +@MULTI_MATCH( + cluster_handler_names=CLUSTER_HANDLER_HUMIDITY, + stop_on_match_group=CLUSTER_HANDLER_HUMIDITY, ) -@MULTI_MATCH(channel_names=CHANNEL_HUMIDITY, stop_on_match_group=CHANNEL_HUMIDITY) class Humidity(Sensor): """Humidity sensor.""" @@ -360,7 +370,7 @@ class Humidity(Sensor): _attr_native_unit_of_measurement = PERCENTAGE -@MULTI_MATCH(channel_names=CHANNEL_SOIL_MOISTURE) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_SOIL_MOISTURE) class SoilMoisture(Sensor): """Soil Moisture sensor.""" @@ -372,7 +382,7 @@ class SoilMoisture(Sensor): _attr_native_unit_of_measurement = PERCENTAGE -@MULTI_MATCH(channel_names=CHANNEL_LEAF_WETNESS) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_LEAF_WETNESS) class LeafWetness(Sensor): """Leaf Wetness sensor.""" @@ -384,7 +394,7 @@ class LeafWetness(Sensor): _attr_native_unit_of_measurement = PERCENTAGE -@MULTI_MATCH(channel_names=CHANNEL_ILLUMINANCE) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ILLUMINANCE) class Illuminance(Sensor): """Illuminance Sensor.""" @@ -400,8 +410,8 @@ class Illuminance(Sensor): @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, - stop_on_match_group=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, + stop_on_match_group=CLUSTER_HANDLER_SMARTENERGY_METERING, ) class SmartEnergyMetering(Sensor): """Metering sensor.""" @@ -428,21 +438,21 @@ class SmartEnergyMetering(Sensor): } def formatter(self, value: int) -> int | float: - """Pass through channel formatter.""" - return self._channel.demand_formatter(value) + """Pass through cluster handler formatter.""" + return self._cluster_handler.demand_formatter(value) @property def native_unit_of_measurement(self) -> str | None: """Return Unit of measurement.""" - return self.unit_of_measure_map.get(self._channel.unit_of_measurement) + return self.unit_of_measure_map.get(self._cluster_handler.unit_of_measurement) @property def extra_state_attributes(self) -> dict[str, Any]: """Return device state attrs for battery sensors.""" attrs = {} - if self._channel.device_type is not None: - attrs["device_type"] = self._channel.device_type - if (status := self._channel.status) is not None: + if self._cluster_handler.device_type is not None: + attrs["device_type"] = self._cluster_handler.device_type + if (status := self._cluster_handler.status) is not None: if isinstance(status, enum.IntFlag) and sys.version_info >= (3, 11): attrs["status"] = str( status.name if status.name is not None else status.value @@ -453,8 +463,8 @@ class SmartEnergyMetering(Sensor): @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, - stop_on_match_group=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, + stop_on_match_group=CLUSTER_HANDLER_SMARTENERGY_METERING, ) class SmartEnergySummation(SmartEnergyMetering, id_suffix="summation_delivered"): """Smart Energy Metering summation sensor.""" @@ -482,17 +492,20 @@ class SmartEnergySummation(SmartEnergyMetering, id_suffix="summation_delivered") def formatter(self, value: int) -> int | float: """Numeric pass-through formatter.""" - if self._channel.unit_of_measurement != 0: - return self._channel.summa_formatter(value) + if self._cluster_handler.unit_of_measurement != 0: + return self._cluster_handler.summa_formatter(value) - cooked = float(self._channel.multiplier * value) / self._channel.divisor + cooked = ( + float(self._cluster_handler.multiplier * value) + / self._cluster_handler.divisor + ) return round(cooked, 3) @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, models={"TS011F", "ZLinky_TIC"}, - stop_on_match_group=CHANNEL_SMARTENERGY_METERING, + stop_on_match_group=CLUSTER_HANDLER_SMARTENERGY_METERING, ) class PolledSmartEnergySummation(SmartEnergySummation): """Polled Smart Energy Metering summation sensor.""" @@ -503,11 +516,11 @@ class PolledSmartEnergySummation(SmartEnergySummation): """Retrieve latest state.""" if not self.available: return - await self._channel.async_force_update() + await self._cluster_handler.async_force_update() @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, models={"ZLinky_TIC"}, ) class Tier1SmartEnergySummation( @@ -520,7 +533,7 @@ class Tier1SmartEnergySummation( @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, models={"ZLinky_TIC"}, ) class Tier2SmartEnergySummation( @@ -533,7 +546,7 @@ class Tier2SmartEnergySummation( @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, models={"ZLinky_TIC"}, ) class Tier3SmartEnergySummation( @@ -546,7 +559,7 @@ class Tier3SmartEnergySummation( @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, models={"ZLinky_TIC"}, ) class Tier4SmartEnergySummation( @@ -559,7 +572,7 @@ class Tier4SmartEnergySummation( @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, models={"ZLinky_TIC"}, ) class Tier5SmartEnergySummation( @@ -572,7 +585,7 @@ class Tier5SmartEnergySummation( @MULTI_MATCH( - channel_names=CHANNEL_SMARTENERGY_METERING, + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, models={"ZLinky_TIC"}, ) class Tier6SmartEnergySummation( @@ -584,7 +597,7 @@ class Tier6SmartEnergySummation( _attr_name: str = "Tier 6 summation delivered" -@MULTI_MATCH(channel_names=CHANNEL_PRESSURE) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_PRESSURE) class Pressure(Sensor): """Pressure sensor.""" @@ -596,7 +609,7 @@ class Pressure(Sensor): _attr_native_unit_of_measurement = UnitOfPressure.HPA -@MULTI_MATCH(channel_names=CHANNEL_TEMPERATURE) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_TEMPERATURE) class Temperature(Sensor): """Temperature Sensor.""" @@ -608,7 +621,7 @@ class Temperature(Sensor): _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS -@MULTI_MATCH(channel_names=CHANNEL_DEVICE_TEMPERATURE) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_DEVICE_TEMPERATURE) class DeviceTemperature(Sensor): """Device Temperature Sensor.""" @@ -621,7 +634,7 @@ class DeviceTemperature(Sensor): _attr_entity_category = EntityCategory.DIAGNOSTIC -@MULTI_MATCH(channel_names="carbon_dioxide_concentration") +@MULTI_MATCH(cluster_handler_names="carbon_dioxide_concentration") class CarbonDioxideConcentration(Sensor): """Carbon Dioxide Concentration sensor.""" @@ -634,7 +647,7 @@ class CarbonDioxideConcentration(Sensor): _attr_native_unit_of_measurement = CONCENTRATION_PARTS_PER_MILLION -@MULTI_MATCH(channel_names="carbon_monoxide_concentration") +@MULTI_MATCH(cluster_handler_names="carbon_monoxide_concentration") class CarbonMonoxideConcentration(Sensor): """Carbon Monoxide Concentration sensor.""" @@ -647,8 +660,8 @@ class CarbonMonoxideConcentration(Sensor): _attr_native_unit_of_measurement = CONCENTRATION_PARTS_PER_MILLION -@MULTI_MATCH(generic_ids="channel_0x042e", stop_on_match_group="voc_level") -@MULTI_MATCH(channel_names="voc_level", stop_on_match_group="voc_level") +@MULTI_MATCH(generic_ids="cluster_handler_0x042e", stop_on_match_group="voc_level") +@MULTI_MATCH(cluster_handler_names="voc_level", stop_on_match_group="voc_level") class VOCLevel(Sensor): """VOC Level sensor.""" @@ -662,7 +675,7 @@ class VOCLevel(Sensor): @MULTI_MATCH( - channel_names="voc_level", + cluster_handler_names="voc_level", models="lumi.airmonitor.acn01", stop_on_match_group="voc_level", ) @@ -678,7 +691,7 @@ class PPBVOCLevel(Sensor): _attr_native_unit_of_measurement = CONCENTRATION_PARTS_PER_BILLION -@MULTI_MATCH(channel_names="pm25") +@MULTI_MATCH(cluster_handler_names="pm25") class PM25(Sensor): """Particulate Matter 2.5 microns or less sensor.""" @@ -690,7 +703,7 @@ class PM25(Sensor): _attr_native_unit_of_measurement = CONCENTRATION_MICROGRAMS_PER_CUBIC_METER -@MULTI_MATCH(channel_names="formaldehyde_concentration") +@MULTI_MATCH(cluster_handler_names="formaldehyde_concentration") class FormaldehydeConcentration(Sensor): """Formaldehyde Concentration sensor.""" @@ -702,7 +715,10 @@ class FormaldehydeConcentration(Sensor): _attr_native_unit_of_measurement = CONCENTRATION_PARTS_PER_MILLION -@MULTI_MATCH(channel_names=CHANNEL_THERMOSTAT, stop_on_match_group=CHANNEL_THERMOSTAT) +@MULTI_MATCH( + cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT, + stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT, +) class ThermostatHVACAction(Sensor, id_suffix="hvac_action"): """Thermostat HVAC action sensor.""" @@ -713,7 +729,7 @@ class ThermostatHVACAction(Sensor, id_suffix="hvac_action"): cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. @@ -721,14 +737,14 @@ class ThermostatHVACAction(Sensor, id_suffix="hvac_action"): Return entity if it is a supported configuration, otherwise return None """ - return cls(unique_id, zha_device, channels, **kwargs) + return cls(unique_id, zha_device, cluster_handlers, **kwargs) @property def native_value(self) -> str | None: """Return the current HVAC action.""" if ( - self._channel.pi_heating_demand is None - and self._channel.pi_cooling_demand is None + self._cluster_handler.pi_heating_demand is None + and self._cluster_handler.pi_cooling_demand is None ): return self._rm_rs_action return self._pi_demand_action @@ -737,36 +753,36 @@ class ThermostatHVACAction(Sensor, id_suffix="hvac_action"): def _rm_rs_action(self) -> HVACAction | None: """Return the current HVAC action based on running mode and running state.""" - if (running_state := self._channel.running_state) is None: + if (running_state := self._cluster_handler.running_state) is None: return None rs_heat = ( - self._channel.RunningState.Heat_State_On - | self._channel.RunningState.Heat_2nd_Stage_On + self._cluster_handler.RunningState.Heat_State_On + | self._cluster_handler.RunningState.Heat_2nd_Stage_On ) if running_state & rs_heat: return HVACAction.HEATING rs_cool = ( - self._channel.RunningState.Cool_State_On - | self._channel.RunningState.Cool_2nd_Stage_On + self._cluster_handler.RunningState.Cool_State_On + | self._cluster_handler.RunningState.Cool_2nd_Stage_On ) if running_state & rs_cool: return HVACAction.COOLING - running_state = self._channel.running_state + running_state = self._cluster_handler.running_state if running_state and running_state & ( - self._channel.RunningState.Fan_State_On - | self._channel.RunningState.Fan_2nd_Stage_On - | self._channel.RunningState.Fan_3rd_Stage_On + self._cluster_handler.RunningState.Fan_State_On + | self._cluster_handler.RunningState.Fan_2nd_Stage_On + | self._cluster_handler.RunningState.Fan_3rd_Stage_On ): return HVACAction.FAN - running_state = self._channel.running_state - if running_state and running_state & self._channel.RunningState.Idle: + running_state = self._cluster_handler.running_state + if running_state and running_state & self._cluster_handler.RunningState.Idle: return HVACAction.IDLE - if self._channel.system_mode != self._channel.SystemMode.Off: + if self._cluster_handler.system_mode != self._cluster_handler.SystemMode.Off: return HVACAction.IDLE return HVACAction.OFF @@ -774,27 +790,27 @@ class ThermostatHVACAction(Sensor, id_suffix="hvac_action"): def _pi_demand_action(self) -> HVACAction: """Return the current HVAC action based on pi_demands.""" - heating_demand = self._channel.pi_heating_demand + heating_demand = self._cluster_handler.pi_heating_demand if heating_demand is not None and heating_demand > 0: return HVACAction.HEATING - cooling_demand = self._channel.pi_cooling_demand + cooling_demand = self._cluster_handler.pi_cooling_demand if cooling_demand is not None and cooling_demand > 0: return HVACAction.COOLING - if self._channel.system_mode != self._channel.SystemMode.Off: + if self._cluster_handler.system_mode != self._cluster_handler.SystemMode.Off: return HVACAction.IDLE return HVACAction.OFF @callback def async_set_state(self, *args, **kwargs) -> None: - """Handle state update from channel.""" + """Handle state update from cluster handler.""" self.async_write_ha_state() @MULTI_MATCH( - channel_names={CHANNEL_THERMOSTAT}, + cluster_handler_names={CLUSTER_HANDLER_THERMOSTAT}, manufacturers="Sinope Technologies", - stop_on_match_group=CHANNEL_THERMOSTAT, + stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT, ) class SinopeHVACAction(ThermostatHVACAction): """Sinope Thermostat HVAC action sensor.""" @@ -803,28 +819,28 @@ class SinopeHVACAction(ThermostatHVACAction): def _rm_rs_action(self) -> HVACAction: """Return the current HVAC action based on running mode and running state.""" - running_mode = self._channel.running_mode - if running_mode == self._channel.RunningMode.Heat: + running_mode = self._cluster_handler.running_mode + if running_mode == self._cluster_handler.RunningMode.Heat: return HVACAction.HEATING - if running_mode == self._channel.RunningMode.Cool: + if running_mode == self._cluster_handler.RunningMode.Cool: return HVACAction.COOLING - running_state = self._channel.running_state + running_state = self._cluster_handler.running_state if running_state and running_state & ( - self._channel.RunningState.Fan_State_On - | self._channel.RunningState.Fan_2nd_Stage_On - | self._channel.RunningState.Fan_3rd_Stage_On + self._cluster_handler.RunningState.Fan_State_On + | self._cluster_handler.RunningState.Fan_2nd_Stage_On + | self._cluster_handler.RunningState.Fan_3rd_Stage_On ): return HVACAction.FAN if ( - self._channel.system_mode != self._channel.SystemMode.Off - and running_mode == self._channel.SystemMode.Off + self._cluster_handler.system_mode != self._cluster_handler.SystemMode.Off + and running_mode == self._cluster_handler.SystemMode.Off ): return HVACAction.IDLE return HVACAction.OFF -@MULTI_MATCH(channel_names=CHANNEL_BASIC) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_BASIC) class RSSISensor(Sensor, id_suffix="rssi"): """RSSI sensor for a device.""" @@ -842,17 +858,17 @@ class RSSISensor(Sensor, id_suffix="rssi"): cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. Return entity if it is a supported configuration, otherwise return None """ - key = f"{CHANNEL_BASIC}_{cls.unique_id_suffix}" + key = f"{CLUSTER_HANDLER_BASIC}_{cls.unique_id_suffix}" if ZHA_ENTITIES.prevent_entity_creation(Platform.SENSOR, zha_device.ieee, key): return None - return cls(unique_id, zha_device, channels, **kwargs) + return cls(unique_id, zha_device, cluster_handlers, **kwargs) @property def native_value(self) -> StateType: @@ -860,7 +876,7 @@ class RSSISensor(Sensor, id_suffix="rssi"): return getattr(self._zha_device.device, self.unique_id_suffix) -@MULTI_MATCH(channel_names=CHANNEL_BASIC) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_BASIC) class LQISensor(RSSISensor, id_suffix="lqi"): """LQI sensor for a device.""" @@ -870,7 +886,7 @@ class LQISensor(RSSISensor, id_suffix="lqi"): @MULTI_MATCH( - channel_names="tuya_manufacturer", + cluster_handler_names="tuya_manufacturer", manufacturers={ "_TZE200_htnnfasr", }, @@ -885,7 +901,7 @@ class TimeLeft(Sensor, id_suffix="time_left"): _attr_native_unit_of_measurement = UnitOfTime.MINUTES -@MULTI_MATCH(channel_names="ikea_airpurifier") +@MULTI_MATCH(cluster_handler_names="ikea_airpurifier") class IkeaDeviceRunTime(Sensor, id_suffix="device_run_time"): """Sensor that displays device run time (in minutes).""" @@ -896,7 +912,7 @@ class IkeaDeviceRunTime(Sensor, id_suffix="device_run_time"): _attr_native_unit_of_measurement = UnitOfTime.MINUTES -@MULTI_MATCH(channel_names="ikea_airpurifier") +@MULTI_MATCH(cluster_handler_names="ikea_airpurifier") class IkeaFilterRunTime(Sensor, id_suffix="filter_run_time"): """Sensor that displays run time of the current filter (in minutes).""" @@ -914,7 +930,7 @@ class AqaraFeedingSource(types.enum8): HomeAssistant = 0x02 -@MULTI_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"}) class AqaraPetFeederLastFeedingSource(Sensor, id_suffix="last_feeding_source"): """Sensor that displays the last feeding source of pet feeder.""" @@ -927,7 +943,7 @@ class AqaraPetFeederLastFeedingSource(Sensor, id_suffix="last_feeding_source"): return AqaraFeedingSource(value).name -@MULTI_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"}) class AqaraPetFeederLastFeedingSize(Sensor, id_suffix="last_feeding_size"): """Sensor that displays the last feeding size of the pet feeder.""" @@ -936,7 +952,7 @@ class AqaraPetFeederLastFeedingSize(Sensor, id_suffix="last_feeding_size"): _attr_icon: str = "mdi:counter" -@MULTI_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"}) class AqaraPetFeederPortionsDispensed(Sensor, id_suffix="portions_dispensed"): """Sensor that displays the number of portions dispensed by the pet feeder.""" @@ -946,7 +962,7 @@ class AqaraPetFeederPortionsDispensed(Sensor, id_suffix="portions_dispensed"): _attr_icon: str = "mdi:counter" -@MULTI_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"}) class AqaraPetFeederWeightDispensed(Sensor, id_suffix="weight_dispensed"): """Sensor that displays the weight dispensed by the pet feeder.""" @@ -957,7 +973,7 @@ class AqaraPetFeederWeightDispensed(Sensor, id_suffix="weight_dispensed"): _attr_icon: str = "mdi:weight-gram" -@MULTI_MATCH(channel_names="opple_cluster", models={"lumi.sensor_smoke.acn03"}) +@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"lumi.sensor_smoke.acn03"}) class AqaraSmokeDensityDbm(Sensor, id_suffix="smoke_density_dbm"): """Sensor that displays the smoke density of an Aqara smoke sensor in dB/m.""" diff --git a/homeassistant/components/zha/siren.py b/homeassistant/components/zha/siren.py index dedb339292e..043df779dca 100644 --- a/homeassistant/components/zha/siren.py +++ b/homeassistant/components/zha/siren.py @@ -22,9 +22,9 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_call_later from .core import discovery -from .core.channels.security import IasWd +from .core.cluster_handlers.security import IasWd from .core.const import ( - CHANNEL_IAS_WD, + CLUSTER_HANDLER_IAS_WD, DATA_ZHA, SIGNAL_ADD_ENTITIES, WARNING_DEVICE_MODE_BURGLAR, @@ -43,7 +43,7 @@ from .core.registries import ZHA_ENTITIES from .entity import ZhaEntity if TYPE_CHECKING: - from .core.channels.base import ZigbeeChannel + from .core.cluster_handlers import ClusterHandler from .core.device import ZHADevice MULTI_MATCH = functools.partial(ZHA_ENTITIES.multipass_match, Platform.SIREN) @@ -70,7 +70,7 @@ async def async_setup_entry( config_entry.async_on_unload(unsub) -@MULTI_MATCH(channel_names=CHANNEL_IAS_WD) +@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_IAS_WD) class ZHASiren(ZhaEntity, SirenEntity): """Representation of a ZHA siren.""" @@ -78,7 +78,7 @@ class ZHASiren(ZhaEntity, SirenEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs, ) -> None: """Init this siren.""" @@ -97,8 +97,8 @@ class ZHASiren(ZhaEntity, SirenEntity): WARNING_DEVICE_MODE_FIRE_PANIC: "Fire Panic", WARNING_DEVICE_MODE_EMERGENCY_PANIC: "Emergency Panic", } - super().__init__(unique_id, zha_device, channels, **kwargs) - self._channel: IasWd = cast(IasWd, channels[0]) + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._cluster_handler: IasWd = cast(IasWd, cluster_handlers[0]) self._attr_is_on: bool = False self._off_listener: Callable[[], None] | None = None @@ -107,22 +107,28 @@ class ZHASiren(ZhaEntity, SirenEntity): if self._off_listener: self._off_listener() self._off_listener = None - tone_cache = self._channel.data_cache.get(WD.Warning.WarningMode.__name__) + tone_cache = self._cluster_handler.data_cache.get( + WD.Warning.WarningMode.__name__ + ) siren_tone = ( tone_cache.value if tone_cache is not None else WARNING_DEVICE_MODE_EMERGENCY ) siren_duration = DEFAULT_DURATION - level_cache = self._channel.data_cache.get(WD.Warning.SirenLevel.__name__) + level_cache = self._cluster_handler.data_cache.get( + WD.Warning.SirenLevel.__name__ + ) siren_level = ( level_cache.value if level_cache is not None else WARNING_DEVICE_SOUND_HIGH ) - strobe_cache = self._channel.data_cache.get(Strobe.__name__) + strobe_cache = self._cluster_handler.data_cache.get(Strobe.__name__) should_strobe = ( strobe_cache.value if strobe_cache is not None else Strobe.No_Strobe ) - strobe_level_cache = self._channel.data_cache.get(WD.StrobeLevel.__name__) + strobe_level_cache = self._cluster_handler.data_cache.get( + WD.StrobeLevel.__name__ + ) strobe_level = ( strobe_level_cache.value if strobe_level_cache is not None @@ -134,7 +140,7 @@ class ZHASiren(ZhaEntity, SirenEntity): siren_tone = tone if (level := kwargs.get(ATTR_VOLUME_LEVEL)) is not None: siren_level = int(level) - await self._channel.issue_start_warning( + await self._cluster_handler.issue_start_warning( mode=siren_tone, warning_duration=siren_duration, siren_level=siren_level, @@ -150,7 +156,7 @@ class ZHASiren(ZhaEntity, SirenEntity): async def async_turn_off(self, **kwargs: Any) -> None: """Turn off siren.""" - await self._channel.issue_start_warning( + await self._cluster_handler.issue_start_warning( mode=WARNING_DEVICE_MODE_STOP, strobe=WARNING_DEVICE_STROBE_NO ) self._attr_is_on = False diff --git a/homeassistant/components/zha/switch.py b/homeassistant/components/zha/switch.py index c57075a15ca..9e2714ffaba 100644 --- a/homeassistant/components/zha/switch.py +++ b/homeassistant/components/zha/switch.py @@ -19,9 +19,9 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .core import discovery from .core.const import ( - CHANNEL_BASIC, - CHANNEL_INOVELLI, - CHANNEL_ON_OFF, + CLUSTER_HANDLER_BASIC, + CLUSTER_HANDLER_INOVELLI, + CLUSTER_HANDLER_ON_OFF, DATA_ZHA, SIGNAL_ADD_ENTITIES, SIGNAL_ATTR_UPDATED, @@ -30,7 +30,7 @@ from .core.registries import ZHA_ENTITIES from .entity import ZhaEntity, ZhaGroupEntity if TYPE_CHECKING: - from .core.channels.base import ZigbeeChannel + from .core.cluster_handlers import ClusterHandler from .core.device import ZHADevice STRICT_MATCH = functools.partial(ZHA_ENTITIES.strict_match, Platform.SWITCH) @@ -60,7 +60,7 @@ async def async_setup_entry( config_entry.async_on_unload(unsub) -@STRICT_MATCH(channel_names=CHANNEL_ON_OFF) +@STRICT_MATCH(cluster_handler_names=CLUSTER_HANDLER_ON_OFF) class Switch(ZhaEntity, SwitchEntity): """ZHA switch.""" @@ -68,51 +68,53 @@ class Switch(ZhaEntity, SwitchEntity): self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Initialize the ZHA switch.""" - super().__init__(unique_id, zha_device, channels, **kwargs) - self._on_off_channel = self.cluster_channels[CHANNEL_ON_OFF] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) + self._on_off_cluster_handler = self.cluster_handlers[CLUSTER_HANDLER_ON_OFF] @property def is_on(self) -> bool: """Return if the switch is on based on the statemachine.""" - if self._on_off_channel.on_off is None: + if self._on_off_cluster_handler.on_off is None: return False - return self._on_off_channel.on_off + return self._on_off_cluster_handler.on_off async def async_turn_on(self, **kwargs: Any) -> None: """Turn the entity on.""" - result = await self._on_off_channel.turn_on() + result = await self._on_off_cluster_handler.turn_on() if not result: return self.async_write_ha_state() async def async_turn_off(self, **kwargs: Any) -> None: """Turn the entity off.""" - result = await self._on_off_channel.turn_off() + result = await self._on_off_cluster_handler.turn_off() if not result: return self.async_write_ha_state() @callback def async_set_state(self, attr_id: int, attr_name: str, value: Any): - """Handle state update from channel.""" + """Handle state update from cluster handler.""" self.async_write_ha_state() async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._on_off_channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._on_off_cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) async def async_update(self) -> None: """Attempt to retrieve on off state from the switch.""" await super().async_update() - if self._on_off_channel: - await self._on_off_channel.get_attribute_value("on_off", from_cache=False) + if self._on_off_cluster_handler: + await self._on_off_cluster_handler.get_attribute_value( + "on_off", from_cache=False + ) @GROUP_MATCH() @@ -132,7 +134,7 @@ class SwitchGroup(ZhaGroupEntity, SwitchEntity): self._available: bool self._state: bool group = self.zha_device.gateway.get_group(self._group_id) - self._on_off_channel = group.endpoint[OnOff.cluster_id] + self._on_off_cluster_handler = group.endpoint[OnOff.cluster_id] @property def is_on(self) -> bool: @@ -141,7 +143,7 @@ class SwitchGroup(ZhaGroupEntity, SwitchEntity): async def async_turn_on(self, **kwargs: Any) -> None: """Turn the entity on.""" - result = await self._on_off_channel.on() + result = await self._on_off_cluster_handler.on() if isinstance(result, Exception) or result[1] is not Status.SUCCESS: return self._state = True @@ -149,7 +151,7 @@ class SwitchGroup(ZhaGroupEntity, SwitchEntity): async def async_turn_off(self, **kwargs: Any) -> None: """Turn the entity off.""" - result = await self._on_off_channel.off() + result = await self._on_off_cluster_handler.off() if isinstance(result, Exception) or result[1] is not Status.SUCCESS: return self._state = False @@ -178,17 +180,17 @@ class ZHASwitchConfigurationEntity(ZhaEntity, SwitchEntity): cls, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> Self | None: """Entity Factory. Return entity if it is a supported configuration, otherwise return None """ - channel = channels[0] + cluster_handler = cluster_handlers[0] if ( - cls._zcl_attribute in channel.cluster.unsupported_attributes - or channel.cluster.get(cls._zcl_attribute) is None + cls._zcl_attribute in cluster_handler.cluster.unsupported_attributes + or cluster_handler.cluster.get(cls._zcl_attribute) is None ): _LOGGER.debug( "%s is not supported - skipping %s entity creation", @@ -197,48 +199,48 @@ class ZHASwitchConfigurationEntity(ZhaEntity, SwitchEntity): ) return None - return cls(unique_id, zha_device, channels, **kwargs) + return cls(unique_id, zha_device, cluster_handlers, **kwargs) def __init__( self, unique_id: str, zha_device: ZHADevice, - channels: list[ZigbeeChannel], + cluster_handlers: list[ClusterHandler], **kwargs: Any, ) -> None: """Init this number configuration entity.""" - self._channel: ZigbeeChannel = channels[0] - super().__init__(unique_id, zha_device, channels, **kwargs) + self._cluster_handler: ClusterHandler = cluster_handlers[0] + super().__init__(unique_id, zha_device, cluster_handlers, **kwargs) async def async_added_to_hass(self) -> None: """Run when about to be added to hass.""" await super().async_added_to_hass() self.async_accept_signal( - self._channel, SIGNAL_ATTR_UPDATED, self.async_set_state + self._cluster_handler, SIGNAL_ATTR_UPDATED, self.async_set_state ) @callback def async_set_state(self, attr_id: int, attr_name: str, value: Any): - """Handle state update from channel.""" + """Handle state update from cluster handler.""" self.async_write_ha_state() @property def inverted(self) -> bool: """Return True if the switch is inverted.""" if self._zcl_inverter_attribute: - return bool(self._channel.cluster.get(self._zcl_inverter_attribute)) + return bool(self._cluster_handler.cluster.get(self._zcl_inverter_attribute)) return self._force_inverted @property def is_on(self) -> bool: """Return if the switch is on based on the statemachine.""" - val = bool(self._channel.cluster.get(self._zcl_attribute)) + val = bool(self._cluster_handler.cluster.get(self._zcl_attribute)) return (not val) if self.inverted else val async def async_turn_on_off(self, state: bool) -> None: """Turn the entity on or off.""" try: - result = await self._channel.cluster.write_attributes( + result = await self._cluster_handler.cluster.write_attributes( {self._zcl_attribute: not state if self.inverted else state} ) except zigpy.exceptions.ZigbeeException as ex: @@ -261,18 +263,18 @@ class ZHASwitchConfigurationEntity(ZhaEntity, SwitchEntity): """Attempt to retrieve the state of the entity.""" await super().async_update() self.error("Polling current state") - if self._channel: - value = await self._channel.get_attribute_value( + if self._cluster_handler: + value = await self._cluster_handler.get_attribute_value( self._zcl_attribute, from_cache=False ) - await self._channel.get_attribute_value( + await self._cluster_handler.get_attribute_value( self._zcl_inverter_attribute, from_cache=False ) self.debug("read value=%s, inverted=%s", value, self.inverted) @CONFIG_DIAGNOSTIC_MATCH( - channel_names="tuya_manufacturer", + cluster_handler_names="tuya_manufacturer", manufacturers={ "_TZE200_b6wax7g0", }, @@ -286,7 +288,9 @@ class OnOffWindowDetectionFunctionConfigurationEntity( _zcl_inverter_attribute: str = "window_detection_function_inverter" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.motion.ac02"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.motion.ac02"} +) class P1MotionTriggerIndicatorSwitch( ZHASwitchConfigurationEntity, id_suffix="trigger_indicator" ): @@ -297,7 +301,8 @@ class P1MotionTriggerIndicatorSwitch( @CONFIG_DIAGNOSTIC_MATCH( - channel_names="opple_cluster", models={"lumi.plug.mmeu01", "lumi.plug.maeu01"} + cluster_handler_names="opple_cluster", + models={"lumi.plug.mmeu01", "lumi.plug.maeu01"}, ) class XiaomiPlugPowerOutageMemorySwitch( ZHASwitchConfigurationEntity, id_suffix="power_outage_memory" @@ -309,7 +314,7 @@ class XiaomiPlugPowerOutageMemorySwitch( @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_BASIC, + cluster_handler_names=CLUSTER_HANDLER_BASIC, manufacturers={"Philips", "Signify Netherlands B.V."}, models={"SML001", "SML002", "SML003", "SML004"}, ) @@ -323,7 +328,7 @@ class HueMotionTriggerIndicatorSwitch( @CONFIG_DIAGNOSTIC_MATCH( - channel_names="ikea_airpurifier", + cluster_handler_names="ikea_airpurifier", models={"STARKVIND Air purifier", "STARKVIND Air purifier table"}, ) class ChildLock(ZHASwitchConfigurationEntity, id_suffix="child_lock"): @@ -334,7 +339,7 @@ class ChildLock(ZHASwitchConfigurationEntity, id_suffix="child_lock"): @CONFIG_DIAGNOSTIC_MATCH( - channel_names="ikea_airpurifier", + cluster_handler_names="ikea_airpurifier", models={"STARKVIND Air purifier", "STARKVIND Air purifier table"}, ) class DisableLed(ZHASwitchConfigurationEntity, id_suffix="disable_led"): @@ -345,7 +350,7 @@ class DisableLed(ZHASwitchConfigurationEntity, id_suffix="disable_led"): @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliInvertSwitch(ZHASwitchConfigurationEntity, id_suffix="invert_switch"): """Inovelli invert switch control.""" @@ -355,7 +360,7 @@ class InovelliInvertSwitch(ZHASwitchConfigurationEntity, id_suffix="invert_switc @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliSmartBulbMode(ZHASwitchConfigurationEntity, id_suffix="smart_bulb_mode"): """Inovelli smart bulb mode control.""" @@ -365,7 +370,7 @@ class InovelliSmartBulbMode(ZHASwitchConfigurationEntity, id_suffix="smart_bulb_ @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliDoubleTapUpEnabled( ZHASwitchConfigurationEntity, id_suffix="double_tap_up_enabled" @@ -377,7 +382,7 @@ class InovelliDoubleTapUpEnabled( @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliDoubleTapDownEnabled( ZHASwitchConfigurationEntity, id_suffix="double_tap_down_enabled" @@ -389,7 +394,7 @@ class InovelliDoubleTapDownEnabled( @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliAuxSwitchScenes( ZHASwitchConfigurationEntity, id_suffix="aux_switch_scenes" @@ -401,7 +406,7 @@ class InovelliAuxSwitchScenes( @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliBindingOffToOnSyncLevel( ZHASwitchConfigurationEntity, id_suffix="binding_off_to_on_sync_level" @@ -413,7 +418,7 @@ class InovelliBindingOffToOnSyncLevel( @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliLocalProtection( ZHASwitchConfigurationEntity, id_suffix="local_protection" @@ -425,7 +430,7 @@ class InovelliLocalProtection( @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliOnOffLEDMode(ZHASwitchConfigurationEntity, id_suffix="on_off_led_mode"): """Inovelli only 1 LED mode control.""" @@ -435,7 +440,7 @@ class InovelliOnOffLEDMode(ZHASwitchConfigurationEntity, id_suffix="on_off_led_m @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliFirmwareProgressLED( ZHASwitchConfigurationEntity, id_suffix="firmware_progress_led" @@ -447,7 +452,7 @@ class InovelliFirmwareProgressLED( @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliRelayClickInOnOffMode( ZHASwitchConfigurationEntity, id_suffix="relay_click_in_on_off_mode" @@ -459,7 +464,7 @@ class InovelliRelayClickInOnOffMode( @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_INOVELLI, + cluster_handler_names=CLUSTER_HANDLER_INOVELLI, ) class InovelliDisableDoubleTapClearNotificationsMode( ZHASwitchConfigurationEntity, id_suffix="disable_clear_notifications_double_tap" @@ -470,7 +475,9 @@ class InovelliDisableDoubleTapClearNotificationsMode( _attr_name: str = "Disable config 2x tap to clear notifications" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"} +) class AqaraPetFeederLEDIndicator( ZHASwitchConfigurationEntity, id_suffix="disable_led_indicator" ): @@ -482,7 +489,9 @@ class AqaraPetFeederLEDIndicator( _attr_icon: str = "mdi:led-on" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"aqara.feeder.acn001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"} +) class AqaraPetFeederChildLock(ZHASwitchConfigurationEntity, id_suffix="child_lock"): """Representation of a child lock configuration entity.""" @@ -492,7 +501,7 @@ class AqaraPetFeederChildLock(ZHASwitchConfigurationEntity, id_suffix="child_loc @CONFIG_DIAGNOSTIC_MATCH( - channel_names=CHANNEL_ON_OFF, + cluster_handler_names=CLUSTER_HANDLER_ON_OFF, models={"TS011F"}, ) class TuyaChildLockSwitch(ZHASwitchConfigurationEntity, id_suffix="child_lock"): @@ -503,7 +512,9 @@ class TuyaChildLockSwitch(ZHASwitchConfigurationEntity, id_suffix="child_lock"): _attr_icon: str = "mdi:account-lock" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"} +) class AqaraThermostatWindowDetection( ZHASwitchConfigurationEntity, id_suffix="window_detection" ): @@ -513,7 +524,9 @@ class AqaraThermostatWindowDetection( _attr_name = "Window detection" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"} +) class AqaraThermostatValveDetection( ZHASwitchConfigurationEntity, id_suffix="valve_detection" ): @@ -523,7 +536,9 @@ class AqaraThermostatValveDetection( _attr_name = "Valve detection" -@CONFIG_DIAGNOSTIC_MATCH(channel_names="opple_cluster", models={"lumi.airrtc.agl001"}) +@CONFIG_DIAGNOSTIC_MATCH( + cluster_handler_names="opple_cluster", models={"lumi.airrtc.agl001"} +) class AqaraThermostatChildLock(ZHASwitchConfigurationEntity, id_suffix="child_lock"): """Representation of an Aqara thermostat child lock configuration entity.""" @@ -533,7 +548,7 @@ class AqaraThermostatChildLock(ZHASwitchConfigurationEntity, id_suffix="child_lo @CONFIG_DIAGNOSTIC_MATCH( - channel_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} + cluster_handler_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} ) class AqaraHeartbeatIndicator( ZHASwitchConfigurationEntity, id_suffix="heartbeat_indicator" @@ -546,7 +561,7 @@ class AqaraHeartbeatIndicator( @CONFIG_DIAGNOSTIC_MATCH( - channel_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} + cluster_handler_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} ) class AqaraLinkageAlarm(ZHASwitchConfigurationEntity, id_suffix="linkage_alarm"): """Representation of a linkage alarm configuration entity for Aqara smoke sensors.""" @@ -557,7 +572,7 @@ class AqaraLinkageAlarm(ZHASwitchConfigurationEntity, id_suffix="linkage_alarm") @CONFIG_DIAGNOSTIC_MATCH( - channel_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} + cluster_handler_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} ) class AqaraBuzzerManualMute( ZHASwitchConfigurationEntity, id_suffix="buzzer_manual_mute" @@ -570,7 +585,7 @@ class AqaraBuzzerManualMute( @CONFIG_DIAGNOSTIC_MATCH( - channel_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} + cluster_handler_names="opple_cluster", models={"lumi.sensor_smoke.acn03"} ) class AqaraBuzzerManualAlarm( ZHASwitchConfigurationEntity, id_suffix="buzzer_manual_alarm" diff --git a/homeassistant/components/zha/websocket_api.py b/homeassistant/components/zha/websocket_api.py index d2da6af0126..322107a074e 100644 --- a/homeassistant/components/zha/websocket_api.py +++ b/homeassistant/components/zha/websocket_api.py @@ -40,10 +40,10 @@ from .core.const import ( ATTR_WARNING_DEVICE_STROBE_DUTY_CYCLE, ATTR_WARNING_DEVICE_STROBE_INTENSITY, BINDINGS, - CHANNEL_IAS_WD, CLUSTER_COMMAND_SERVER, CLUSTER_COMMANDS_CLIENT, CLUSTER_COMMANDS_SERVER, + CLUSTER_HANDLER_IAS_WD, CLUSTER_TYPE_IN, CLUSTER_TYPE_OUT, CUSTOM_CONFIGURATION, @@ -61,7 +61,7 @@ from .core.const import ( WARNING_DEVICE_STROBE_HIGH, WARNING_DEVICE_STROBE_YES, ZHA_ALARM_OPTIONS, - ZHA_CHANNEL_MSG, + ZHA_CLUSTER_HANDLER_MSG, ZHA_CONFIG_SCHEMAS, ) from .core.gateway import EntityReference @@ -389,7 +389,7 @@ async def websocket_get_groupable_devices( ), } for entity_ref in entity_refs - if list(entity_ref.cluster_channels.values())[ + if list(entity_ref.cluster_handlers.values())[ 0 ].cluster.endpoint.endpoint_id == ep_id @@ -597,7 +597,7 @@ async def websocket_reconfigure_node( connection.send_message(websocket_api.event_message(msg["id"], data)) remove_dispatcher_function = async_dispatcher_connect( - hass, ZHA_CHANNEL_MSG, forward_messages + hass, ZHA_CLUSTER_HANDLER_MSG, forward_messages ) @callback @@ -1406,14 +1406,14 @@ def async_load_api(hass: HomeAssistant) -> None: schema=SERVICE_SCHEMAS[SERVICE_ISSUE_ZIGBEE_GROUP_COMMAND], ) - def _get_ias_wd_channel(zha_device): - """Get the IASWD channel for a device.""" - cluster_channels = { + def _get_ias_wd_cluster_handler(zha_device): + """Get the IASWD cluster handler for a device.""" + cluster_handlers = { ch.name: ch - for pool in zha_device.channels.pools - for ch in pool.claimed_channels.values() + for endpoint in zha_device.endpoints.values() + for ch in endpoint.claimed_cluster_handlers.values() } - return cluster_channels.get(CHANNEL_IAS_WD) + return cluster_handlers.get(CLUSTER_HANDLER_IAS_WD) async def warning_device_squawk(service: ServiceCall) -> None: """Issue the squawk command for an IAS warning device.""" @@ -1423,11 +1423,11 @@ def async_load_api(hass: HomeAssistant) -> None: level: int = service.data[ATTR_LEVEL] if (zha_device := zha_gateway.get_device(ieee)) is not None: - if channel := _get_ias_wd_channel(zha_device): - await channel.issue_squawk(mode, strobe, level) + if cluster_handler := _get_ias_wd_cluster_handler(zha_device): + await cluster_handler.issue_squawk(mode, strobe, level) else: _LOGGER.error( - "Squawking IASWD: %s: [%s] is missing the required IASWD channel!", + "Squawking IASWD: %s: [%s] is missing the required IASWD cluster handler!", ATTR_IEEE, str(ieee), ) @@ -1466,13 +1466,13 @@ def async_load_api(hass: HomeAssistant) -> None: intensity: int = service.data[ATTR_WARNING_DEVICE_STROBE_INTENSITY] if (zha_device := zha_gateway.get_device(ieee)) is not None: - if channel := _get_ias_wd_channel(zha_device): - await channel.issue_start_warning( + if cluster_handler := _get_ias_wd_cluster_handler(zha_device): + await cluster_handler.issue_start_warning( mode, strobe, level, duration, duty_mode, intensity ) else: _LOGGER.error( - "Warning IASWD: %s: [%s] is missing the required IASWD channel!", + "Warning IASWD: %s: [%s] is missing the required IASWD cluster handler!", ATTR_IEEE, str(ieee), ) diff --git a/tests/components/zha/conftest.py b/tests/components/zha/conftest.py index 784e6bae731..a39b7adc9ed 100644 --- a/tests/components/zha/conftest.py +++ b/tests/components/zha/conftest.py @@ -121,19 +121,19 @@ def setup_zha(hass, config_entry, zigpy_app_controller): @pytest.fixture -def channel(): - """Channel mock factory fixture.""" +def cluster_handler(): + """ClusterHandler mock factory fixture.""" - def channel(name: str, cluster_id: int, endpoint_id: int = 1): + def cluster_handler(name: str, cluster_id: int, endpoint_id: int = 1): ch = MagicMock() ch.name = name - ch.generic_id = f"channel_0x{cluster_id:04x}" + ch.generic_id = f"cluster_handler_0x{cluster_id:04x}" ch.id = f"{endpoint_id}:0x{cluster_id:04x}" ch.async_configure = AsyncMock() ch.async_initialize = AsyncMock() return ch - return channel + return cluster_handler @pytest.fixture @@ -162,7 +162,7 @@ def zigpy_device_mock(zigpy_app_controller): for epid, ep in endpoints.items(): endpoint = device.add_endpoint(epid) endpoint.device_type = ep[SIG_EP_TYPE] - endpoint.profile_id = ep.get(SIG_EP_PROFILE) + endpoint.profile_id = ep.get(SIG_EP_PROFILE, 0x0104) endpoint.request = AsyncMock(return_value=[0]) for cluster_id in ep.get(SIG_EP_INPUT, []): @@ -171,6 +171,8 @@ def zigpy_device_mock(zigpy_app_controller): for cluster_id in ep.get(SIG_EP_OUTPUT, []): endpoint.add_output_cluster(cluster_id) + device.status = zigpy.device.Status.ENDPOINTS_INIT + if quirk: device = quirk(zigpy_app_controller, device.ieee, device.nwk, device) diff --git a/tests/components/zha/test_base.py b/tests/components/zha/test_base.py index fbb25f1cbd3..e9c5a0a8e9c 100644 --- a/tests/components/zha/test_base.py +++ b/tests/components/zha/test_base.py @@ -1,9 +1,9 @@ -"""Test ZHA base channel module.""" +"""Test ZHA base cluster handlers module.""" -from homeassistant.components.zha.core.channels.base import parse_and_log_command +from homeassistant.components.zha.core.cluster_handlers import parse_and_log_command -from tests.components.zha.test_channels import ( # noqa: F401 - channel_pool, +from tests.components.zha.test_cluster_handlers import ( # noqa: F401 + endpoint, poll_control_ch, zigpy_coordinator_device, ) diff --git a/tests/components/zha/test_channels.py b/tests/components/zha/test_cluster_handlers.py similarity index 63% rename from tests/components/zha/test_channels.py rename to tests/components/zha/test_cluster_handlers.py index b8542433e7c..7c4903fc7f0 100644 --- a/tests/components/zha/test_channels.py +++ b/tests/components/zha/test_cluster_handlers.py @@ -1,4 +1,4 @@ -"""Test ZHA Core channels.""" +"""Test ZHA Core cluster handlers.""" import asyncio import math from unittest import mock @@ -6,15 +6,17 @@ from unittest.mock import AsyncMock, patch import pytest import zigpy.endpoint +from zigpy.endpoint import Endpoint as ZigpyEndpoint import zigpy.profiles.zha import zigpy.types as t from zigpy.zcl import foundation import zigpy.zcl.clusters import zigpy.zdo.types as zdo_t -import homeassistant.components.zha.core.channels as zha_channels -import homeassistant.components.zha.core.channels.base as base_channels +import homeassistant.components.zha.core.cluster_handlers as cluster_handlers import homeassistant.components.zha.core.const as zha_const +from homeassistant.components.zha.core.device import ZHADevice as Device +from homeassistant.components.zha.core.endpoint import Endpoint import homeassistant.components.zha.core.registries as registries from homeassistant.core import HomeAssistant @@ -65,20 +67,22 @@ def zigpy_coordinator_device(zigpy_device_mock): @pytest.fixture -def channel_pool(zigpy_coordinator_device): - """Endpoint Channels fixture.""" - ch_pool_mock = mock.MagicMock(spec_set=zha_channels.ChannelPool) - ch_pool_mock.endpoint.device.application.get_device.return_value = ( +def endpoint(zigpy_coordinator_device): + """Endpoint fixture.""" + endpoint_mock = mock.MagicMock(spec_set=Endpoint) + endpoint_mock.zigpy_endpoint.device.application.get_device.return_value = ( zigpy_coordinator_device ) - type(ch_pool_mock).skip_configuration = mock.PropertyMock(return_value=False) - ch_pool_mock.id = 1 - return ch_pool_mock + type(endpoint_mock.device).skip_configuration = mock.PropertyMock( + return_value=False + ) + endpoint_mock.id = 1 + return endpoint_mock @pytest.fixture -def poll_control_ch(channel_pool, zigpy_device_mock): - """Poll control channel fixture.""" +def poll_control_ch(endpoint, zigpy_device_mock): + """Poll control cluster handler fixture.""" cluster_id = zigpy.zcl.clusters.general.PollControl.cluster_id zigpy_dev = zigpy_device_mock( {1: {SIG_EP_INPUT: [cluster_id], SIG_EP_OUTPUT: [], SIG_EP_TYPE: 0x1234}}, @@ -88,8 +92,8 @@ def poll_control_ch(channel_pool, zigpy_device_mock): ) cluster = zigpy_dev.endpoints[1].in_clusters[cluster_id] - channel_class = registries.ZIGBEE_CHANNEL_REGISTRY.get(cluster_id) - return channel_class(cluster, channel_pool) + cluster_handler_class = registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.get(cluster_id) + return cluster_handler_class(cluster, endpoint) @pytest.fixture @@ -236,10 +240,10 @@ async def poll_control_device(zha_device_restored, zigpy_device_mock): ), ], ) -async def test_in_channel_config( - cluster_id, bind_count, attrs, channel_pool, zigpy_device_mock, zha_gateway +async def test_in_cluster_handler_config( + cluster_id, bind_count, attrs, endpoint, zigpy_device_mock, zha_gateway ) -> None: - """Test ZHA core channel configuration for input clusters.""" + """Test ZHA core cluster handler configuration for input clusters.""" zigpy_dev = zigpy_device_mock( {1: {SIG_EP_INPUT: [cluster_id], SIG_EP_OUTPUT: [], SIG_EP_TYPE: 0x1234}}, "00:11:22:33:44:55:66:77", @@ -248,12 +252,12 @@ async def test_in_channel_config( ) cluster = zigpy_dev.endpoints[1].in_clusters[cluster_id] - channel_class = registries.ZIGBEE_CHANNEL_REGISTRY.get( - cluster_id, base_channels.ZigbeeChannel + cluster_handler_class = registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.get( + cluster_id, cluster_handlers.ClusterHandler ) - channel = channel_class(cluster, channel_pool) + cluster_handler = cluster_handler_class(cluster, endpoint) - await channel.async_configure() + await cluster_handler.async_configure() assert cluster.bind.call_count == bind_count assert cluster.configure_reporting.call_count == 0 @@ -299,10 +303,10 @@ async def test_in_channel_config( (0x0B04, 1), ], ) -async def test_out_channel_config( - cluster_id, bind_count, channel_pool, zigpy_device_mock, zha_gateway +async def test_out_cluster_handler_config( + cluster_id, bind_count, endpoint, zigpy_device_mock, zha_gateway ) -> None: - """Test ZHA core channel configuration for output clusters.""" + """Test ZHA core cluster handler configuration for output clusters.""" zigpy_dev = zigpy_device_mock( {1: {SIG_EP_OUTPUT: [cluster_id], SIG_EP_INPUT: [], SIG_EP_TYPE: 0x1234}}, "00:11:22:33:44:55:66:77", @@ -312,102 +316,109 @@ async def test_out_channel_config( cluster = zigpy_dev.endpoints[1].out_clusters[cluster_id] cluster.bind_only = True - channel_class = registries.ZIGBEE_CHANNEL_REGISTRY.get( - cluster_id, base_channels.ZigbeeChannel + cluster_handler_class = registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.get( + cluster_id, cluster_handlers.ClusterHandler ) - channel = channel_class(cluster, channel_pool) + cluster_handler = cluster_handler_class(cluster, endpoint) - await channel.async_configure() + await cluster_handler.async_configure() assert cluster.bind.call_count == bind_count assert cluster.configure_reporting.call_count == 0 -def test_channel_registry() -> None: - """Test ZIGBEE Channel Registry.""" - for cluster_id, channel in registries.ZIGBEE_CHANNEL_REGISTRY.items(): +def test_cluster_handler_registry() -> None: + """Test ZIGBEE cluster handler Registry.""" + for ( + cluster_id, + cluster_handler, + ) in registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.items(): assert isinstance(cluster_id, int) assert 0 <= cluster_id <= 0xFFFF - assert issubclass(channel, base_channels.ZigbeeChannel) + assert issubclass(cluster_handler, cluster_handlers.ClusterHandler) -def test_epch_unclaimed_channels(channel) -> None: - """Test unclaimed channels.""" +def test_epch_unclaimed_cluster_handlers(cluster_handler) -> None: + """Test unclaimed cluster handlers.""" - ch_1 = channel(zha_const.CHANNEL_ON_OFF, 6) - ch_2 = channel(zha_const.CHANNEL_LEVEL, 8) - ch_3 = channel(zha_const.CHANNEL_COLOR, 768) + ch_1 = cluster_handler(zha_const.CLUSTER_HANDLER_ON_OFF, 6) + ch_2 = cluster_handler(zha_const.CLUSTER_HANDLER_LEVEL, 8) + ch_3 = cluster_handler(zha_const.CLUSTER_HANDLER_COLOR, 768) - ep_channels = zha_channels.ChannelPool( - mock.MagicMock(spec_set=zha_channels.Channels), mock.sentinel.ep + ep_cluster_handlers = Endpoint( + mock.MagicMock(spec_set=ZigpyEndpoint), mock.MagicMock(spec_set=Device) ) - all_channels = {ch_1.id: ch_1, ch_2.id: ch_2, ch_3.id: ch_3} - with mock.patch.dict(ep_channels.all_channels, all_channels, clear=True): - available = ep_channels.unclaimed_channels() + all_cluster_handlers = {ch_1.id: ch_1, ch_2.id: ch_2, ch_3.id: ch_3} + with mock.patch.dict( + ep_cluster_handlers.all_cluster_handlers, all_cluster_handlers, clear=True + ): + available = ep_cluster_handlers.unclaimed_cluster_handlers() assert ch_1 in available assert ch_2 in available assert ch_3 in available - ep_channels.claimed_channels[ch_2.id] = ch_2 - available = ep_channels.unclaimed_channels() + ep_cluster_handlers.claimed_cluster_handlers[ch_2.id] = ch_2 + available = ep_cluster_handlers.unclaimed_cluster_handlers() assert ch_1 in available assert ch_2 not in available assert ch_3 in available - ep_channels.claimed_channels[ch_1.id] = ch_1 - available = ep_channels.unclaimed_channels() + ep_cluster_handlers.claimed_cluster_handlers[ch_1.id] = ch_1 + available = ep_cluster_handlers.unclaimed_cluster_handlers() assert ch_1 not in available assert ch_2 not in available assert ch_3 in available - ep_channels.claimed_channels[ch_3.id] = ch_3 - available = ep_channels.unclaimed_channels() + ep_cluster_handlers.claimed_cluster_handlers[ch_3.id] = ch_3 + available = ep_cluster_handlers.unclaimed_cluster_handlers() assert ch_1 not in available assert ch_2 not in available assert ch_3 not in available -def test_epch_claim_channels(channel) -> None: - """Test channel claiming.""" +def test_epch_claim_cluster_handlers(cluster_handler) -> None: + """Test cluster handler claiming.""" - ch_1 = channel(zha_const.CHANNEL_ON_OFF, 6) - ch_2 = channel(zha_const.CHANNEL_LEVEL, 8) - ch_3 = channel(zha_const.CHANNEL_COLOR, 768) + ch_1 = cluster_handler(zha_const.CLUSTER_HANDLER_ON_OFF, 6) + ch_2 = cluster_handler(zha_const.CLUSTER_HANDLER_LEVEL, 8) + ch_3 = cluster_handler(zha_const.CLUSTER_HANDLER_COLOR, 768) - ep_channels = zha_channels.ChannelPool( - mock.MagicMock(spec_set=zha_channels.Channels), mock.sentinel.ep + ep_cluster_handlers = Endpoint( + mock.MagicMock(spec_set=ZigpyEndpoint), mock.MagicMock(spec_set=Device) ) - all_channels = {ch_1.id: ch_1, ch_2.id: ch_2, ch_3.id: ch_3} - with mock.patch.dict(ep_channels.all_channels, all_channels, clear=True): - assert ch_1.id not in ep_channels.claimed_channels - assert ch_2.id not in ep_channels.claimed_channels - assert ch_3.id not in ep_channels.claimed_channels + all_cluster_handlers = {ch_1.id: ch_1, ch_2.id: ch_2, ch_3.id: ch_3} + with mock.patch.dict( + ep_cluster_handlers.all_cluster_handlers, all_cluster_handlers, clear=True + ): + assert ch_1.id not in ep_cluster_handlers.claimed_cluster_handlers + assert ch_2.id not in ep_cluster_handlers.claimed_cluster_handlers + assert ch_3.id not in ep_cluster_handlers.claimed_cluster_handlers - ep_channels.claim_channels([ch_2]) - assert ch_1.id not in ep_channels.claimed_channels - assert ch_2.id in ep_channels.claimed_channels - assert ep_channels.claimed_channels[ch_2.id] is ch_2 - assert ch_3.id not in ep_channels.claimed_channels + ep_cluster_handlers.claim_cluster_handlers([ch_2]) + assert ch_1.id not in ep_cluster_handlers.claimed_cluster_handlers + assert ch_2.id in ep_cluster_handlers.claimed_cluster_handlers + assert ep_cluster_handlers.claimed_cluster_handlers[ch_2.id] is ch_2 + assert ch_3.id not in ep_cluster_handlers.claimed_cluster_handlers - ep_channels.claim_channels([ch_3, ch_1]) - assert ch_1.id in ep_channels.claimed_channels - assert ep_channels.claimed_channels[ch_1.id] is ch_1 - assert ch_2.id in ep_channels.claimed_channels - assert ep_channels.claimed_channels[ch_2.id] is ch_2 - assert ch_3.id in ep_channels.claimed_channels - assert ep_channels.claimed_channels[ch_3.id] is ch_3 - assert "1:0x0300" in ep_channels.claimed_channels + ep_cluster_handlers.claim_cluster_handlers([ch_3, ch_1]) + assert ch_1.id in ep_cluster_handlers.claimed_cluster_handlers + assert ep_cluster_handlers.claimed_cluster_handlers[ch_1.id] is ch_1 + assert ch_2.id in ep_cluster_handlers.claimed_cluster_handlers + assert ep_cluster_handlers.claimed_cluster_handlers[ch_2.id] is ch_2 + assert ch_3.id in ep_cluster_handlers.claimed_cluster_handlers + assert ep_cluster_handlers.claimed_cluster_handlers[ch_3.id] is ch_3 + assert "1:0x0300" in ep_cluster_handlers.claimed_cluster_handlers @mock.patch( - "homeassistant.components.zha.core.channels.ChannelPool.add_client_channels" + "homeassistant.components.zha.core.endpoint.Endpoint.add_client_cluster_handlers" ) @mock.patch( "homeassistant.components.zha.core.discovery.PROBE.discover_entities", mock.MagicMock(), ) -def test_ep_channels_all_channels(m1, zha_device_mock) -> None: - """Test EndpointChannels adding all channels.""" +def test_ep_all_cluster_handlers(m1, zha_device_mock) -> None: + """Test Endpoint adding all cluster handlers.""" zha_device = zha_device_mock( { 1: { @@ -422,43 +433,37 @@ def test_ep_channels_all_channels(m1, zha_device_mock) -> None: }, } ) - channels = zha_channels.Channels(zha_device) - - ep_channels = zha_channels.ChannelPool.new(channels, 1) - assert "1:0x0000" in ep_channels.all_channels - assert "1:0x0001" in ep_channels.all_channels - assert "1:0x0006" in ep_channels.all_channels - assert "1:0x0008" in ep_channels.all_channels - assert "1:0x0300" not in ep_channels.all_channels - assert "2:0x0000" not in ep_channels.all_channels - assert "2:0x0001" not in ep_channels.all_channels - assert "2:0x0006" not in ep_channels.all_channels - assert "2:0x0008" not in ep_channels.all_channels - assert "2:0x0300" not in ep_channels.all_channels - - channels = zha_channels.Channels(zha_device) - ep_channels = zha_channels.ChannelPool.new(channels, 2) - assert "1:0x0000" not in ep_channels.all_channels - assert "1:0x0001" not in ep_channels.all_channels - assert "1:0x0006" not in ep_channels.all_channels - assert "1:0x0008" not in ep_channels.all_channels - assert "1:0x0300" not in ep_channels.all_channels - assert "2:0x0000" in ep_channels.all_channels - assert "2:0x0001" in ep_channels.all_channels - assert "2:0x0006" in ep_channels.all_channels - assert "2:0x0008" in ep_channels.all_channels - assert "2:0x0300" in ep_channels.all_channels + assert "1:0x0000" in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0001" in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0006" in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0008" in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0300" not in zha_device._endpoints[1].all_cluster_handlers + assert "2:0x0000" not in zha_device._endpoints[1].all_cluster_handlers + assert "2:0x0001" not in zha_device._endpoints[1].all_cluster_handlers + assert "2:0x0006" not in zha_device._endpoints[1].all_cluster_handlers + assert "2:0x0008" not in zha_device._endpoints[1].all_cluster_handlers + assert "2:0x0300" not in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0000" not in zha_device._endpoints[2].all_cluster_handlers + assert "1:0x0001" not in zha_device._endpoints[2].all_cluster_handlers + assert "1:0x0006" not in zha_device._endpoints[2].all_cluster_handlers + assert "1:0x0008" not in zha_device._endpoints[2].all_cluster_handlers + assert "1:0x0300" not in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0000" in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0001" in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0006" in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0008" in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0300" in zha_device._endpoints[2].all_cluster_handlers @mock.patch( - "homeassistant.components.zha.core.channels.ChannelPool.add_client_channels" + "homeassistant.components.zha.core.endpoint.Endpoint.add_client_cluster_handlers" ) @mock.patch( "homeassistant.components.zha.core.discovery.PROBE.discover_entities", mock.MagicMock(), ) -def test_channel_power_config(m1, zha_device_mock) -> None: - """Test that channels only get a single power channel.""" +def test_cluster_handler_power_config(m1, zha_device_mock) -> None: + """Test that cluster handlers only get a single power cluster handler.""" in_clusters = [0, 1, 6, 8] zha_device = zha_device_mock( { @@ -470,18 +475,16 @@ def test_channel_power_config(m1, zha_device_mock) -> None: }, } ) - channels = zha_channels.Channels.new(zha_device) - pools = {pool.id: pool for pool in channels.pools} - assert "1:0x0000" in pools[1].all_channels - assert "1:0x0001" in pools[1].all_channels - assert "1:0x0006" in pools[1].all_channels - assert "1:0x0008" in pools[1].all_channels - assert "1:0x0300" not in pools[1].all_channels - assert "2:0x0000" in pools[2].all_channels - assert "2:0x0001" not in pools[2].all_channels - assert "2:0x0006" in pools[2].all_channels - assert "2:0x0008" in pools[2].all_channels - assert "2:0x0300" in pools[2].all_channels + assert "1:0x0000" in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0001" in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0006" in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0008" in zha_device._endpoints[1].all_cluster_handlers + assert "1:0x0300" not in zha_device._endpoints[1].all_cluster_handlers + assert "2:0x0000" in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0001" in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0006" in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0008" in zha_device._endpoints[2].all_cluster_handlers + assert "2:0x0300" in zha_device._endpoints[2].all_cluster_handlers zha_device = zha_device_mock( { @@ -489,46 +492,43 @@ def test_channel_power_config(m1, zha_device_mock) -> None: 2: {SIG_EP_INPUT: in_clusters, SIG_EP_OUTPUT: [], SIG_EP_TYPE: 0x0000}, } ) - channels = zha_channels.Channels.new(zha_device) - pools = {pool.id: pool for pool in channels.pools} - assert "1:0x0001" not in pools[1].all_channels - assert "2:0x0001" in pools[2].all_channels + assert "1:0x0001" not in zha_device._endpoints[1].all_cluster_handlers + assert "2:0x0001" in zha_device._endpoints[2].all_cluster_handlers zha_device = zha_device_mock( {2: {SIG_EP_INPUT: in_clusters, SIG_EP_OUTPUT: [], SIG_EP_TYPE: 0x0000}} ) - channels = zha_channels.Channels.new(zha_device) - pools = {pool.id: pool for pool in channels.pools} - assert "2:0x0001" in pools[2].all_channels + assert "2:0x0001" in zha_device._endpoints[2].all_cluster_handlers -async def test_ep_channels_configure(channel) -> None: - """Test unclaimed channels.""" +async def test_ep_cluster_handlers_configure(cluster_handler) -> None: + """Test unclaimed cluster handlers.""" - ch_1 = channel(zha_const.CHANNEL_ON_OFF, 6) - ch_2 = channel(zha_const.CHANNEL_LEVEL, 8) - ch_3 = channel(zha_const.CHANNEL_COLOR, 768) + ch_1 = cluster_handler(zha_const.CLUSTER_HANDLER_ON_OFF, 6) + ch_2 = cluster_handler(zha_const.CLUSTER_HANDLER_LEVEL, 8) + ch_3 = cluster_handler(zha_const.CLUSTER_HANDLER_COLOR, 768) ch_3.async_configure = AsyncMock(side_effect=asyncio.TimeoutError) ch_3.async_initialize = AsyncMock(side_effect=asyncio.TimeoutError) - ch_4 = channel(zha_const.CHANNEL_ON_OFF, 6) - ch_5 = channel(zha_const.CHANNEL_LEVEL, 8) + ch_4 = cluster_handler(zha_const.CLUSTER_HANDLER_ON_OFF, 6) + ch_5 = cluster_handler(zha_const.CLUSTER_HANDLER_LEVEL, 8) ch_5.async_configure = AsyncMock(side_effect=asyncio.TimeoutError) ch_5.async_initialize = AsyncMock(side_effect=asyncio.TimeoutError) - channels = mock.MagicMock(spec_set=zha_channels.Channels) - type(channels).semaphore = mock.PropertyMock(return_value=asyncio.Semaphore(3)) - ep_channels = zha_channels.ChannelPool(channels, mock.sentinel.ep) + endpoint_mock = mock.MagicMock(spec_set=ZigpyEndpoint) + type(endpoint_mock).in_clusters = mock.PropertyMock(return_value={}) + type(endpoint_mock).out_clusters = mock.PropertyMock(return_value={}) + endpoint = Endpoint.new(endpoint_mock, mock.MagicMock(spec_set=Device)) claimed = {ch_1.id: ch_1, ch_2.id: ch_2, ch_3.id: ch_3} - client_chans = {ch_4.id: ch_4, ch_5.id: ch_5} + client_handlers = {ch_4.id: ch_4, ch_5.id: ch_5} with mock.patch.dict( - ep_channels.claimed_channels, claimed, clear=True - ), mock.patch.dict(ep_channels.client_channels, client_chans, clear=True): - await ep_channels.async_configure() - await ep_channels.async_initialize(mock.sentinel.from_cache) + endpoint.claimed_cluster_handlers, claimed, clear=True + ), mock.patch.dict(endpoint.client_cluster_handlers, client_handlers, clear=True): + await endpoint.async_configure() + await endpoint.async_initialize(mock.sentinel.from_cache) - for ch in [*claimed.values(), *client_chans.values()]: + for ch in [*claimed.values(), *client_handlers.values()]: assert ch.async_initialize.call_count == 1 assert ch.async_initialize.await_count == 1 assert ch.async_initialize.call_args[0][0] is mock.sentinel.from_cache @@ -540,7 +540,7 @@ async def test_ep_channels_configure(channel) -> None: async def test_poll_control_configure(poll_control_ch) -> None: - """Test poll control channel configuration.""" + """Test poll control cluster handler configuration.""" await poll_control_ch.async_configure() assert poll_control_ch.cluster.write_attributes.call_count == 1 assert poll_control_ch.cluster.write_attributes.call_args[0][0] == { @@ -549,7 +549,7 @@ async def test_poll_control_configure(poll_control_ch) -> None: async def test_poll_control_checkin_response(poll_control_ch) -> None: - """Test poll control channel checkin response.""" + """Test poll control cluster handler checkin response.""" rsp_mock = AsyncMock() set_interval_mock = AsyncMock() fast_poll_mock = AsyncMock() @@ -576,9 +576,9 @@ async def test_poll_control_checkin_response(poll_control_ch) -> None: async def test_poll_control_cluster_command( hass: HomeAssistant, poll_control_device ) -> None: - """Test poll control channel response to cluster command.""" + """Test poll control cluster handler response to cluster command.""" checkin_mock = AsyncMock() - poll_control_ch = poll_control_device.channels.pools[0].all_channels["1:0x0020"] + poll_control_ch = poll_control_device._endpoints[1].all_cluster_handlers["1:0x0020"] cluster = poll_control_ch.cluster events = async_capture_events(hass, zha_const.ZHA_EVENT) @@ -607,9 +607,9 @@ async def test_poll_control_cluster_command( async def test_poll_control_ignore_list( hass: HomeAssistant, poll_control_device ) -> None: - """Test poll control channel ignore list.""" + """Test poll control cluster handler ignore list.""" set_long_poll_mock = AsyncMock() - poll_control_ch = poll_control_device.channels.pools[0].all_channels["1:0x0020"] + poll_control_ch = poll_control_device._endpoints[1].all_cluster_handlers["1:0x0020"] cluster = poll_control_ch.cluster with mock.patch.object(cluster, "set_long_poll_interval", set_long_poll_mock): @@ -626,9 +626,9 @@ async def test_poll_control_ignore_list( async def test_poll_control_ikea(hass: HomeAssistant, poll_control_device) -> None: - """Test poll control channel ignore list for ikea.""" + """Test poll control cluster handler ignore list for ikea.""" set_long_poll_mock = AsyncMock() - poll_control_ch = poll_control_device.channels.pools[0].all_channels["1:0x0020"] + poll_control_ch = poll_control_device._endpoints[1].all_cluster_handlers["1:0x0020"] cluster = poll_control_ch.cluster poll_control_device.device.node_desc.manufacturer_code = 4476 @@ -651,12 +651,12 @@ def zigpy_zll_device(zigpy_device_mock): async def test_zll_device_groups( - zigpy_zll_device, channel_pool, zigpy_coordinator_device + zigpy_zll_device, endpoint, zigpy_coordinator_device ) -> None: """Test adding coordinator to ZLL groups.""" cluster = zigpy_zll_device.endpoints[1].lightlink - channel = zha_channels.lightlink.LightLink(cluster, channel_pool) + cluster_handler = cluster_handlers.lightlink.LightLink(cluster, endpoint) get_group_identifiers_rsp = zigpy.zcl.clusters.lightlink.LightLink.commands_by_name[ "get_group_identifiers_rsp" @@ -671,7 +671,7 @@ async def test_zll_device_groups( ) ), ) as cmd_mock: - await channel.async_configure() + await cluster_handler.async_configure() assert cmd_mock.await_count == 1 assert ( cluster.server_commands[cmd_mock.await_args[0][0]].name @@ -693,7 +693,7 @@ async def test_zll_device_groups( ) ), ) as cmd_mock: - await channel.async_configure() + await cluster_handler.async_configure() assert cmd_mock.await_count == 1 assert ( cluster.server_commands[cmd_mock.await_args[0][0]].name @@ -711,37 +711,34 @@ async def test_zll_device_groups( ) -@mock.patch( - "homeassistant.components.zha.core.channels.ChannelPool.add_client_channels" -) @mock.patch( "homeassistant.components.zha.core.discovery.PROBE.discover_entities", mock.MagicMock(), ) -async def test_cluster_no_ep_attribute(m1, zha_device_mock) -> None: - """Test channels for clusters without ep_attribute.""" +async def test_cluster_no_ep_attribute(zha_device_mock) -> None: + """Test cluster handlers for clusters without ep_attribute.""" zha_device = zha_device_mock( {1: {SIG_EP_INPUT: [0x042E], SIG_EP_OUTPUT: [], SIG_EP_TYPE: 0x1234}}, ) - channels = zha_channels.Channels.new(zha_device) - pools = {pool.id: pool for pool in channels.pools} - assert "1:0x042e" in pools[1].all_channels - assert pools[1].all_channels["1:0x042e"].name + assert "1:0x042e" in zha_device._endpoints[1].all_cluster_handlers + assert zha_device._endpoints[1].all_cluster_handlers["1:0x042e"].name -async def test_configure_reporting(hass: HomeAssistant) -> None: - """Test setting up a channel and configuring attribute reporting in two batches.""" +async def test_configure_reporting(hass: HomeAssistant, endpoint) -> None: + """Test setting up a cluster handler and configuring attribute reporting in two batches.""" - class TestZigbeeChannel(base_channels.ZigbeeChannel): + class TestZigbeeClusterHandler(cluster_handlers.ClusterHandler): BIND = True REPORT_CONFIG = ( # By name - base_channels.AttrReportConfig(attr="current_x", config=(1, 60, 1)), - base_channels.AttrReportConfig(attr="current_hue", config=(1, 60, 2)), - base_channels.AttrReportConfig(attr="color_temperature", config=(1, 60, 3)), - base_channels.AttrReportConfig(attr="current_y", config=(1, 60, 4)), + cluster_handlers.AttrReportConfig(attr="current_x", config=(1, 60, 1)), + cluster_handlers.AttrReportConfig(attr="current_hue", config=(1, 60, 2)), + cluster_handlers.AttrReportConfig( + attr="color_temperature", config=(1, 60, 3) + ), + cluster_handlers.AttrReportConfig(attr="current_y", config=(1, 60, 4)), ) mock_ep = mock.AsyncMock(spec_set=zigpy.endpoint.Endpoint) @@ -761,11 +758,8 @@ async def test_configure_reporting(hass: HomeAssistant) -> None: ], ) - ch_pool = mock.AsyncMock(spec_set=zha_channels.ChannelPool) - ch_pool.skip_configuration = False - - channel = TestZigbeeChannel(cluster, ch_pool) - await channel.async_configure() + cluster_handler = TestZigbeeClusterHandler(cluster, endpoint) + await cluster_handler.async_configure() # Since we request reporting for five attributes, we need to make two calls (3 + 1) assert cluster.configure_reporting_multiple.mock_calls == [ diff --git a/tests/components/zha/test_device.py b/tests/components/zha/test_device.py index bbf69ab2cdb..411d7081577 100644 --- a/tests/components/zha/test_device.py +++ b/tests/components/zha/test_device.py @@ -46,9 +46,9 @@ def required_platforms_only(): def zigpy_device(zigpy_device_mock): """Device tracker zigpy device.""" - def _dev(with_basic_channel: bool = True, **kwargs): + def _dev(with_basic_cluster_handler: bool = True, **kwargs): in_clusters = [general.OnOff.cluster_id] - if with_basic_channel: + if with_basic_cluster_handler: in_clusters.append(general.Basic.cluster_id) endpoints = { @@ -67,9 +67,9 @@ def zigpy_device(zigpy_device_mock): def zigpy_device_mains(zigpy_device_mock): """Device tracker zigpy device.""" - def _dev(with_basic_channel: bool = True): + def _dev(with_basic_cluster_handler: bool = True): in_clusters = [general.OnOff.cluster_id] - if with_basic_channel: + if with_basic_cluster_handler: in_clusters.append(general.Basic.cluster_id) endpoints = { @@ -87,15 +87,15 @@ def zigpy_device_mains(zigpy_device_mock): @pytest.fixture -def device_with_basic_channel(zigpy_device_mains): - """Return a ZHA device with a basic channel present.""" - return zigpy_device_mains(with_basic_channel=True) +def device_with_basic_cluster_handler(zigpy_device_mains): + """Return a ZHA device with a basic cluster handler present.""" + return zigpy_device_mains(with_basic_cluster_handler=True) @pytest.fixture -def device_without_basic_channel(zigpy_device): - """Return a ZHA device with a basic channel present.""" - return zigpy_device(with_basic_channel=False) +def device_without_basic_cluster_handler(zigpy_device): + """Return a ZHA device without a basic cluster handler present.""" + return zigpy_device(with_basic_cluster_handler=False) @pytest.fixture @@ -125,32 +125,32 @@ def _send_time_changed(hass, seconds): @patch( - "homeassistant.components.zha.core.channels.general.BasicChannel.async_initialize", + "homeassistant.components.zha.core.cluster_handlers.general.BasicClusterHandler.async_initialize", new=mock.AsyncMock(), ) async def test_check_available_success( - hass: HomeAssistant, device_with_basic_channel, zha_device_restored + hass: HomeAssistant, device_with_basic_cluster_handler, zha_device_restored ) -> None: """Check device availability success on 1st try.""" - zha_device = await zha_device_restored(device_with_basic_channel) + zha_device = await zha_device_restored(device_with_basic_cluster_handler) await async_enable_traffic(hass, [zha_device]) - basic_ch = device_with_basic_channel.endpoints[3].basic + basic_ch = device_with_basic_cluster_handler.endpoints[3].basic basic_ch.read_attributes.reset_mock() - device_with_basic_channel.last_seen = None + device_with_basic_cluster_handler.last_seen = None assert zha_device.available is True _send_time_changed(hass, zha_device.consider_unavailable_time + 2) await hass.async_block_till_done() assert zha_device.available is False assert basic_ch.read_attributes.await_count == 0 - device_with_basic_channel.last_seen = ( + device_with_basic_cluster_handler.last_seen = ( time.time() - zha_device.consider_unavailable_time - 2 ) - _seens = [time.time(), device_with_basic_channel.last_seen] + _seens = [time.time(), device_with_basic_cluster_handler.last_seen] def _update_last_seen(*args, **kwargs): - device_with_basic_channel.last_seen = _seens.pop() + device_with_basic_cluster_handler.last_seen = _seens.pop() basic_ch.read_attributes.side_effect = _update_last_seen @@ -177,22 +177,22 @@ async def test_check_available_success( @patch( - "homeassistant.components.zha.core.channels.general.BasicChannel.async_initialize", + "homeassistant.components.zha.core.cluster_handlers.general.BasicClusterHandler.async_initialize", new=mock.AsyncMock(), ) async def test_check_available_unsuccessful( - hass: HomeAssistant, device_with_basic_channel, zha_device_restored + hass: HomeAssistant, device_with_basic_cluster_handler, zha_device_restored ) -> None: """Check device availability all tries fail.""" - zha_device = await zha_device_restored(device_with_basic_channel) + zha_device = await zha_device_restored(device_with_basic_cluster_handler) await async_enable_traffic(hass, [zha_device]) - basic_ch = device_with_basic_channel.endpoints[3].basic + basic_ch = device_with_basic_cluster_handler.endpoints[3].basic assert zha_device.available is True assert basic_ch.read_attributes.await_count == 0 - device_with_basic_channel.last_seen = ( + device_with_basic_cluster_handler.last_seen = ( time.time() - zha_device.consider_unavailable_time - 2 ) @@ -219,24 +219,24 @@ async def test_check_available_unsuccessful( @patch( - "homeassistant.components.zha.core.channels.general.BasicChannel.async_initialize", + "homeassistant.components.zha.core.cluster_handlers.general.BasicClusterHandler.async_initialize", new=mock.AsyncMock(), ) -async def test_check_available_no_basic_channel( +async def test_check_available_no_basic_cluster_handler( hass: HomeAssistant, - device_without_basic_channel, + device_without_basic_cluster_handler, zha_device_restored, caplog: pytest.LogCaptureFixture, ) -> None: """Check device availability for a device without basic cluster.""" caplog.set_level(logging.DEBUG, logger="homeassistant.components.zha") - zha_device = await zha_device_restored(device_without_basic_channel) + zha_device = await zha_device_restored(device_without_basic_cluster_handler) await async_enable_traffic(hass, [zha_device]) assert zha_device.available is True - device_without_basic_channel.last_seen = ( + device_without_basic_cluster_handler.last_seen = ( time.time() - zha_device.consider_unavailable_time - 2 ) @@ -248,9 +248,9 @@ async def test_check_available_no_basic_channel( async def test_ota_sw_version(hass: HomeAssistant, ota_zha_device) -> None: - """Test device entry gets sw_version updated via OTA channel.""" + """Test device entry gets sw_version updated via OTA cluster handler.""" - ota_ch = ota_zha_device.channels.pools[0].client_channels["1:0x0019"] + ota_ch = ota_zha_device._endpoints[1].client_cluster_handlers["1:0x0019"] dev_registry = dr.async_get(hass) entry = dev_registry.async_get(ota_zha_device.device_id) assert entry.sw_version is None diff --git a/tests/components/zha/test_device_action.py b/tests/components/zha/test_device_action.py index cd12651a8e5..6db138ebcde 100644 --- a/tests/components/zha/test_device_action.py +++ b/tests/components/zha/test_device_action.py @@ -302,8 +302,8 @@ async def test_action(hass: HomeAssistant, device_ias, device_inovelli) -> None: await hass.async_block_till_done() calls = async_mock_service(hass, DOMAIN, "warning_device_warn") - channel = zha_device.channels.pools[0].client_channels["1:0x0006"] - channel.zha_send_event(COMMAND_SINGLE, []) + cluster_handler = zha_device.endpoints[1].client_cluster_handlers["1:0x0006"] + cluster_handler.zha_send_event(COMMAND_SINGLE, []) await hass.async_block_till_done() assert len(calls) == 1 @@ -350,8 +350,8 @@ async def test_action(hass: HomeAssistant, device_ias, device_inovelli) -> None: async def test_invalid_zha_event_type(hass: HomeAssistant, device_ias) -> None: """Test that unexpected types are not passed to `zha_send_event`.""" zigpy_device, zha_device = device_ias - channel = zha_device.channels.pools[0].client_channels["1:0x0006"] + cluster_handler = zha_device._endpoints[1].client_cluster_handlers["1:0x0006"] # `zha_send_event` accepts only zigpy responses, lists, and dicts with pytest.raises(TypeError): - channel.zha_send_event(COMMAND_SINGLE, 123) + cluster_handler.zha_send_event(COMMAND_SINGLE, 123) diff --git a/tests/components/zha/test_device_trigger.py b/tests/components/zha/test_device_trigger.py index 531b88aee31..8c789c0fc59 100644 --- a/tests/components/zha/test_device_trigger.py +++ b/tests/components/zha/test_device_trigger.py @@ -223,8 +223,8 @@ async def test_if_fires_on_event(hass: HomeAssistant, mock_devices, calls) -> No await hass.async_block_till_done() - channel = zha_device.channels.pools[0].client_channels["1:0x0006"] - channel.zha_send_event(COMMAND_SINGLE, []) + cluster_handler = zha_device.endpoints[1].client_cluster_handlers["1:0x0006"] + cluster_handler.zha_send_event(COMMAND_SINGLE, []) await hass.async_block_till_done() assert len(calls) == 1 diff --git a/tests/components/zha/test_discover.py b/tests/components/zha/test_discover.py index 20db04d9615..c24a614d317 100644 --- a/tests/components/zha/test_discover.py +++ b/tests/components/zha/test_discover.py @@ -14,10 +14,10 @@ import zigpy.zcl.clusters.security import zigpy.zcl.foundation as zcl_f import homeassistant.components.zha.binary_sensor -import homeassistant.components.zha.core.channels as zha_channels -import homeassistant.components.zha.core.channels.base as base_channels +import homeassistant.components.zha.core.cluster_handlers as cluster_handlers import homeassistant.components.zha.core.const as zha_const import homeassistant.components.zha.core.discovery as disc +from homeassistant.components.zha.core.endpoint import Endpoint import homeassistant.components.zha.core.registries as zha_regs import homeassistant.components.zha.cover import homeassistant.components.zha.device_tracker @@ -33,11 +33,11 @@ import homeassistant.helpers.entity_registry as er from .common import get_zha_gateway from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE from .zha_devices_list import ( - DEV_SIG_CHANNELS, + DEV_SIG_CLUSTER_HANDLERS, DEV_SIG_ENT_MAP, DEV_SIG_ENT_MAP_CLASS, DEV_SIG_ENT_MAP_ID, - DEV_SIG_EVT_CHANNELS, + DEV_SIG_EVT_CLUSTER_HANDLERS, DEVICES, ) @@ -63,27 +63,6 @@ def contains_ignored_suffix(unique_id: str) -> bool: return False -@pytest.fixture -def channels_mock(zha_device_mock): - """Channels mock factory.""" - - def _mock( - endpoints, - ieee="00:11:22:33:44:55:66:77", - manufacturer="mock manufacturer", - model="mock model", - node_desc=b"\x02@\x807\x10\x7fd\x00\x00*d\x00\x00", - patch_cluster=False, - ): - zha_dev = zha_device_mock( - endpoints, ieee, manufacturer, model, node_desc, patch_cluster=patch_cluster - ) - channels = zha_channels.Channels.new(zha_dev) - return channels - - return _mock - - @patch( "zigpy.zcl.clusters.general.Identify.request", new=AsyncMock(return_value=[mock.sentinel.data, zcl_f.Status.SUCCESS]), @@ -119,14 +98,14 @@ async def test_devices( if cluster_identify: cluster_identify.request.reset_mock() - orig_new_entity = zha_channels.ChannelPool.async_new_entity + orig_new_entity = Endpoint.async_new_entity _dispatch = mock.MagicMock(wraps=orig_new_entity) try: - zha_channels.ChannelPool.async_new_entity = lambda *a, **kw: _dispatch(*a, **kw) + Endpoint.async_new_entity = lambda *a, **kw: _dispatch(*a, **kw) zha_dev = await zha_device_joined_restored(zigpy_device) await hass_disable_services.async_block_till_done() finally: - zha_channels.ChannelPool.async_new_entity = orig_new_entity + Endpoint.async_new_entity = orig_new_entity if cluster_identify: called = int(zha_device_joined_restored.name == "zha_device_joined") @@ -147,34 +126,36 @@ async def test_devices( tsn=None, ) - event_channels = { - ch.id for pool in zha_dev.channels.pools for ch in pool.client_channels.values() + event_cluster_handlers = { + ch.id + for endpoint in zha_dev._endpoints.values() + for ch in endpoint.client_cluster_handlers.values() } - assert event_channels == set(device[DEV_SIG_EVT_CHANNELS]) + assert event_cluster_handlers == set(device[DEV_SIG_EVT_CLUSTER_HANDLERS]) # we need to probe the class create entity factory so we need to reset this to get accurate results zha_regs.ZHA_ENTITIES.clean_up() - # build a dict of entity_class -> (component, unique_id, channels) tuple + # build a dict of entity_class -> (platform, unique_id, cluster_handlers) tuple ha_ent_info = {} created_entity_count = 0 for call in _dispatch.call_args_list: - _, component, entity_cls, unique_id, channels = call[0] + _, platform, entity_cls, unique_id, cluster_handlers = call[0] # the factory can return None. We filter these out to get an accurate created entity count - response = entity_cls.create_entity(unique_id, zha_dev, channels) + response = entity_cls.create_entity(unique_id, zha_dev, cluster_handlers) if response and not contains_ignored_suffix(response.name): created_entity_count += 1 unique_id_head = UNIQUE_ID_HD.match(unique_id).group( 0 ) # ieee + endpoint_id ha_ent_info[(unique_id_head, entity_cls.__name__)] = ( - component, + platform, unique_id, - channels, + cluster_handlers, ) for comp_id, ent_info in device[DEV_SIG_ENT_MAP].items(): - component, unique_id = comp_id + platform, unique_id = comp_id no_tail_id = NO_TAIL_ID.sub("", ent_info[DEV_SIG_ENT_MAP_ID]) - ha_entity_id = entity_registry.async_get_entity_id(component, "zha", unique_id) + ha_entity_id = entity_registry.async_get_entity_id(platform, "zha", unique_id) assert ha_entity_id is not None assert ha_entity_id.startswith(no_tail_id) @@ -182,13 +163,15 @@ async def test_devices( test_unique_id_head = UNIQUE_ID_HD.match(unique_id).group(0) assert (test_unique_id_head, test_ent_class) in ha_ent_info - ha_comp, ha_unique_id, ha_channels = ha_ent_info[ + ha_comp, ha_unique_id, ha_cluster_handlers = ha_ent_info[ (test_unique_id_head, test_ent_class) ] - assert component is ha_comp.value + assert platform is ha_comp.value # unique_id used for discover is the same for "multi entities" assert unique_id.startswith(ha_unique_id) - assert {ch.name for ch in ha_channels} == set(ent_info[DEV_SIG_CHANNELS]) + assert {ch.name for ch in ha_cluster_handlers} == set( + ent_info[DEV_SIG_CLUSTER_HANDLERS] + ) assert created_entity_count == len(device[DEV_SIG_ENT_MAP]) @@ -219,16 +202,16 @@ def _get_first_identify_cluster(zigpy_device): ) def test_discover_entities(m1, m2) -> None: """Test discover endpoint class method.""" - ep_channels = mock.MagicMock() - disc.PROBE.discover_entities(ep_channels) + endpoint = mock.MagicMock() + disc.PROBE.discover_entities(endpoint) assert m1.call_count == 1 - assert m1.call_args[0][0] is ep_channels + assert m1.call_args[0][0] is endpoint assert m2.call_count == 1 - assert m2.call_args[0][0] is ep_channels + assert m2.call_args[0][0] is endpoint @pytest.mark.parametrize( - ("device_type", "component", "hit"), + ("device_type", "platform", "hit"), [ (zigpy.profiles.zha.DeviceType.ON_OFF_LIGHT, Platform.LIGHT, True), (zigpy.profiles.zha.DeviceType.ON_OFF_BALLAST, Platform.SWITCH, True), @@ -236,14 +219,14 @@ def test_discover_entities(m1, m2) -> None: (0xFFFF, None, False), ], ) -def test_discover_by_device_type(device_type, component, hit) -> None: +def test_discover_by_device_type(device_type, platform, hit) -> None: """Test entity discovery by device type.""" - ep_channels = mock.MagicMock(spec_set=zha_channels.ChannelPool) + endpoint = mock.MagicMock(spec_set=Endpoint) ep_mock = mock.PropertyMock() ep_mock.return_value.profile_id = 0x0104 ep_mock.return_value.device_type = device_type - type(ep_channels).endpoint = ep_mock + type(endpoint).zigpy_endpoint = ep_mock get_entity_mock = mock.MagicMock( return_value=(mock.sentinel.entity_cls, mock.sentinel.claimed) @@ -252,26 +235,26 @@ def test_discover_by_device_type(device_type, component, hit) -> None: "homeassistant.components.zha.core.registries.ZHA_ENTITIES.get_entity", get_entity_mock, ): - disc.PROBE.discover_by_device_type(ep_channels) + disc.PROBE.discover_by_device_type(endpoint) if hit: assert get_entity_mock.call_count == 1 - assert ep_channels.claim_channels.call_count == 1 - assert ep_channels.claim_channels.call_args[0][0] is mock.sentinel.claimed - assert ep_channels.async_new_entity.call_count == 1 - assert ep_channels.async_new_entity.call_args[0][0] == component - assert ep_channels.async_new_entity.call_args[0][1] == mock.sentinel.entity_cls + assert endpoint.claim_cluster_handlers.call_count == 1 + assert endpoint.claim_cluster_handlers.call_args[0][0] is mock.sentinel.claimed + assert endpoint.async_new_entity.call_count == 1 + assert endpoint.async_new_entity.call_args[0][0] == platform + assert endpoint.async_new_entity.call_args[0][1] == mock.sentinel.entity_cls def test_discover_by_device_type_override() -> None: """Test entity discovery by device type overriding.""" - ep_channels = mock.MagicMock(spec_set=zha_channels.ChannelPool) + endpoint = mock.MagicMock(spec_set=Endpoint) ep_mock = mock.PropertyMock() ep_mock.return_value.profile_id = 0x0104 ep_mock.return_value.device_type = 0x0100 - type(ep_channels).endpoint = ep_mock + type(endpoint).zigpy_endpoint = ep_mock - overrides = {ep_channels.unique_id: {"type": Platform.SWITCH}} + overrides = {endpoint.unique_id: {"type": Platform.SWITCH}} get_entity_mock = mock.MagicMock( return_value=(mock.sentinel.entity_cls, mock.sentinel.claimed) ) @@ -279,99 +262,105 @@ def test_discover_by_device_type_override() -> None: "homeassistant.components.zha.core.registries.ZHA_ENTITIES.get_entity", get_entity_mock, ), mock.patch.dict(disc.PROBE._device_configs, overrides, clear=True): - disc.PROBE.discover_by_device_type(ep_channels) + disc.PROBE.discover_by_device_type(endpoint) assert get_entity_mock.call_count == 1 - assert ep_channels.claim_channels.call_count == 1 - assert ep_channels.claim_channels.call_args[0][0] is mock.sentinel.claimed - assert ep_channels.async_new_entity.call_count == 1 - assert ep_channels.async_new_entity.call_args[0][0] == Platform.SWITCH - assert ep_channels.async_new_entity.call_args[0][1] == mock.sentinel.entity_cls + assert endpoint.claim_cluster_handlers.call_count == 1 + assert endpoint.claim_cluster_handlers.call_args[0][0] is mock.sentinel.claimed + assert endpoint.async_new_entity.call_count == 1 + assert endpoint.async_new_entity.call_args[0][0] == Platform.SWITCH + assert endpoint.async_new_entity.call_args[0][1] == mock.sentinel.entity_cls def test_discover_probe_single_cluster() -> None: """Test entity discovery by single cluster.""" - ep_channels = mock.MagicMock(spec_set=zha_channels.ChannelPool) + endpoint = mock.MagicMock(spec_set=Endpoint) ep_mock = mock.PropertyMock() ep_mock.return_value.profile_id = 0x0104 ep_mock.return_value.device_type = 0x0100 - type(ep_channels).endpoint = ep_mock + type(endpoint).zigpy_endpoint = ep_mock get_entity_mock = mock.MagicMock( return_value=(mock.sentinel.entity_cls, mock.sentinel.claimed) ) - channel_mock = mock.MagicMock(spec_set=base_channels.ZigbeeChannel) + cluster_handler_mock = mock.MagicMock(spec_set=cluster_handlers.ClusterHandler) with mock.patch( "homeassistant.components.zha.core.registries.ZHA_ENTITIES.get_entity", get_entity_mock, ): - disc.PROBE.probe_single_cluster(Platform.SWITCH, channel_mock, ep_channels) + disc.PROBE.probe_single_cluster(Platform.SWITCH, cluster_handler_mock, endpoint) assert get_entity_mock.call_count == 1 - assert ep_channels.claim_channels.call_count == 1 - assert ep_channels.claim_channels.call_args[0][0] is mock.sentinel.claimed - assert ep_channels.async_new_entity.call_count == 1 - assert ep_channels.async_new_entity.call_args[0][0] == Platform.SWITCH - assert ep_channels.async_new_entity.call_args[0][1] == mock.sentinel.entity_cls - assert ep_channels.async_new_entity.call_args[0][3] == mock.sentinel.claimed + assert endpoint.claim_cluster_handlers.call_count == 1 + assert endpoint.claim_cluster_handlers.call_args[0][0] is mock.sentinel.claimed + assert endpoint.async_new_entity.call_count == 1 + assert endpoint.async_new_entity.call_args[0][0] == Platform.SWITCH + assert endpoint.async_new_entity.call_args[0][1] == mock.sentinel.entity_cls + assert endpoint.async_new_entity.call_args[0][3] == mock.sentinel.claimed @pytest.mark.parametrize("device_info", DEVICES) async def test_discover_endpoint( - device_info, channels_mock, hass: HomeAssistant + device_info, zha_device_mock, hass: HomeAssistant ) -> None: """Test device discovery.""" with mock.patch( - "homeassistant.components.zha.core.channels.Channels.async_new_entity" + "homeassistant.components.zha.core.endpoint.Endpoint.async_new_entity" ) as new_ent: - channels = channels_mock( + device = zha_device_mock( device_info[SIG_ENDPOINTS], manufacturer=device_info[SIG_MANUFACTURER], model=device_info[SIG_MODEL], node_desc=device_info[SIG_NODE_DESC], - patch_cluster=False, + patch_cluster=True, ) - assert device_info[DEV_SIG_EVT_CHANNELS] == sorted( - ch.id for pool in channels.pools for ch in pool.client_channels.values() + assert device_info[DEV_SIG_EVT_CLUSTER_HANDLERS] == sorted( + ch.id + for endpoint in device._endpoints.values() + for ch in endpoint.client_cluster_handlers.values() ) - # build a dict of entity_class -> (component, unique_id, channels) tuple + # build a dict of entity_class -> (platform, unique_id, cluster_handlers) tuple ha_ent_info = {} for call in new_ent.call_args_list: - component, entity_cls, unique_id, channels = call[0] + platform, entity_cls, unique_id, cluster_handlers = call[0] if not contains_ignored_suffix(unique_id): unique_id_head = UNIQUE_ID_HD.match(unique_id).group( 0 ) # ieee + endpoint_id ha_ent_info[(unique_id_head, entity_cls.__name__)] = ( - component, + platform, unique_id, - channels, + cluster_handlers, ) - for comp_id, ent_info in device_info[DEV_SIG_ENT_MAP].items(): - component, unique_id = comp_id + for platform_id, ent_info in device_info[DEV_SIG_ENT_MAP].items(): + platform, unique_id = platform_id test_ent_class = ent_info[DEV_SIG_ENT_MAP_CLASS] test_unique_id_head = UNIQUE_ID_HD.match(unique_id).group(0) assert (test_unique_id_head, test_ent_class) in ha_ent_info - ha_comp, ha_unique_id, ha_channels = ha_ent_info[ + entity_platform, entity_unique_id, entity_cluster_handlers = ha_ent_info[ (test_unique_id_head, test_ent_class) ] - assert component is ha_comp.value + assert platform is entity_platform.value # unique_id used for discover is the same for "multi entities" - assert unique_id.startswith(ha_unique_id) - assert {ch.name for ch in ha_channels} == set(ent_info[DEV_SIG_CHANNELS]) + assert unique_id.startswith(entity_unique_id) + assert {ch.name for ch in entity_cluster_handlers} == set( + ent_info[DEV_SIG_CLUSTER_HANDLERS] + ) def _ch_mock(cluster): - """Return mock of a channel with a cluster.""" - channel = mock.MagicMock() - type(channel).cluster = mock.PropertyMock(return_value=cluster(mock.MagicMock())) - return channel + """Return mock of a cluster_handler with a cluster.""" + cluster_handler = mock.MagicMock() + type(cluster_handler).cluster = mock.PropertyMock( + return_value=cluster(mock.MagicMock()) + ) + return cluster_handler @mock.patch( @@ -401,16 +390,16 @@ def _test_single_input_cluster_device_class(probe_mock): analog_ch = _ch_mock(_Analog) - ch_pool = mock.MagicMock(spec_set=zha_channels.ChannelPool) - ch_pool.unclaimed_channels.return_value = [ + endpoint = mock.MagicMock(spec_set=Endpoint) + endpoint.unclaimed_cluster_handlers.return_value = [ door_ch, cover_ch, multistate_ch, ias_ch, ] - disc.ProbeEndpoint().discover_by_cluster_id(ch_pool) - assert probe_mock.call_count == len(ch_pool.unclaimed_channels()) + disc.ProbeEndpoint().discover_by_cluster_id(endpoint) + assert probe_mock.call_count == len(endpoint.unclaimed_cluster_handlers()) probes = ( (Platform.LOCK, door_ch), (Platform.COVER, cover_ch), @@ -419,8 +408,8 @@ def _test_single_input_cluster_device_class(probe_mock): (Platform.SENSOR, analog_ch), ) for call, details in zip(probe_mock.call_args_list, probes): - component, ch = details - assert call[0][0] == component + platform, ch = details + assert call[0][0] == platform assert call[0][1] == ch @@ -498,7 +487,7 @@ async def test_group_probe_cleanup_called( "homeassistant.components.zha.entity.ZhaEntity.entity_registry_enabled_default", new=Mock(return_value=True), ) -async def test_channel_with_empty_ep_attribute_cluster( +async def test_cluster_handler_with_empty_ep_attribute_cluster( hass_disable_services, zigpy_device_mock, zha_device_joined_restored, diff --git a/tests/components/zha/test_light.py b/tests/components/zha/test_light.py index 5070aa770e4..0053258d09d 100644 --- a/tests/components/zha/test_light.py +++ b/tests/components/zha/test_light.py @@ -1036,18 +1036,18 @@ async def test_transitions( blocking=True, ) - group_on_off_channel = zha_group.endpoint[general.OnOff.cluster_id] - group_level_channel = zha_group.endpoint[general.LevelControl.cluster_id] - group_color_channel = zha_group.endpoint[lighting.Color.cluster_id] - assert group_on_off_channel.request.call_count == 0 - assert group_on_off_channel.request.await_count == 0 - assert group_color_channel.request.call_count == 1 - assert group_color_channel.request.await_count == 1 - assert group_level_channel.request.call_count == 1 - assert group_level_channel.request.await_count == 1 + group_on_off_cluster_handler = zha_group.endpoint[general.OnOff.cluster_id] + group_level_cluster_handler = zha_group.endpoint[general.LevelControl.cluster_id] + group_color_cluster_handler = zha_group.endpoint[lighting.Color.cluster_id] + assert group_on_off_cluster_handler.request.call_count == 0 + assert group_on_off_cluster_handler.request.await_count == 0 + assert group_color_cluster_handler.request.call_count == 1 + assert group_color_cluster_handler.request.await_count == 1 + assert group_level_cluster_handler.request.call_count == 1 + assert group_level_cluster_handler.request.await_count == 1 # groups are omitted from the 3 call dance for new_color_provided_while_off - assert group_color_channel.request.call_args == call( + assert group_color_cluster_handler.request.call_args == call( False, dev2_cluster_color.commands_by_name["move_to_color_temp"].id, dev2_cluster_color.commands_by_name["move_to_color_temp"].schema, @@ -1058,7 +1058,7 @@ async def test_transitions( tries=1, tsn=None, ) - assert group_level_channel.request.call_args == call( + assert group_level_cluster_handler.request.call_args == call( False, dev2_cluster_level.commands_by_name["move_to_level_with_on_off"].id, dev2_cluster_level.commands_by_name["move_to_level_with_on_off"].schema, @@ -1076,9 +1076,9 @@ async def test_transitions( assert group_state.attributes["color_temp"] == 235 assert group_state.attributes["color_mode"] == ColorMode.COLOR_TEMP - group_on_off_channel.request.reset_mock() - group_color_channel.request.reset_mock() - group_level_channel.request.reset_mock() + group_on_off_cluster_handler.request.reset_mock() + group_color_cluster_handler.request.reset_mock() + group_level_cluster_handler.request.reset_mock() # turn the sengled light back on await hass.services.async_call( diff --git a/tests/components/zha/test_registries.py b/tests/components/zha/test_registries.py index 80b1f10f561..1ab8e331b0b 100644 --- a/tests/components/zha/test_registries.py +++ b/tests/components/zha/test_registries.py @@ -25,36 +25,48 @@ def zha_device(): @pytest.fixture -def channels(channel): - """Return a mock of channels.""" +def cluster_handlers(cluster_handler): + """Return a mock of cluster_handlers.""" - return [channel("level", 8), channel("on_off", 6)] + return [cluster_handler("level", 8), cluster_handler("on_off", 6)] @pytest.mark.parametrize( ("rule", "matched"), [ (registries.MatchRule(), False), - (registries.MatchRule(channel_names={"level"}), True), - (registries.MatchRule(channel_names={"level", "no match"}), False), - (registries.MatchRule(channel_names={"on_off"}), True), - (registries.MatchRule(channel_names={"on_off", "no match"}), False), - (registries.MatchRule(channel_names={"on_off", "level"}), True), - (registries.MatchRule(channel_names={"on_off", "level", "no match"}), False), + (registries.MatchRule(cluster_handler_names={"level"}), True), + (registries.MatchRule(cluster_handler_names={"level", "no match"}), False), + (registries.MatchRule(cluster_handler_names={"on_off"}), True), + (registries.MatchRule(cluster_handler_names={"on_off", "no match"}), False), + (registries.MatchRule(cluster_handler_names={"on_off", "level"}), True), + ( + registries.MatchRule(cluster_handler_names={"on_off", "level", "no match"}), + False, + ), # test generic_id matching - (registries.MatchRule(generic_ids={"channel_0x0006"}), True), - (registries.MatchRule(generic_ids={"channel_0x0008"}), True), - (registries.MatchRule(generic_ids={"channel_0x0006", "channel_0x0008"}), True), + (registries.MatchRule(generic_ids={"cluster_handler_0x0006"}), True), + (registries.MatchRule(generic_ids={"cluster_handler_0x0008"}), True), ( registries.MatchRule( - generic_ids={"channel_0x0006", "channel_0x0008", "channel_0x0009"} + generic_ids={"cluster_handler_0x0006", "cluster_handler_0x0008"} + ), + True, + ), + ( + registries.MatchRule( + generic_ids={ + "cluster_handler_0x0006", + "cluster_handler_0x0008", + "cluster_handler_0x0009", + } ), False, ), ( registries.MatchRule( - generic_ids={"channel_0x0006", "channel_0x0008"}, - channel_names={"on_off", "level"}, + generic_ids={"cluster_handler_0x0006", "cluster_handler_0x0008"}, + cluster_handler_names={"on_off", "level"}, ), True, ), @@ -62,34 +74,50 @@ def channels(channel): (registries.MatchRule(manufacturers="no match"), False), (registries.MatchRule(manufacturers=MANUFACTURER), True), ( - registries.MatchRule(manufacturers="no match", aux_channels="aux_channel"), + registries.MatchRule( + manufacturers="no match", aux_cluster_handlers="aux_cluster_handler" + ), False, ), ( registries.MatchRule( - manufacturers=MANUFACTURER, aux_channels="aux_channel" + manufacturers=MANUFACTURER, aux_cluster_handlers="aux_cluster_handler" ), True, ), (registries.MatchRule(models=MODEL), True), (registries.MatchRule(models="no match"), False), - (registries.MatchRule(models=MODEL, aux_channels="aux_channel"), True), - (registries.MatchRule(models="no match", aux_channels="aux_channel"), False), - (registries.MatchRule(quirk_classes=QUIRK_CLASS), True), - (registries.MatchRule(quirk_classes="no match"), False), ( - registries.MatchRule(quirk_classes=QUIRK_CLASS, aux_channels="aux_channel"), + registries.MatchRule( + models=MODEL, aux_cluster_handlers="aux_cluster_handler" + ), True, ), ( - registries.MatchRule(quirk_classes="no match", aux_channels="aux_channel"), + registries.MatchRule( + models="no match", aux_cluster_handlers="aux_cluster_handler" + ), + False, + ), + (registries.MatchRule(quirk_classes=QUIRK_CLASS), True), + (registries.MatchRule(quirk_classes="no match"), False), + ( + registries.MatchRule( + quirk_classes=QUIRK_CLASS, aux_cluster_handlers="aux_cluster_handler" + ), + True, + ), + ( + registries.MatchRule( + quirk_classes="no match", aux_cluster_handlers="aux_cluster_handler" + ), False, ), # match everything ( registries.MatchRule( - generic_ids={"channel_0x0006", "channel_0x0008"}, - channel_names={"on_off", "level"}, + generic_ids={"cluster_handler_0x0006", "cluster_handler_0x0008"}, + cluster_handler_names={"on_off", "level"}, manufacturers=MANUFACTURER, models=MODEL, quirk_classes=QUIRK_CLASS, @@ -98,96 +126,114 @@ def channels(channel): ), ( registries.MatchRule( - channel_names="on_off", manufacturers={"random manuf", MANUFACTURER} + cluster_handler_names="on_off", + manufacturers={"random manuf", MANUFACTURER}, ), True, ), ( registries.MatchRule( - channel_names="on_off", manufacturers={"random manuf", "Another manuf"} + cluster_handler_names="on_off", + manufacturers={"random manuf", "Another manuf"}, ), False, ), ( registries.MatchRule( - channel_names="on_off", manufacturers=lambda x: x == MANUFACTURER + cluster_handler_names="on_off", + manufacturers=lambda x: x == MANUFACTURER, ), True, ), ( registries.MatchRule( - channel_names="on_off", manufacturers=lambda x: x != MANUFACTURER + cluster_handler_names="on_off", + manufacturers=lambda x: x != MANUFACTURER, ), False, ), ( registries.MatchRule( - channel_names="on_off", models={"random model", MODEL} + cluster_handler_names="on_off", models={"random model", MODEL} ), True, ), ( registries.MatchRule( - channel_names="on_off", models={"random model", "Another model"} - ), - False, - ), - ( - registries.MatchRule(channel_names="on_off", models=lambda x: x == MODEL), - True, - ), - ( - registries.MatchRule(channel_names="on_off", models=lambda x: x != MODEL), - False, - ), - ( - registries.MatchRule( - channel_names="on_off", quirk_classes={"random quirk", QUIRK_CLASS} - ), - True, - ), - ( - registries.MatchRule( - channel_names="on_off", quirk_classes={"random quirk", "another quirk"} + cluster_handler_names="on_off", models={"random model", "Another model"} ), False, ), ( registries.MatchRule( - channel_names="on_off", quirk_classes=lambda x: x == QUIRK_CLASS + cluster_handler_names="on_off", models=lambda x: x == MODEL ), True, ), ( registries.MatchRule( - channel_names="on_off", quirk_classes=lambda x: x != QUIRK_CLASS + cluster_handler_names="on_off", models=lambda x: x != MODEL + ), + False, + ), + ( + registries.MatchRule( + cluster_handler_names="on_off", + quirk_classes={"random quirk", QUIRK_CLASS}, + ), + True, + ), + ( + registries.MatchRule( + cluster_handler_names="on_off", + quirk_classes={"random quirk", "another quirk"}, + ), + False, + ), + ( + registries.MatchRule( + cluster_handler_names="on_off", quirk_classes=lambda x: x == QUIRK_CLASS + ), + True, + ), + ( + registries.MatchRule( + cluster_handler_names="on_off", quirk_classes=lambda x: x != QUIRK_CLASS ), False, ), ], ) -def test_registry_matching(rule, matched, channels) -> None: +def test_registry_matching(rule, matched, cluster_handlers) -> None: """Test strict rule matching.""" - assert rule.strict_matched(MANUFACTURER, MODEL, channels, QUIRK_CLASS) is matched + assert ( + rule.strict_matched(MANUFACTURER, MODEL, cluster_handlers, QUIRK_CLASS) + is matched + ) @pytest.mark.parametrize( ("rule", "matched"), [ (registries.MatchRule(), False), - (registries.MatchRule(channel_names={"level"}), True), - (registries.MatchRule(channel_names={"level", "no match"}), False), - (registries.MatchRule(channel_names={"on_off"}), True), - (registries.MatchRule(channel_names={"on_off", "no match"}), False), - (registries.MatchRule(channel_names={"on_off", "level"}), True), - (registries.MatchRule(channel_names={"on_off", "level", "no match"}), False), + (registries.MatchRule(cluster_handler_names={"level"}), True), + (registries.MatchRule(cluster_handler_names={"level", "no match"}), False), + (registries.MatchRule(cluster_handler_names={"on_off"}), True), + (registries.MatchRule(cluster_handler_names={"on_off", "no match"}), False), + (registries.MatchRule(cluster_handler_names={"on_off", "level"}), True), ( - registries.MatchRule(channel_names={"on_off", "level"}, models="no match"), + registries.MatchRule(cluster_handler_names={"on_off", "level", "no match"}), + False, + ), + ( + registries.MatchRule( + cluster_handler_names={"on_off", "level"}, models="no match" + ), True, ), ( registries.MatchRule( - channel_names={"on_off", "level"}, + cluster_handler_names={"on_off", "level"}, models="no match", manufacturers="no match", ), @@ -195,40 +241,57 @@ def test_registry_matching(rule, matched, channels) -> None: ), ( registries.MatchRule( - channel_names={"on_off", "level"}, + cluster_handler_names={"on_off", "level"}, models="no match", manufacturers=MANUFACTURER, ), True, ), # test generic_id matching - (registries.MatchRule(generic_ids={"channel_0x0006"}), True), - (registries.MatchRule(generic_ids={"channel_0x0008"}), True), - (registries.MatchRule(generic_ids={"channel_0x0006", "channel_0x0008"}), True), + (registries.MatchRule(generic_ids={"cluster_handler_0x0006"}), True), + (registries.MatchRule(generic_ids={"cluster_handler_0x0008"}), True), ( registries.MatchRule( - generic_ids={"channel_0x0006", "channel_0x0008", "channel_0x0009"} + generic_ids={"cluster_handler_0x0006", "cluster_handler_0x0008"} + ), + True, + ), + ( + registries.MatchRule( + generic_ids={ + "cluster_handler_0x0006", + "cluster_handler_0x0008", + "cluster_handler_0x0009", + } ), False, ), ( registries.MatchRule( - generic_ids={"channel_0x0006", "channel_0x0008", "channel_0x0009"}, + generic_ids={ + "cluster_handler_0x0006", + "cluster_handler_0x0008", + "cluster_handler_0x0009", + }, models="mo match", ), False, ), ( registries.MatchRule( - generic_ids={"channel_0x0006", "channel_0x0008", "channel_0x0009"}, + generic_ids={ + "cluster_handler_0x0006", + "cluster_handler_0x0008", + "cluster_handler_0x0009", + }, models=MODEL, ), True, ), ( registries.MatchRule( - generic_ids={"channel_0x0006", "channel_0x0008"}, - channel_names={"on_off", "level"}, + generic_ids={"cluster_handler_0x0006", "cluster_handler_0x0008"}, + cluster_handler_names={"on_off", "level"}, ), True, ), @@ -242,8 +305,8 @@ def test_registry_matching(rule, matched, channels) -> None: # match everything ( registries.MatchRule( - generic_ids={"channel_0x0006", "channel_0x0008"}, - channel_names={"on_off", "level"}, + generic_ids={"cluster_handler_0x0006", "cluster_handler_0x0008"}, + cluster_handler_names={"on_off", "level"}, manufacturers=MANUFACTURER, models=MODEL, quirk_classes=QUIRK_CLASS, @@ -252,51 +315,64 @@ def test_registry_matching(rule, matched, channels) -> None: ), ], ) -def test_registry_loose_matching(rule, matched, channels) -> None: +def test_registry_loose_matching(rule, matched, cluster_handlers) -> None: """Test loose rule matching.""" - assert rule.loose_matched(MANUFACTURER, MODEL, channels, QUIRK_CLASS) is matched + assert ( + rule.loose_matched(MANUFACTURER, MODEL, cluster_handlers, QUIRK_CLASS) + is matched + ) -def test_match_rule_claim_channels_color(channel) -> None: - """Test channel claiming.""" - ch_color = channel("color", 0x300) - ch_level = channel("level", 8) - ch_onoff = channel("on_off", 6) +def test_match_rule_claim_cluster_handlers_color(cluster_handler) -> None: + """Test cluster handler claiming.""" + ch_color = cluster_handler("color", 0x300) + ch_level = cluster_handler("level", 8) + ch_onoff = cluster_handler("on_off", 6) - rule = registries.MatchRule(channel_names="on_off", aux_channels={"color", "level"}) - claimed = rule.claim_channels([ch_color, ch_level, ch_onoff]) + rule = registries.MatchRule( + cluster_handler_names="on_off", aux_cluster_handlers={"color", "level"} + ) + claimed = rule.claim_cluster_handlers([ch_color, ch_level, ch_onoff]) assert {"color", "level", "on_off"} == {ch.name for ch in claimed} @pytest.mark.parametrize( ("rule", "match"), [ - (registries.MatchRule(channel_names={"level"}), {"level"}), - (registries.MatchRule(channel_names={"level", "no match"}), {"level"}), - (registries.MatchRule(channel_names={"on_off"}), {"on_off"}), - (registries.MatchRule(generic_ids="channel_0x0000"), {"basic"}), - ( - registries.MatchRule(channel_names="level", generic_ids="channel_0x0000"), - {"basic", "level"}, - ), - (registries.MatchRule(channel_names={"level", "power"}), {"level", "power"}), + (registries.MatchRule(cluster_handler_names={"level"}), {"level"}), + (registries.MatchRule(cluster_handler_names={"level", "no match"}), {"level"}), + (registries.MatchRule(cluster_handler_names={"on_off"}), {"on_off"}), + (registries.MatchRule(generic_ids="cluster_handler_0x0000"), {"basic"}), ( registries.MatchRule( - channel_names={"level", "on_off"}, aux_channels={"basic", "power"} + cluster_handler_names="level", generic_ids="cluster_handler_0x0000" + ), + {"basic", "level"}, + ), + ( + registries.MatchRule(cluster_handler_names={"level", "power"}), + {"level", "power"}, + ), + ( + registries.MatchRule( + cluster_handler_names={"level", "on_off"}, + aux_cluster_handlers={"basic", "power"}, ), {"basic", "level", "on_off", "power"}, ), - (registries.MatchRule(channel_names={"color"}), set()), + (registries.MatchRule(cluster_handler_names={"color"}), set()), ], ) -def test_match_rule_claim_channels(rule, match, channel, channels) -> None: - """Test channel claiming.""" - ch_basic = channel("basic", 0) - channels.append(ch_basic) - ch_power = channel("power", 1) - channels.append(ch_power) +def test_match_rule_claim_cluster_handlers( + rule, match, cluster_handler, cluster_handlers +) -> None: + """Test cluster handler claiming.""" + ch_basic = cluster_handler("basic", 0) + cluster_handlers.append(ch_basic) + ch_power = cluster_handler("power", 1) + cluster_handlers.append(ch_power) - claimed = rule.claim_channels(channels) + claimed = rule.claim_cluster_handlers(cluster_handlers) assert match == {ch.name for ch in claimed} @@ -318,7 +394,7 @@ def entity_registry(): ), ) def test_weighted_match( - channel, + cluster_handler, entity_registry: er.EntityRegistry, manufacturer, model, @@ -331,40 +407,45 @@ def test_weighted_match( @entity_registry.strict_match( s.component, - channel_names="on_off", + cluster_handler_names="on_off", models={MODEL, "another model", "some model"}, ) class OnOffMultimodel: pass - @entity_registry.strict_match(s.component, channel_names="on_off") + @entity_registry.strict_match(s.component, cluster_handler_names="on_off") class OnOff: pass @entity_registry.strict_match( - s.component, channel_names="on_off", manufacturers=MANUFACTURER + s.component, cluster_handler_names="on_off", manufacturers=MANUFACTURER ) class OnOffManufacturer: pass - @entity_registry.strict_match(s.component, channel_names="on_off", models=MODEL) + @entity_registry.strict_match( + s.component, cluster_handler_names="on_off", models=MODEL + ) class OnOffModel: pass @entity_registry.strict_match( - s.component, channel_names="on_off", models=MODEL, manufacturers=MANUFACTURER + s.component, + cluster_handler_names="on_off", + models=MODEL, + manufacturers=MANUFACTURER, ) class OnOffModelManufacturer: pass @entity_registry.strict_match( - s.component, channel_names="on_off", quirk_classes=QUIRK_CLASS + s.component, cluster_handler_names="on_off", quirk_classes=QUIRK_CLASS ) class OnOffQuirk: pass - ch_on_off = channel("on_off", 6) - ch_level = channel("level", 8) + ch_on_off = cluster_handler("on_off", 6) + ch_level = cluster_handler("level", 8) match, claimed = entity_registry.get_entity( s.component, manufacturer, model, [ch_on_off, ch_level], quirk_class @@ -374,25 +455,27 @@ def test_weighted_match( assert claimed == [ch_on_off] -def test_multi_sensor_match(channel, entity_registry: er.EntityRegistry) -> None: +def test_multi_sensor_match( + cluster_handler, entity_registry: er.EntityRegistry +) -> None: """Test multi-entity match.""" s = mock.sentinel @entity_registry.multipass_match( s.binary_sensor, - channel_names="smartenergy_metering", + cluster_handler_names="smartenergy_metering", ) class SmartEnergySensor2: pass - ch_se = channel("smartenergy_metering", 0x0702) - ch_illuminati = channel("illuminance", 0x0401) + ch_se = cluster_handler("smartenergy_metering", 0x0702) + ch_illuminati = cluster_handler("illuminance", 0x0401) match, claimed = entity_registry.get_multi_entity( "manufacturer", "model", - channels=[ch_se, ch_illuminati], + cluster_handlers=[ch_se, ch_illuminati], quirk_class="quirk_class", ) @@ -404,15 +487,17 @@ def test_multi_sensor_match(channel, entity_registry: er.EntityRegistry) -> None } @entity_registry.multipass_match( - s.component, channel_names="smartenergy_metering", aux_channels="illuminance" + s.component, + cluster_handler_names="smartenergy_metering", + aux_cluster_handlers="illuminance", ) class SmartEnergySensor1: pass @entity_registry.multipass_match( s.binary_sensor, - channel_names="smartenergy_metering", - aux_channels="illuminance", + cluster_handler_names="smartenergy_metering", + aux_cluster_handlers="illuminance", ) class SmartEnergySensor3: pass @@ -420,7 +505,7 @@ def test_multi_sensor_match(channel, entity_registry: er.EntityRegistry) -> None match, claimed = entity_registry.get_multi_entity( "manufacturer", "model", - channels={ch_se, ch_illuminati}, + cluster_handlers={ch_se, ch_illuminati}, quirk_class="quirk_class", ) diff --git a/tests/components/zha/test_sensor.py b/tests/components/zha/test_sensor.py index 5ef83ff454f..4e2d2265178 100644 --- a/tests/components/zha/test_sensor.py +++ b/tests/components/zha/test_sensor.py @@ -10,7 +10,7 @@ import zigpy.zcl.clusters.measurement as measurement import zigpy.zcl.clusters.smartenergy as smartenergy from homeassistant.components.sensor import SensorDeviceClass -from homeassistant.components.zha.core.const import ZHA_CHANNEL_READS_PER_REQ +from homeassistant.components.zha.core.const import ZHA_CLUSTER_HANDLER_READS_PER_REQ import homeassistant.config as config_util from homeassistant.const import ( ATTR_DEVICE_CLASS, @@ -616,30 +616,30 @@ async def test_electrical_measurement_init( await send_attributes_report(hass, cluster, {0: 1, 1291: 100, 10: 1000}) assert int(hass.states.get(entity_id).state) == 100 - channel = zha_device.channels.pools[0].all_channels["1:0x0b04"] - assert channel.ac_power_divisor == 1 - assert channel.ac_power_multiplier == 1 + cluster_handler = zha_device._endpoints[1].all_cluster_handlers["1:0x0b04"] + assert cluster_handler.ac_power_divisor == 1 + assert cluster_handler.ac_power_multiplier == 1 # update power divisor await send_attributes_report(hass, cluster, {0: 1, 1291: 20, 0x0403: 5, 10: 1000}) - assert channel.ac_power_divisor == 5 - assert channel.ac_power_multiplier == 1 + assert cluster_handler.ac_power_divisor == 5 + assert cluster_handler.ac_power_multiplier == 1 assert hass.states.get(entity_id).state == "4.0" await send_attributes_report(hass, cluster, {0: 1, 1291: 30, 0x0605: 10, 10: 1000}) - assert channel.ac_power_divisor == 10 - assert channel.ac_power_multiplier == 1 + assert cluster_handler.ac_power_divisor == 10 + assert cluster_handler.ac_power_multiplier == 1 assert hass.states.get(entity_id).state == "3.0" # update power multiplier await send_attributes_report(hass, cluster, {0: 1, 1291: 20, 0x0402: 6, 10: 1000}) - assert channel.ac_power_divisor == 10 - assert channel.ac_power_multiplier == 6 + assert cluster_handler.ac_power_divisor == 10 + assert cluster_handler.ac_power_multiplier == 6 assert hass.states.get(entity_id).state == "12.0" await send_attributes_report(hass, cluster, {0: 1, 1291: 30, 0x0604: 20, 10: 1000}) - assert channel.ac_power_divisor == 10 - assert channel.ac_power_multiplier == 20 + assert cluster_handler.ac_power_divisor == 10 + assert cluster_handler.ac_power_multiplier == 20 assert hass.states.get(entity_id).state == "60.0" @@ -972,7 +972,7 @@ async def test_elec_measurement_skip_unsupported_attribute( await async_update_entity(hass, entity_id) await hass.async_block_till_done() assert cluster.read_attributes.call_count == math.ceil( - len(supported_attributes) / ZHA_CHANNEL_READS_PER_REQ + len(supported_attributes) / ZHA_CLUSTER_HANDLER_READS_PER_REQ ) read_attrs = { a for call in cluster.read_attributes.call_args_list for a in call[0][0] diff --git a/tests/components/zha/zha_devices_list.py b/tests/components/zha/zha_devices_list.py index 0b27f1ead16..0f73868b9d7 100644 --- a/tests/components/zha/zha_devices_list.py +++ b/tests/components/zha/zha_devices_list.py @@ -11,14 +11,14 @@ from zigpy.const import ( SIG_NODE_DESC, ) -DEV_SIG_CHANNELS = "channels" +DEV_SIG_CLUSTER_HANDLERS = "cluster_handlers" DEV_SIG_DEV_NO = "device_no" DEV_SIG_ENTITIES = "entities" DEV_SIG_ENT_MAP = "entity_map" DEV_SIG_ENT_MAP_CLASS = "entity_class" DEV_SIG_ENT_MAP_ID = "entity_id" DEV_SIG_EP_ID = "endpoint_id" -DEV_SIG_EVT_CHANNELS = "event_channels" +DEV_SIG_EVT_CLUSTER_HANDLERS = "event_cluster_handlers" DEV_SIG_ZHA_QUIRK = "zha_quirk" DEVICES = [ @@ -36,7 +36,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008"], DEV_SIG_ENTITIES: [ "button.adurolight_adurolight_ncc_identify", "sensor.adurolight_adurolight_ncc_rssi", @@ -44,17 +44,17 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.adurolight_adurolight_ncc_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.adurolight_adurolight_ncc_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.adurolight_adurolight_ncc_lqi", }, @@ -74,7 +74,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["5:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["5:0x0019"], DEV_SIG_ENTITIES: [ "button.bosch_isw_zpr1_wp13_identify", "sensor.bosch_isw_zpr1_wp13_battery", @@ -85,32 +85,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-5-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.bosch_isw_zpr1_wp13_iaszone", }, ("button", "00:11:22:33:44:55:66:77-5-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.bosch_isw_zpr1_wp13_identify", }, ("sensor", "00:11:22:33:44:55:66:77-5-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.bosch_isw_zpr1_wp13_battery", }, ("sensor", "00:11:22:33:44:55:66:77-5-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.bosch_isw_zpr1_wp13_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-5-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.bosch_isw_zpr1_wp13_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-5-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.bosch_isw_zpr1_wp13_lqi", }, @@ -130,7 +130,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.centralite_3130_identify", "sensor.centralite_3130_battery", @@ -139,22 +139,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.centralite_3130_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3130_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3130_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3130_lqi", }, @@ -174,7 +174,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.centralite_3210_l_identify", "sensor.centralite_3210_l_active_power", @@ -191,62 +191,62 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("switch", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.centralite_3210_l_switch", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.centralite_3210_l_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_apparent_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_instantaneous_demand", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_summation_delivered", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_lqi", }, @@ -266,7 +266,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.centralite_3310_s_identify", "sensor.centralite_3310_s_battery", @@ -277,32 +277,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.centralite_3310_s_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3310_s_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3310_s_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3310_s_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3310_s_lqi", }, ("sensor", "00:11:22:33:44:55:66:77-1-64581"): { - DEV_SIG_CHANNELS: ["manufacturer_specific"], + DEV_SIG_CLUSTER_HANDLERS: ["manufacturer_specific"], DEV_SIG_ENT_MAP_CLASS: "Humidity", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3310_s_humidity", }, @@ -329,7 +329,7 @@ DEVICES = [ SIG_EP_PROFILE: 49887, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.centralite_3315_s_identify", "sensor.centralite_3315_s_battery", @@ -340,32 +340,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.centralite_3315_s_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.centralite_3315_s_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3315_s_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3315_s_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3315_s_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3315_s_lqi", }, @@ -392,7 +392,7 @@ DEVICES = [ SIG_EP_PROFILE: 49887, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.centralite_3320_l_identify", "sensor.centralite_3320_l_battery", @@ -403,32 +403,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.centralite_3320_l_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.centralite_3320_l_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3320_l_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3320_l_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3320_l_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3320_l_lqi", }, @@ -455,7 +455,7 @@ DEVICES = [ SIG_EP_PROFILE: 49887, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.centralite_3326_l_identify", "sensor.centralite_3326_l_battery", @@ -466,32 +466,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.centralite_3326_l_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.centralite_3326_l_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3326_l_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3326_l_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3326_l_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3326_l_lqi", }, @@ -518,7 +518,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.centralite_motion_sensor_a_identify", "sensor.centralite_motion_sensor_a_battery", @@ -530,37 +530,37 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.centralite_motion_sensor_a_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.centralite_motion_sensor_a_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.centralite_motion_sensor_a_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.centralite_motion_sensor_a_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_motion_sensor_a_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.centralite_motion_sensor_a_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-2-1030"): { - DEV_SIG_CHANNELS: ["occupancy"], + DEV_SIG_CLUSTER_HANDLERS: ["occupancy"], DEV_SIG_ENT_MAP_CLASS: "Occupancy", DEV_SIG_ENT_MAP_ID: ( "binary_sensor.centralite_motion_sensor_a_occupancy" @@ -589,7 +589,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["4:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["4:0x0019"], DEV_SIG_ENTITIES: [ "button.climaxtechnology_psmp5_00_00_02_02tc_identify", "sensor.climaxtechnology_psmp5_00_00_02_02tc_instantaneous_demand", @@ -600,40 +600,40 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("switch", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: ( "switch.climaxtechnology_psmp5_00_00_02_02tc_switch" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.climaxtechnology_psmp5_00_00_02_02tc_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: ( "sensor.climaxtechnology_psmp5_00_00_02_02tc_instantaneous_demand" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: ( "sensor.climaxtechnology_psmp5_00_00_02_02tc_summation_delivered" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.climaxtechnology_psmp5_00_00_02_02tc_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.climaxtechnology_psmp5_00_00_02_02tc_lqi", }, @@ -653,7 +653,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.climaxtechnology_sd8sc_00_00_03_12tc_identify", "binary_sensor.climaxtechnology_sd8sc_00_00_03_12tc_iaszone", @@ -667,59 +667,59 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: ( "binary_sensor.climaxtechnology_sd8sc_00_00_03_12tc_iaszone" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.climaxtechnology_sd8sc_00_00_03_12tc_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.climaxtechnology_sd8sc_00_00_03_12tc_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.climaxtechnology_sd8sc_00_00_03_12tc_lqi", }, ("select", "00:11:22:33:44:55:66:77-1-1282-WarningMode"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultToneSelectEntity", DEV_SIG_ENT_MAP_ID: ( "select.climaxtechnology_sd8sc_00_00_03_12tc_default_siren_tone" ), }, ("select", "00:11:22:33:44:55:66:77-1-1282-SirenLevel"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultSirenLevelSelectEntity", DEV_SIG_ENT_MAP_ID: ( "select.climaxtechnology_sd8sc_00_00_03_12tc_default_siren_level" ), }, ("select", "00:11:22:33:44:55:66:77-1-1282-StrobeLevel"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultStrobeLevelSelectEntity", DEV_SIG_ENT_MAP_ID: ( "select.climaxtechnology_sd8sc_00_00_03_12tc_default_strobe_level" ), }, ("select", "00:11:22:33:44:55:66:77-1-1282-Strobe"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultStrobeSelectEntity", DEV_SIG_ENT_MAP_ID: ( "select.climaxtechnology_sd8sc_00_00_03_12tc_default_strobe" ), }, ("siren", "00:11:22:33:44:55:66:77-1-1282"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHASiren", DEV_SIG_ENT_MAP_ID: "siren.climaxtechnology_sd8sc_00_00_03_12tc_siren", }, @@ -739,7 +739,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.climaxtechnology_ws15_00_00_03_03tc_identify", "binary_sensor.climaxtechnology_ws15_00_00_03_03tc_iaszone", @@ -748,26 +748,26 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: ( "binary_sensor.climaxtechnology_ws15_00_00_03_03tc_iaszone" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.climaxtechnology_ws15_00_00_03_03tc_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.climaxtechnology_ws15_00_00_03_03tc_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.climaxtechnology_ws15_00_00_03_03tc_lqi", }, @@ -794,7 +794,7 @@ DEVICES = [ SIG_EP_PROFILE: 49246, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.feibit_inc_co_fb56_zcw08ku1_1_identify", "light.feibit_inc_co_fb56_zcw08ku1_1_light", @@ -803,22 +803,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-11"): { - DEV_SIG_CHANNELS: ["on_off", "light_color", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "light_color", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.feibit_inc_co_fb56_zcw08ku1_1_light", }, ("button", "00:11:22:33:44:55:66:77-11-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.feibit_inc_co_fb56_zcw08ku1_1_identify", }, ("sensor", "00:11:22:33:44:55:66:77-11-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.feibit_inc_co_fb56_zcw08ku1_1_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-11-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.feibit_inc_co_fb56_zcw08ku1_1_lqi", }, @@ -838,7 +838,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.heiman_smokesensor_em_identify", "sensor.heiman_smokesensor_em_battery", @@ -853,52 +853,52 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.heiman_smokesensor_em_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.heiman_smokesensor_em_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.heiman_smokesensor_em_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.heiman_smokesensor_em_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.heiman_smokesensor_em_lqi", }, ("select", "00:11:22:33:44:55:66:77-1-1282-WarningMode"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultToneSelectEntity", DEV_SIG_ENT_MAP_ID: "select.heiman_smokesensor_em_default_siren_tone", }, ("select", "00:11:22:33:44:55:66:77-1-1282-SirenLevel"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultSirenLevelSelectEntity", DEV_SIG_ENT_MAP_ID: "select.heiman_smokesensor_em_default_siren_level", }, ("select", "00:11:22:33:44:55:66:77-1-1282-StrobeLevel"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultStrobeLevelSelectEntity", DEV_SIG_ENT_MAP_ID: "select.heiman_smokesensor_em_default_strobe_level", }, ("select", "00:11:22:33:44:55:66:77-1-1282-Strobe"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultStrobeSelectEntity", DEV_SIG_ENT_MAP_ID: "select.heiman_smokesensor_em_default_strobe", }, ("siren", "00:11:22:33:44:55:66:77-1-1282"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHASiren", DEV_SIG_ENT_MAP_ID: "siren.heiman_smokesensor_em_siren", }, @@ -918,7 +918,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.heiman_co_v16_identify", "binary_sensor.heiman_co_v16_iaszone", @@ -927,22 +927,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.heiman_co_v16_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.heiman_co_v16_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.heiman_co_v16_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.heiman_co_v16_lqi", }, @@ -962,7 +962,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.heiman_warningdevice_identify", "binary_sensor.heiman_warningdevice_iaszone", @@ -976,47 +976,47 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("select", "00:11:22:33:44:55:66:77-1-1282-WarningMode"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultToneSelectEntity", DEV_SIG_ENT_MAP_ID: "select.heiman_warningdevice_default_siren_tone", }, ("select", "00:11:22:33:44:55:66:77-1-1282-SirenLevel"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultSirenLevelSelectEntity", DEV_SIG_ENT_MAP_ID: "select.heiman_warningdevice_default_siren_level", }, ("select", "00:11:22:33:44:55:66:77-1-1282-StrobeLevel"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultStrobeLevelSelectEntity", DEV_SIG_ENT_MAP_ID: "select.heiman_warningdevice_default_strobe_level", }, ("select", "00:11:22:33:44:55:66:77-1-1282-Strobe"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHADefaultStrobeSelectEntity", DEV_SIG_ENT_MAP_ID: "select.heiman_warningdevice_default_strobe", }, ("siren", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["ias_wd"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_wd"], DEV_SIG_ENT_MAP_CLASS: "ZHASiren", DEV_SIG_ENT_MAP_ID: "siren.heiman_warningdevice_siren", }, ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.heiman_warningdevice_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.heiman_warningdevice_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.heiman_warningdevice_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.heiman_warningdevice_lqi", }, @@ -1036,7 +1036,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["6:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["6:0x0019"], DEV_SIG_ENTITIES: [ "button.hivehome_com_mot003_identify", "sensor.hivehome_com_mot003_battery", @@ -1048,37 +1048,37 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-6-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.hivehome_com_mot003_iaszone", }, ("button", "00:11:22:33:44:55:66:77-6-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.hivehome_com_mot003_identify", }, ("sensor", "00:11:22:33:44:55:66:77-6-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.hivehome_com_mot003_battery", }, ("sensor", "00:11:22:33:44:55:66:77-6-1024"): { - DEV_SIG_CHANNELS: ["illuminance"], + DEV_SIG_CLUSTER_HANDLERS: ["illuminance"], DEV_SIG_ENT_MAP_CLASS: "Illuminance", DEV_SIG_ENT_MAP_ID: "sensor.hivehome_com_mot003_illuminance", }, ("sensor", "00:11:22:33:44:55:66:77-6-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.hivehome_com_mot003_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-6-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.hivehome_com_mot003_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-6-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.hivehome_com_mot003_lqi", }, @@ -1105,7 +1105,7 @@ DEVICES = [ SIG_EP_PROFILE: 41440, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_bulb_e12_ws_opal_600lm_identify", "light.ikea_of_sweden_tradfri_bulb_e12_ws_opal_600lm_light", @@ -1114,28 +1114,28 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level", "light_color"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level", "light_color"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: ( "light.ikea_of_sweden_tradfri_bulb_e12_ws_opal_600lm_light" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_bulb_e12_ws_opal_600lm_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e12_ws_opal_600lm_rssi" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e12_ws_opal_600lm_lqi" @@ -1157,7 +1157,7 @@ DEVICES = [ SIG_EP_PROFILE: 49246, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_bulb_e26_cws_opal_600lm_identify", "light.ikea_of_sweden_tradfri_bulb_e26_cws_opal_600lm_light", @@ -1166,28 +1166,28 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level", "light_color"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level", "light_color"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: ( "light.ikea_of_sweden_tradfri_bulb_e26_cws_opal_600lm_light" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_bulb_e26_cws_opal_600lm_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e26_cws_opal_600lm_rssi" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e26_cws_opal_600lm_lqi" @@ -1209,7 +1209,7 @@ DEVICES = [ SIG_EP_PROFILE: 49246, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_bulb_e26_w_opal_1000lm_identify", "light.ikea_of_sweden_tradfri_bulb_e26_w_opal_1000lm_light", @@ -1218,28 +1218,28 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: ( "light.ikea_of_sweden_tradfri_bulb_e26_w_opal_1000lm_light" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_bulb_e26_w_opal_1000lm_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e26_w_opal_1000lm_rssi" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e26_w_opal_1000lm_lqi" @@ -1261,7 +1261,7 @@ DEVICES = [ SIG_EP_PROFILE: 49246, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_bulb_e26_ws_opal_980lm_identify", "light.ikea_of_sweden_tradfri_bulb_e26_ws_opal_980lm_light", @@ -1270,28 +1270,28 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level", "light_color"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level", "light_color"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: ( "light.ikea_of_sweden_tradfri_bulb_e26_ws_opal_980lm_light" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_bulb_e26_ws_opal_980lm_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e26_ws_opal_980lm_rssi" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e26_ws_opal_980lm_lqi" @@ -1313,7 +1313,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_bulb_e26_opal_1000lm_identify", "light.ikea_of_sweden_tradfri_bulb_e26_opal_1000lm_light", @@ -1322,28 +1322,28 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: ( "light.ikea_of_sweden_tradfri_bulb_e26_opal_1000lm_light" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_bulb_e26_opal_1000lm_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e26_opal_1000lm_rssi" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_bulb_e26_opal_1000lm_lqi" @@ -1365,7 +1365,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_control_outlet_identify", "switch.ikea_of_sweden_tradfri_control_outlet_switch", @@ -1374,26 +1374,26 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("switch", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: ( "switch.ikea_of_sweden_tradfri_control_outlet_switch" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_control_outlet_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_control_outlet_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_control_outlet_lqi", }, @@ -1413,7 +1413,7 @@ DEVICES = [ SIG_EP_PROFILE: 49246, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_motion_sensor_identify", "sensor.ikea_of_sweden_tradfri_motion_sensor_battery", @@ -1423,31 +1423,31 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_motion_sensor_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_motion_sensor_battery" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_motion_sensor_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_motion_sensor_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-1-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Motion", DEV_SIG_ENT_MAP_ID: ( "binary_sensor.ikea_of_sweden_tradfri_motion_sensor_motion" @@ -1469,7 +1469,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0019", "1:0x0102"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0019", "1:0x0102"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_on_off_switch_identify", "sensor.ikea_of_sweden_tradfri_on_off_switch_battery", @@ -1478,26 +1478,26 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_on_off_switch_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_on_off_switch_battery" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_on_off_switch_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_on_off_switch_lqi", }, @@ -1517,7 +1517,7 @@ DEVICES = [ SIG_EP_PROFILE: 49246, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0006", "1:0x0008", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0006", "1:0x0008", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_remote_control_identify", "sensor.ikea_of_sweden_tradfri_remote_control_battery", @@ -1526,26 +1526,26 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_remote_control_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_remote_control_battery" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_remote_control_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_remote_control_lqi", }, @@ -1572,7 +1572,7 @@ DEVICES = [ SIG_EP_PROFILE: 41440, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_signal_repeater_identify", "sensor.ikea_of_sweden_tradfri_signal_repeater_rssi", @@ -1580,21 +1580,21 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_signal_repeater_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_signal_repeater_rssi" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_signal_repeater_lqi", }, @@ -1614,7 +1614,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.ikea_of_sweden_tradfri_wireless_dimmer_identify", "sensor.ikea_of_sweden_tradfri_wireless_dimmer_battery", @@ -1623,28 +1623,28 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.ikea_of_sweden_tradfri_wireless_dimmer_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_wireless_dimmer_battery" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: ( "sensor.ikea_of_sweden_tradfri_wireless_dimmer_rssi" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ikea_of_sweden_tradfri_wireless_dimmer_lqi", }, @@ -1671,7 +1671,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019", "2:0x0006", "2:0x0008"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019", "2:0x0006", "2:0x0008"], DEV_SIG_ENTITIES: [ "button.jasco_products_45852_identify", "sensor.jasco_products_45852_instantaneous_demand", @@ -1682,32 +1682,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.jasco_products_45852_light", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.jasco_products_45852_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45852_instantaneous_demand", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45852_summation_delivered", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45852_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45852_lqi", }, @@ -1734,7 +1734,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019", "2:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019", "2:0x0006"], DEV_SIG_ENTITIES: [ "button.jasco_products_45856_identify", "light.jasco_products_45856_light", @@ -1745,32 +1745,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.jasco_products_45856_light", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.jasco_products_45856_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45856_instantaneous_demand", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45856_summation_delivered", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45856_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45856_lqi", }, @@ -1797,7 +1797,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019", "2:0x0006", "2:0x0008"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019", "2:0x0006", "2:0x0008"], DEV_SIG_ENTITIES: [ "button.jasco_products_45857_identify", "light.jasco_products_45857_light", @@ -1808,32 +1808,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.jasco_products_45857_light", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.jasco_products_45857_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45857_instantaneous_demand", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45857_summation_delivered", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45857_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45857_lqi", }, @@ -1853,7 +1853,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.keen_home_inc_sv02_610_mp_1_3_identify", "sensor.keen_home_inc_sv02_610_mp_1_3_battery", @@ -1865,37 +1865,37 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.keen_home_inc_sv02_610_mp_1_3_identify", }, ("cover", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["level", "on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["level", "on_off"], DEV_SIG_ENT_MAP_CLASS: "KeenVent", DEV_SIG_ENT_MAP_ID: "cover.keen_home_inc_sv02_610_mp_1_3_keenvent", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_610_mp_1_3_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1027"): { - DEV_SIG_CHANNELS: ["pressure"], + DEV_SIG_CLUSTER_HANDLERS: ["pressure"], DEV_SIG_ENT_MAP_CLASS: "Pressure", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_610_mp_1_3_pressure", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_610_mp_1_3_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_610_mp_1_3_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_610_mp_1_3_lqi", }, @@ -1915,7 +1915,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.keen_home_inc_sv02_612_mp_1_2_identify", "sensor.keen_home_inc_sv02_612_mp_1_2_battery", @@ -1927,37 +1927,37 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.keen_home_inc_sv02_612_mp_1_2_identify", }, ("cover", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["level", "on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["level", "on_off"], DEV_SIG_ENT_MAP_CLASS: "KeenVent", DEV_SIG_ENT_MAP_ID: "cover.keen_home_inc_sv02_612_mp_1_2_keenvent", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_2_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1027"): { - DEV_SIG_CHANNELS: ["pressure"], + DEV_SIG_CLUSTER_HANDLERS: ["pressure"], DEV_SIG_ENT_MAP_CLASS: "Pressure", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_2_pressure", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_2_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_2_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_2_lqi", }, @@ -1977,7 +1977,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.keen_home_inc_sv02_612_mp_1_3_identify", "sensor.keen_home_inc_sv02_612_mp_1_3_battery", @@ -1989,37 +1989,37 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.keen_home_inc_sv02_612_mp_1_3_identify", }, ("cover", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["level", "on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["level", "on_off"], DEV_SIG_ENT_MAP_CLASS: "KeenVent", DEV_SIG_ENT_MAP_ID: "cover.keen_home_inc_sv02_612_mp_1_3_keenvent", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_3_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1027"): { - DEV_SIG_CHANNELS: ["pressure"], + DEV_SIG_CLUSTER_HANDLERS: ["pressure"], DEV_SIG_ENT_MAP_CLASS: "Pressure", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_3_pressure", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_3_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_3_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.keen_home_inc_sv02_612_mp_1_3_lqi", }, @@ -2039,7 +2039,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.king_of_fans_inc_hbuniversalcfremote_identify", "light.king_of_fans_inc_hbuniversalcfremote_light", @@ -2049,29 +2049,29 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.king_of_fans_inc_hbuniversalcfremote_light", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: ( "button.king_of_fans_inc_hbuniversalcfremote_identify" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.king_of_fans_inc_hbuniversalcfremote_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.king_of_fans_inc_hbuniversalcfremote_lqi", }, ("fan", "00:11:22:33:44:55:66:77-1-514"): { - DEV_SIG_CHANNELS: ["fan"], + DEV_SIG_CLUSTER_HANDLERS: ["fan"], DEV_SIG_ENT_MAP_CLASS: "ZhaFan", DEV_SIG_ENT_MAP_ID: "fan.king_of_fans_inc_hbuniversalcfremote_fan", }, @@ -2091,7 +2091,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0019", "1:0x0300"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0019", "1:0x0300"], DEV_SIG_ENTITIES: [ "button.lds_zbt_cctswitch_d0001_identify", "sensor.lds_zbt_cctswitch_d0001_battery", @@ -2100,22 +2100,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lds_zbt_cctswitch_d0001_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lds_zbt_cctswitch_d0001_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lds_zbt_cctswitch_d0001_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lds_zbt_cctswitch_d0001_lqi", }, @@ -2135,7 +2135,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.ledvance_a19_rgbw_identify", "light.ledvance_a19_rgbw_light", @@ -2144,22 +2144,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level", "light_color"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level", "light_color"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.ledvance_a19_rgbw_light", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.ledvance_a19_rgbw_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.ledvance_a19_rgbw_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ledvance_a19_rgbw_lqi", }, @@ -2179,7 +2179,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.ledvance_flex_rgbw_identify", "light.ledvance_flex_rgbw_light", @@ -2188,22 +2188,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level", "light_color"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level", "light_color"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.ledvance_flex_rgbw_light", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.ledvance_flex_rgbw_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.ledvance_flex_rgbw_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ledvance_flex_rgbw_lqi", }, @@ -2223,7 +2223,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.ledvance_plug_identify", "switch.ledvance_plug_switch", @@ -2232,22 +2232,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("switch", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.ledvance_plug_switch", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.ledvance_plug_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.ledvance_plug_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ledvance_plug_lqi", }, @@ -2267,7 +2267,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.ledvance_rt_rgbw_identify", "light.ledvance_rt_rgbw_light", @@ -2276,22 +2276,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level", "light_color"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level", "light_color"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.ledvance_rt_rgbw_light", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.ledvance_rt_rgbw_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.ledvance_rt_rgbw_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.ledvance_rt_rgbw_lqi", }, @@ -2332,7 +2332,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_plug_maus01_identify", "sensor.lumi_lumi_plug_maus01_active_power", @@ -2349,62 +2349,62 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("switch", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.lumi_lumi_plug_maus01_switch", }, ("sensor", "00:11:22:33:44:55:66:77-1-2"): { - DEV_SIG_CHANNELS: ["device_temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["device_temperature"], DEV_SIG_ENT_MAP_CLASS: "DeviceTemperature", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_device_temperature", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_plug_maus01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_apparent_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_plug_maus01_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-100-15"): { - DEV_SIG_CHANNELS: ["binary_input"], + DEV_SIG_CLUSTER_HANDLERS: ["binary_input"], DEV_SIG_ENT_MAP_CLASS: "BinaryInput", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_plug_maus01_binaryinput", }, @@ -2431,7 +2431,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_relay_c2acn01_identify", "light.lumi_lumi_relay_c2acn01_light", @@ -2448,62 +2448,62 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.lumi_lumi_relay_c2acn01_light", }, ("sensor", "00:11:22:33:44:55:66:77-1-2"): { - DEV_SIG_CHANNELS: ["device_temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["device_temperature"], DEV_SIG_ENT_MAP_CLASS: "DeviceTemperature", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_device_temperature", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_relay_c2acn01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_apparent_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_lqi", }, ("light", "00:11:22:33:44:55:66:77-2"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.lumi_lumi_relay_c2acn01_light_2", }, @@ -2537,7 +2537,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_remote_b186acn01_identify", "sensor.lumi_lumi_remote_b186acn01_battery", @@ -2546,22 +2546,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_remote_b186acn01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b186acn01_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b186acn01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b186acn01_lqi", }, @@ -2595,7 +2595,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_remote_b286acn01_identify", "sensor.lumi_lumi_remote_b286acn01_battery", @@ -2604,22 +2604,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_remote_b286acn01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b286acn01_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b286acn01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b286acn01_lqi", }, @@ -2674,7 +2674,7 @@ DEVICES = [ SIG_EP_PROFILE: -1, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0300"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0300"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_remote_b286opcn01_identify", "sensor.lumi_lumi_remote_b286opcn01_rssi", @@ -2682,17 +2682,17 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_remote_b286opcn01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b286opcn01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b286opcn01_lqi", }, @@ -2747,7 +2747,7 @@ DEVICES = [ SIG_EP_PROFILE: -1, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0300", "2:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0300", "2:0x0006"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_remote_b486opcn01_identify", "sensor.lumi_lumi_remote_b486opcn01_rssi", @@ -2755,17 +2755,17 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_remote_b486opcn01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b486opcn01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b486opcn01_lqi", }, @@ -2785,7 +2785,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0300"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0300"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_remote_b686opcn01_identify", "sensor.lumi_lumi_remote_b686opcn01_rssi", @@ -2793,17 +2793,17 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_remote_b686opcn01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b686opcn01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b686opcn01_lqi", }, @@ -2858,7 +2858,7 @@ DEVICES = [ SIG_EP_PROFILE: None, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0300", "2:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0300", "2:0x0006"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_remote_b686opcn01_identify", "sensor.lumi_lumi_remote_b686opcn01_rssi", @@ -2866,17 +2866,17 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_remote_b686opcn01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b686opcn01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_remote_b686opcn01_lqi", }, @@ -2896,7 +2896,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["8:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["8:0x0006"], DEV_SIG_ENTITIES: [ "light.lumi_lumi_router_light", "binary_sensor.lumi_lumi_router_opening", @@ -2905,22 +2905,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-8"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.lumi_lumi_router_light", }, ("sensor", "00:11:22:33:44:55:66:77-8-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_router_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-8-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_router_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-8-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Opening", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_router_opening", }, @@ -2940,7 +2940,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["8:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["8:0x0006"], DEV_SIG_ENTITIES: [ "light.lumi_lumi_router_light", "binary_sensor.lumi_lumi_router_opening", @@ -2949,22 +2949,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-8"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.lumi_lumi_router_light", }, ("sensor", "00:11:22:33:44:55:66:77-8-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_router_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-8-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_router_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-8-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Opening", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_router_opening", }, @@ -2984,7 +2984,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["8:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["8:0x0006"], DEV_SIG_ENTITIES: [ "light.lumi_lumi_router_light", "binary_sensor.lumi_lumi_router_opening", @@ -2993,22 +2993,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-8"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.lumi_lumi_router_light", }, ("sensor", "00:11:22:33:44:55:66:77-8-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_router_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-8-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_router_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-8-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Opening", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_router_opening", }, @@ -3028,7 +3028,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sen_ill_mgl01_identify", "sensor.lumi_lumi_sen_ill_mgl01_illuminance", @@ -3037,22 +3037,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sen_ill_mgl01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1024"): { - DEV_SIG_CHANNELS: ["illuminance"], + DEV_SIG_CLUSTER_HANDLERS: ["illuminance"], DEV_SIG_ENT_MAP_CLASS: "Illuminance", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sen_ill_mgl01_illuminance", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sen_ill_mgl01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sen_ill_mgl01_lqi", }, @@ -3086,7 +3086,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_86sw1_identify", "sensor.lumi_lumi_sensor_86sw1_battery", @@ -3095,22 +3095,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_86sw1_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_86sw1_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_86sw1_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_86sw1_lqi", }, @@ -3144,7 +3144,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_cube_aqgl01_identify", "sensor.lumi_lumi_sensor_cube_aqgl01_battery", @@ -3153,22 +3153,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_cube_aqgl01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_cube_aqgl01_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_cube_aqgl01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_cube_aqgl01_lqi", }, @@ -3202,7 +3202,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019", "2:0x0005", "3:0x0005"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_ht_identify", "sensor.lumi_lumi_sensor_ht_battery", @@ -3213,32 +3213,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_ht_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_ht_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_ht_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_ht_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_ht_lqi", }, ("sensor", "00:11:22:33:44:55:66:77-1-1029"): { - DEV_SIG_CHANNELS: ["humidity"], + DEV_SIG_CLUSTER_HANDLERS: ["humidity"], DEV_SIG_ENT_MAP_CLASS: "Humidity", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_ht_humidity", }, @@ -3258,7 +3258,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0006", "1:0x0008", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0006", "1:0x0008", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_magnet_identify", "sensor.lumi_lumi_sensor_magnet_battery", @@ -3268,27 +3268,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_magnet_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_magnet_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_magnet_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_magnet_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-1-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Opening", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_sensor_magnet_opening", }, @@ -3308,7 +3308,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_magnet_aq2_identify", "sensor.lumi_lumi_sensor_magnet_aq2_battery", @@ -3318,27 +3318,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_magnet_aq2_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_magnet_aq2_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_magnet_aq2_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_magnet_aq2_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-1-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Opening", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_sensor_magnet_aq2_opening", }, @@ -3358,7 +3358,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_motion_aq2_identify", "sensor.lumi_lumi_sensor_motion_aq2_battery", @@ -3370,39 +3370,39 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1030"): { - DEV_SIG_CHANNELS: ["occupancy"], + DEV_SIG_CLUSTER_HANDLERS: ["occupancy"], DEV_SIG_ENT_MAP_CLASS: "Occupancy", DEV_SIG_ENT_MAP_ID: ( "binary_sensor.lumi_lumi_sensor_motion_aq2_occupancy" ), }, ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_sensor_motion_aq2_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_motion_aq2_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_motion_aq2_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1024"): { - DEV_SIG_CHANNELS: ["illuminance"], + DEV_SIG_CLUSTER_HANDLERS: ["illuminance"], DEV_SIG_ENT_MAP_CLASS: "Illuminance", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_motion_aq2_illuminance", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_motion_aq2_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_motion_aq2_lqi", }, @@ -3422,7 +3422,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_smoke_identify", "sensor.lumi_lumi_sensor_smoke_battery", @@ -3432,27 +3432,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_sensor_smoke_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_smoke_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_smoke_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_smoke_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_smoke_lqi", }, @@ -3472,7 +3472,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0006", "1:0x0008", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0006", "1:0x0008", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_switch_identify", "sensor.lumi_lumi_sensor_switch_battery", @@ -3481,22 +3481,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_switch_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_lqi", }, @@ -3516,7 +3516,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006"], DEV_SIG_ENTITIES: [ "sensor.lumi_lumi_sensor_switch_aq2_battery", "sensor.lumi_lumi_sensor_switch_aq2_rssi", @@ -3524,17 +3524,17 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_aq2_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_aq2_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_aq2_lqi", }, @@ -3554,7 +3554,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006"], DEV_SIG_ENTITIES: [ "sensor.lumi_lumi_sensor_switch_aq3_battery", "sensor.lumi_lumi_sensor_switch_aq3_rssi", @@ -3562,17 +3562,17 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_aq3_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_aq3_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_switch_aq3_lqi", }, @@ -3592,7 +3592,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_sensor_wleak_aq1_identify", "sensor.lumi_lumi_sensor_wleak_aq1_battery", @@ -3603,34 +3603,34 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_sensor_wleak_aq1_iaszone", }, ("sensor", "00:11:22:33:44:55:66:77-1-2"): { - DEV_SIG_CHANNELS: ["device_temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["device_temperature"], DEV_SIG_ENT_MAP_CLASS: "DeviceTemperature", DEV_SIG_ENT_MAP_ID: ( "sensor.lumi_lumi_sensor_wleak_aq1_device_temperature" ), }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_sensor_wleak_aq1_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_wleak_aq1_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_wleak_aq1_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_sensor_wleak_aq1_lqi", }, @@ -3657,7 +3657,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0019", "2:0x0005"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0019", "2:0x0005"], DEV_SIG_ENTITIES: [ "button.lumi_lumi_vibration_aq1_identify", "sensor.lumi_lumi_vibration_aq1_battery", @@ -3668,32 +3668,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.lumi_lumi_vibration_aq1_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_vibration_aq1_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_vibration_aq1_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_vibration_aq1_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_vibration_aq1_lqi", }, ("lock", "00:11:22:33:44:55:66:77-1-257"): { - DEV_SIG_CHANNELS: ["door_lock"], + DEV_SIG_CLUSTER_HANDLERS: ["door_lock"], DEV_SIG_ENT_MAP_CLASS: "ZhaDoorLock", DEV_SIG_ENT_MAP_ID: "lock.lumi_lumi_vibration_aq1_doorlock", }, @@ -3713,7 +3713,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.lumi_lumi_weather_identify", "sensor.lumi_lumi_weather_battery", @@ -3725,37 +3725,37 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.lumi_lumi_weather_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_weather_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1027"): { - DEV_SIG_CHANNELS: ["pressure"], + DEV_SIG_CLUSTER_HANDLERS: ["pressure"], DEV_SIG_ENT_MAP_CLASS: "Pressure", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_weather_pressure", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_weather_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_weather_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_weather_lqi", }, ("sensor", "00:11:22:33:44:55:66:77-1-1029"): { - DEV_SIG_CHANNELS: ["humidity"], + DEV_SIG_CLUSTER_HANDLERS: ["humidity"], DEV_SIG_ENT_MAP_CLASS: "Humidity", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_weather_humidity", }, @@ -3775,7 +3775,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.nyce_3010_identify", "sensor.nyce_3010_battery", @@ -3785,27 +3785,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.nyce_3010_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.nyce_3010_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.nyce_3010_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.nyce_3010_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.nyce_3010_lqi", }, @@ -3825,7 +3825,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.nyce_3014_identify", "sensor.nyce_3014_battery", @@ -3835,27 +3835,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.nyce_3014_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.nyce_3014_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.nyce_3014_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.nyce_3014_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.nyce_3014_lqi", }, @@ -3882,7 +3882,7 @@ DEVICES = [ SIG_EP_PROFILE: 41440, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: ["1:0x0019"], DEV_SIG_ENT_MAP: {}, }, @@ -3900,7 +3900,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [], DEV_SIG_ENT_MAP: {}, }, @@ -3918,7 +3918,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["3:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["3:0x0019"], DEV_SIG_ENTITIES: [ "button.osram_lightify_a19_rgbw_identify", "light.osram_lightify_a19_rgbw_light", @@ -3927,22 +3927,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-3"): { - DEV_SIG_CHANNELS: ["on_off", "light_color", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "light_color", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.osram_lightify_a19_rgbw_light", }, ("button", "00:11:22:33:44:55:66:77-3-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.osram_lightify_a19_rgbw_identify", }, ("sensor", "00:11:22:33:44:55:66:77-3-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_a19_rgbw_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-3-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_a19_rgbw_lqi", }, @@ -3962,7 +3962,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0006", "1:0x0008", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0006", "1:0x0008", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.osram_lightify_dimming_switch_identify", "sensor.osram_lightify_dimming_switch_battery", @@ -3971,22 +3971,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.osram_lightify_dimming_switch_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_dimming_switch_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_dimming_switch_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_dimming_switch_lqi", }, @@ -4006,7 +4006,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["3:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["3:0x0019"], DEV_SIG_ENTITIES: [ "button.osram_lightify_flex_rgbw_identify", "light.osram_lightify_flex_rgbw_light", @@ -4015,22 +4015,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-3"): { - DEV_SIG_CHANNELS: ["on_off", "light_color", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "light_color", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.osram_lightify_flex_rgbw_light", }, ("button", "00:11:22:33:44:55:66:77-3-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.osram_lightify_flex_rgbw_identify", }, ("sensor", "00:11:22:33:44:55:66:77-3-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_flex_rgbw_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-3-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_flex_rgbw_lqi", }, @@ -4050,7 +4050,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["3:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["3:0x0019"], DEV_SIG_ENTITIES: [ "button.osram_lightify_rt_tunable_white_identify", "light.osram_lightify_rt_tunable_white_light", @@ -4065,64 +4065,64 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-3"): { - DEV_SIG_CHANNELS: ["on_off", "light_color", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "light_color", "level"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.osram_lightify_rt_tunable_white_light", }, ("button", "00:11:22:33:44:55:66:77-3-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.osram_lightify_rt_tunable_white_identify", }, ("sensor", "00:11:22:33:44:55:66:77-3-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: ( "sensor.osram_lightify_rt_tunable_white_active_power" ), }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: ( "sensor.osram_lightify_rt_tunable_white_apparent_power" ), }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: ( "sensor.osram_lightify_rt_tunable_white_rms_current" ), }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: ( "sensor.osram_lightify_rt_tunable_white_rms_voltage" ), }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: ( "sensor.osram_lightify_rt_tunable_white_ac_frequency" ), }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: ( "sensor.osram_lightify_rt_tunable_white_power_factor" ), }, ("sensor", "00:11:22:33:44:55:66:77-3-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_rt_tunable_white_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-3-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_lightify_rt_tunable_white_lqi", }, @@ -4142,7 +4142,7 @@ DEVICES = [ SIG_EP_PROFILE: 49246, }, }, - DEV_SIG_EVT_CHANNELS: ["3:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["3:0x0019"], DEV_SIG_ENTITIES: [ "button.osram_plug_01_identify", "sensor.osram_plug_01_active_power", @@ -4157,52 +4157,52 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("switch", "00:11:22:33:44:55:66:77-3"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.osram_plug_01_switch", }, ("button", "00:11:22:33:44:55:66:77-3-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.osram_plug_01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-3-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.osram_plug_01_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: "sensor.osram_plug_01_apparent_power", }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.osram_plug_01_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.osram_plug_01_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.osram_plug_01_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-3-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.osram_plug_01_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-3-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_plug_01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-3-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_plug_01_lqi", }, @@ -4257,7 +4257,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [ + DEV_SIG_EVT_CLUSTER_HANDLERS: [ "1:0x0005", "1:0x0006", "1:0x0008", @@ -4291,17 +4291,17 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.osram_switch_4x_lightify_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_switch_4x_lightify_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.osram_switch_4x_lightify_lqi", }, @@ -4328,7 +4328,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0006", "1:0x0008", "2:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0006", "1:0x0008", "2:0x0019"], DEV_SIG_ENTITIES: [ "button.philips_rwl020_identify", "sensor.philips_rwl020_battery", @@ -4338,27 +4338,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.philips_rwl020_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.philips_rwl020_lqi", }, ("binary_sensor", "00:11:22:33:44:55:66:77-2-15"): { - DEV_SIG_CHANNELS: ["binary_input"], + DEV_SIG_CLUSTER_HANDLERS: ["binary_input"], DEV_SIG_ENT_MAP_CLASS: "BinaryInput", DEV_SIG_ENT_MAP_ID: "binary_sensor.philips_rwl020_binaryinput", }, ("button", "00:11:22:33:44:55:66:77-2-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.philips_rwl020_identify", }, ("sensor", "00:11:22:33:44:55:66:77-2-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.philips_rwl020_battery", }, @@ -4378,7 +4378,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.samjin_button_identify", "sensor.samjin_button_battery", @@ -4389,32 +4389,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.samjin_button_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.samjin_button_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.samjin_button_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.samjin_button_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.samjin_button_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.samjin_button_lqi", }, @@ -4434,7 +4434,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.samjin_multi_identify", "sensor.samjin_multi_battery", @@ -4445,32 +4445,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.samjin_multi_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.samjin_multi_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.samjin_multi_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.samjin_multi_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.samjin_multi_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.samjin_multi_lqi", }, @@ -4490,7 +4490,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.samjin_water_identify", "sensor.samjin_water_battery", @@ -4501,32 +4501,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.samjin_water_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.samjin_water_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.samjin_water_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.samjin_water_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.samjin_water_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.samjin_water_lqi", }, @@ -4546,7 +4546,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0005", "1:0x0006", "1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0005", "1:0x0006", "1:0x0019"], DEV_SIG_ENTITIES: [ "button.securifi_ltd_unk_model_identify", "sensor.securifi_ltd_unk_model_active_power", @@ -4561,52 +4561,52 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.securifi_ltd_unk_model_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.securifi_ltd_unk_model_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: "sensor.securifi_ltd_unk_model_apparent_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.securifi_ltd_unk_model_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.securifi_ltd_unk_model_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.securifi_ltd_unk_model_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.securifi_ltd_unk_model_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.securifi_ltd_unk_model_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.securifi_ltd_unk_model_lqi", }, ("switch", "00:11:22:33:44:55:66:77-1-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.securifi_ltd_unk_model_switch", }, @@ -4626,7 +4626,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.sercomm_corp_sz_dws04n_sf_identify", "sensor.sercomm_corp_sz_dws04n_sf_battery", @@ -4637,32 +4637,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.sercomm_corp_sz_dws04n_sf_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sercomm_corp_sz_dws04n_sf_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_dws04n_sf_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_dws04n_sf_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_dws04n_sf_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_dws04n_sf_lqi", }, @@ -4689,7 +4689,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019", "2:0x0006"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019", "2:0x0006"], DEV_SIG_ENTITIES: [ "button.sercomm_corp_sz_esw01_identify", "sensor.sercomm_corp_sz_esw01_active_power", @@ -4706,62 +4706,62 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.sercomm_corp_sz_esw01_light", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sercomm_corp_sz_esw01_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_apparent_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_instantaneous_demand", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_summation_delivered", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_lqi", }, @@ -4781,7 +4781,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.sercomm_corp_sz_pir04_identify", "sensor.sercomm_corp_sz_pir04_battery", @@ -4793,37 +4793,37 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.sercomm_corp_sz_pir04_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sercomm_corp_sz_pir04_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_pir04_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1024"): { - DEV_SIG_CHANNELS: ["illuminance"], + DEV_SIG_CLUSTER_HANDLERS: ["illuminance"], DEV_SIG_ENT_MAP_CLASS: "Illuminance", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_pir04_illuminance", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_pir04_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_pir04_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_pir04_lqi", }, @@ -4843,7 +4843,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.sinope_technologies_rm3250zb_identify", "sensor.sinope_technologies_rm3250zb_active_power", @@ -4858,54 +4858,54 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sinope_technologies_rm3250zb_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_rm3250zb_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: ( "sensor.sinope_technologies_rm3250zb_apparent_power" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_rm3250zb_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_rm3250zb_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_rm3250zb_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_rm3250zb_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_rm3250zb_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_rm3250zb_lqi", }, ("switch", "00:11:22:33:44:55:66:77-1-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.sinope_technologies_rm3250zb_switch", }, @@ -4932,7 +4932,7 @@ DEVICES = [ SIG_EP_PROFILE: 49757, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.sinope_technologies_th1123zb_identify", "sensor.sinope_technologies_th1123zb_active_power", @@ -4949,64 +4949,64 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sinope_technologies_th1123zb_identify", }, ("climate", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["thermostat"], + DEV_SIG_CLUSTER_HANDLERS: ["thermostat"], DEV_SIG_ENT_MAP_CLASS: "Thermostat", DEV_SIG_ENT_MAP_ID: "climate.sinope_technologies_th1123zb_thermostat", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: ( "sensor.sinope_technologies_th1123zb_apparent_power" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_lqi", }, ("sensor", "00:11:22:33:44:55:66:77-1-513-hvac_action"): { - DEV_SIG_CHANNELS: ["thermostat"], + DEV_SIG_CLUSTER_HANDLERS: ["thermostat"], DEV_SIG_ENT_MAP_CLASS: "SinopeHVACAction", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1123zb_hvac_action", }, @@ -5033,7 +5033,7 @@ DEVICES = [ SIG_EP_PROFILE: 49757, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.sinope_technologies_th1124zb_identify", "sensor.sinope_technologies_th1124zb_active_power", @@ -5050,64 +5050,64 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sinope_technologies_th1124zb_identify", }, ("climate", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["thermostat"], + DEV_SIG_CLUSTER_HANDLERS: ["thermostat"], DEV_SIG_ENT_MAP_CLASS: "Thermostat", DEV_SIG_ENT_MAP_ID: "climate.sinope_technologies_th1124zb_thermostat", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: ( "sensor.sinope_technologies_th1124zb_apparent_power" ), }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_lqi", }, ("sensor", "00:11:22:33:44:55:66:77-1-513-hvac_action"): { - DEV_SIG_CHANNELS: ["thermostat"], + DEV_SIG_CLUSTER_HANDLERS: ["thermostat"], DEV_SIG_ENT_MAP_CLASS: "SinopeHVACAction", DEV_SIG_ENT_MAP_ID: "sensor.sinope_technologies_th1124zb_hvac_action", }, @@ -5127,7 +5127,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.smartthings_outletv4_identify", "sensor.smartthings_outletv4_active_power", @@ -5143,57 +5143,57 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-15"): { - DEV_SIG_CHANNELS: ["binary_input"], + DEV_SIG_CLUSTER_HANDLERS: ["binary_input"], DEV_SIG_ENT_MAP_CLASS: "BinaryInput", DEV_SIG_ENT_MAP_ID: "binary_sensor.smartthings_outletv4_binaryinput", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.smartthings_outletv4_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurement", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_outletv4_active_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-apparent_power"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementApparentPower", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_outletv4_apparent_power", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_current"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSCurrent", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_outletv4_rms_current", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-rms_voltage"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementRMSVoltage", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_outletv4_rms_voltage", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-ac_frequency"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementFrequency", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_outletv4_ac_frequency", }, ("sensor", "00:11:22:33:44:55:66:77-1-2820-power_factor"): { - DEV_SIG_CHANNELS: ["electrical_measurement"], + DEV_SIG_CLUSTER_HANDLERS: ["electrical_measurement"], DEV_SIG_ENT_MAP_CLASS: "ElectricalMeasurementPowerFactor", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_outletv4_power_factor", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_outletv4_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_outletv4_lqi", }, ("switch", "00:11:22:33:44:55:66:77-1-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.smartthings_outletv4_switch", }, @@ -5213,7 +5213,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.smartthings_tagv4_identify", "device_tracker.smartthings_tagv4_devicescanner", @@ -5223,27 +5223,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("device_tracker", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "ZHADeviceScannerEntity", DEV_SIG_ENT_MAP_ID: "device_tracker.smartthings_tagv4_devicescanner", }, ("binary_sensor", "00:11:22:33:44:55:66:77-1-15"): { - DEV_SIG_CHANNELS: ["binary_input"], + DEV_SIG_CLUSTER_HANDLERS: ["binary_input"], DEV_SIG_ENT_MAP_CLASS: "BinaryInput", DEV_SIG_ENT_MAP_ID: "binary_sensor.smartthings_tagv4_binaryinput", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.smartthings_tagv4_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_tagv4_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.smartthings_tagv4_lqi", }, @@ -5263,7 +5263,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.third_reality_inc_3rss007z_identify", "switch.third_reality_inc_3rss007z_switch", @@ -5272,22 +5272,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.third_reality_inc_3rss007z_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.third_reality_inc_3rss007z_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.third_reality_inc_3rss007z_lqi", }, ("switch", "00:11:22:33:44:55:66:77-1-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.third_reality_inc_3rss007z_switch", }, @@ -5307,7 +5307,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.third_reality_inc_3rss008z_identify", "sensor.third_reality_inc_3rss008z_battery", @@ -5317,27 +5317,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.third_reality_inc_3rss008z_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.third_reality_inc_3rss008z_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.third_reality_inc_3rss008z_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.third_reality_inc_3rss008z_lqi", }, ("switch", "00:11:22:33:44:55:66:77-1-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.third_reality_inc_3rss008z_switch", }, @@ -5357,7 +5357,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.visonic_mct_340_e_identify", "sensor.visonic_mct_340_e_battery", @@ -5368,32 +5368,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.visonic_mct_340_e_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.visonic_mct_340_e_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.visonic_mct_340_e_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.visonic_mct_340_e_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.visonic_mct_340_e_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.visonic_mct_340_e_lqi", }, @@ -5413,7 +5413,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.zen_within_zen_01_identify", "sensor.zen_within_zen_01_battery", @@ -5424,32 +5424,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.zen_within_zen_01_identify", }, ("climate", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["thermostat", "fan"], + DEV_SIG_CLUSTER_HANDLERS: ["thermostat", "fan"], DEV_SIG_ENT_MAP_CLASS: "ZenWithinThermostat", DEV_SIG_ENT_MAP_ID: "climate.zen_within_zen_01_zenwithinthermostat", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.zen_within_zen_01_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.zen_within_zen_01_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.zen_within_zen_01_lqi", }, ("sensor", "00:11:22:33:44:55:66:77-1-513-hvac_action"): { - DEV_SIG_CHANNELS: ["thermostat"], + DEV_SIG_CLUSTER_HANDLERS: ["thermostat"], DEV_SIG_ENT_MAP_CLASS: "ThermostatHVACAction", DEV_SIG_ENT_MAP_ID: "sensor.zen_within_zen_01_hvac_action", }, @@ -5490,7 +5490,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "light.tyzb01_ns1ndbww_ts0004_light", "light.tyzb01_ns1ndbww_ts0004_light_2", @@ -5501,32 +5501,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.tyzb01_ns1ndbww_ts0004_light", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.tyzb01_ns1ndbww_ts0004_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.tyzb01_ns1ndbww_ts0004_lqi", }, ("light", "00:11:22:33:44:55:66:77-2"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.tyzb01_ns1ndbww_ts0004_light_2", }, ("light", "00:11:22:33:44:55:66:77-3"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.tyzb01_ns1ndbww_ts0004_light_3", }, ("light", "00:11:22:33:44:55:66:77-4"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Light", DEV_SIG_ENT_MAP_ID: "light.tyzb01_ns1ndbww_ts0004_light_4", }, @@ -5546,7 +5546,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.netvox_z308e3ed_identify", "sensor.netvox_z308e3ed_battery", @@ -5556,27 +5556,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("binary_sensor", "00:11:22:33:44:55:66:77-1-1280"): { - DEV_SIG_CHANNELS: ["ias_zone"], + DEV_SIG_CLUSTER_HANDLERS: ["ias_zone"], DEV_SIG_ENT_MAP_CLASS: "IASZone", DEV_SIG_ENT_MAP_ID: "binary_sensor.netvox_z308e3ed_iaszone", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.netvox_z308e3ed_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.netvox_z308e3ed_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.netvox_z308e3ed_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.netvox_z308e3ed_lqi", }, @@ -5596,7 +5596,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.sengled_e11_g13_identify", "light.sengled_e11_g13_mintransitionlight", @@ -5607,32 +5607,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level"], DEV_SIG_ENT_MAP_CLASS: "MinTransitionLight", DEV_SIG_ENT_MAP_ID: "light.sengled_e11_g13_mintransitionlight", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sengled_e11_g13_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e11_g13_instantaneous_demand", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e11_g13_summation_delivered", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e11_g13_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e11_g13_lqi", }, @@ -5652,7 +5652,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.sengled_e12_n14_identify", "light.sengled_e12_n14_mintransitionlight", @@ -5663,32 +5663,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level"], DEV_SIG_ENT_MAP_CLASS: "MinTransitionLight", DEV_SIG_ENT_MAP_ID: "light.sengled_e12_n14_mintransitionlight", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sengled_e12_n14_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e12_n14_instantaneous_demand", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e12_n14_summation_delivered", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e12_n14_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e12_n14_lqi", }, @@ -5708,7 +5708,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: ["1:0x0019"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["1:0x0019"], DEV_SIG_ENTITIES: [ "button.sengled_z01_a19nae26_identify", "light.sengled_z01_a19nae26_mintransitionlight", @@ -5719,32 +5719,32 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("light", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["on_off", "level", "light_color"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off", "level", "light_color"], DEV_SIG_ENT_MAP_CLASS: "MinTransitionLight", DEV_SIG_ENT_MAP_ID: "light.sengled_z01_a19nae26_mintransitionlight", }, ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.sengled_z01_a19nae26_identify", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", DEV_SIG_ENT_MAP_ID: "sensor.sengled_z01_a19nae26_instantaneous_demand", }, ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_delivered"): { - DEV_SIG_CHANNELS: ["smartenergy_metering"], + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.sengled_z01_a19nae26_summation_delivered", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.sengled_z01_a19nae26_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.sengled_z01_a19nae26_lqi", }, @@ -5764,7 +5764,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "button.unk_manufacturer_unk_model_identify", "cover.unk_manufacturer_unk_model_shade", @@ -5773,22 +5773,22 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("button", "00:11:22:33:44:55:66:77-1-3"): { - DEV_SIG_CHANNELS: ["identify"], + DEV_SIG_CLUSTER_HANDLERS: ["identify"], DEV_SIG_ENT_MAP_CLASS: "ZHAIdentifyButton", DEV_SIG_ENT_MAP_ID: "button.unk_manufacturer_unk_model_identify", }, ("cover", "00:11:22:33:44:55:66:77-1"): { - DEV_SIG_CHANNELS: ["level", "on_off", "shade"], + DEV_SIG_CLUSTER_HANDLERS: ["level", "on_off", "shade"], DEV_SIG_ENT_MAP_CLASS: "Shade", DEV_SIG_ENT_MAP_ID: "cover.unk_manufacturer_unk_model_shade", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.unk_manufacturer_unk_model_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.unk_manufacturer_unk_model_lqi", }, @@ -5913,7 +5913,7 @@ DEVICES = [ SIG_EP_PROFILE: 49413, }, }, - DEV_SIG_EVT_CHANNELS: ["232:0x0008"], + DEV_SIG_EVT_CLUSTER_HANDLERS: ["232:0x0008"], DEV_SIG_ENTITIES: [ "number.digi_xbee3_number", "number.digi_xbee3_number_2", @@ -5940,112 +5940,112 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("sensor", "00:11:22:33:44:55:66:77-208-12"): { - DEV_SIG_CHANNELS: ["analog_input"], + DEV_SIG_CLUSTER_HANDLERS: ["analog_input"], DEV_SIG_ENT_MAP_CLASS: "AnalogInput", DEV_SIG_ENT_MAP_ID: "sensor.digi_xbee3_analoginput", }, ("switch", "00:11:22:33:44:55:66:77-208-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch", }, ("sensor", "00:11:22:33:44:55:66:77-209-12"): { - DEV_SIG_CHANNELS: ["analog_input"], + DEV_SIG_CLUSTER_HANDLERS: ["analog_input"], DEV_SIG_ENT_MAP_CLASS: "AnalogInput", DEV_SIG_ENT_MAP_ID: "sensor.digi_xbee3_analoginput_2", }, ("switch", "00:11:22:33:44:55:66:77-209-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_2", }, ("sensor", "00:11:22:33:44:55:66:77-210-12"): { - DEV_SIG_CHANNELS: ["analog_input"], + DEV_SIG_CLUSTER_HANDLERS: ["analog_input"], DEV_SIG_ENT_MAP_CLASS: "AnalogInput", DEV_SIG_ENT_MAP_ID: "sensor.digi_xbee3_analoginput_3", }, ("switch", "00:11:22:33:44:55:66:77-210-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_3", }, ("sensor", "00:11:22:33:44:55:66:77-211-12"): { - DEV_SIG_CHANNELS: ["analog_input"], + DEV_SIG_CLUSTER_HANDLERS: ["analog_input"], DEV_SIG_ENT_MAP_CLASS: "AnalogInput", DEV_SIG_ENT_MAP_ID: "sensor.digi_xbee3_analoginput_4", }, ("switch", "00:11:22:33:44:55:66:77-211-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_4", }, ("switch", "00:11:22:33:44:55:66:77-212-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_5", }, ("switch", "00:11:22:33:44:55:66:77-213-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_6", }, ("switch", "00:11:22:33:44:55:66:77-214-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_7", }, ("sensor", "00:11:22:33:44:55:66:77-215-12"): { - DEV_SIG_CHANNELS: ["analog_input"], + DEV_SIG_CLUSTER_HANDLERS: ["analog_input"], DEV_SIG_ENT_MAP_CLASS: "AnalogInput", DEV_SIG_ENT_MAP_ID: "sensor.digi_xbee3_analoginput_5", }, ("switch", "00:11:22:33:44:55:66:77-215-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_8", }, ("switch", "00:11:22:33:44:55:66:77-216-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_9", }, ("switch", "00:11:22:33:44:55:66:77-217-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_10", }, ("number", "00:11:22:33:44:55:66:77-218-13"): { - DEV_SIG_CHANNELS: ["analog_output"], + DEV_SIG_CLUSTER_HANDLERS: ["analog_output"], DEV_SIG_ENT_MAP_CLASS: "ZhaNumber", DEV_SIG_ENT_MAP_ID: "number.digi_xbee3_number", }, ("switch", "00:11:22:33:44:55:66:77-218-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_11", }, ("switch", "00:11:22:33:44:55:66:77-219-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_12", }, ("number", "00:11:22:33:44:55:66:77-219-13"): { - DEV_SIG_CHANNELS: ["analog_output"], + DEV_SIG_CLUSTER_HANDLERS: ["analog_output"], DEV_SIG_ENT_MAP_CLASS: "ZhaNumber", DEV_SIG_ENT_MAP_ID: "number.digi_xbee3_number_2", }, ("switch", "00:11:22:33:44:55:66:77-220-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_13", }, ("switch", "00:11:22:33:44:55:66:77-221-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_14", }, ("switch", "00:11:22:33:44:55:66:77-222-6"): { - DEV_SIG_CHANNELS: ["on_off"], + DEV_SIG_CLUSTER_HANDLERS: ["on_off"], DEV_SIG_ENT_MAP_CLASS: "Switch", DEV_SIG_ENT_MAP_ID: "switch.digi_xbee3_switch_15", }, @@ -6065,7 +6065,7 @@ DEVICES = [ SIG_EP_PROFILE: 260, }, }, - DEV_SIG_EVT_CHANNELS: [], + DEV_SIG_EVT_CLUSTER_HANDLERS: [], DEV_SIG_ENTITIES: [ "sensor.efektalab_ru_efekta_pws_battery", "sensor.efektalab_ru_efekta_pws_soil_moisture", @@ -6075,27 +6075,27 @@ DEVICES = [ ], DEV_SIG_ENT_MAP: { ("sensor", "00:11:22:33:44:55:66:77-1-1"): { - DEV_SIG_CHANNELS: ["power"], + DEV_SIG_CLUSTER_HANDLERS: ["power"], DEV_SIG_ENT_MAP_CLASS: "Battery", DEV_SIG_ENT_MAP_ID: "sensor.efektalab_ru_efekta_pws_battery", }, ("sensor", "00:11:22:33:44:55:66:77-1-1032"): { - DEV_SIG_CHANNELS: ["soil_moisture"], + DEV_SIG_CLUSTER_HANDLERS: ["soil_moisture"], DEV_SIG_ENT_MAP_CLASS: "SoilMoisture", DEV_SIG_ENT_MAP_ID: "sensor.efektalab_ru_efekta_pws_soil_moisture", }, ("sensor", "00:11:22:33:44:55:66:77-1-1026"): { - DEV_SIG_CHANNELS: ["temperature"], + DEV_SIG_CLUSTER_HANDLERS: ["temperature"], DEV_SIG_ENT_MAP_CLASS: "Temperature", DEV_SIG_ENT_MAP_ID: "sensor.efektalab_ru_efekta_pws_temperature", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", DEV_SIG_ENT_MAP_ID: "sensor.efektalab_ru_efekta_pws_rssi", }, ("sensor", "00:11:22:33:44:55:66:77-1-0-lqi"): { - DEV_SIG_CHANNELS: ["basic"], + DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "LQISensor", DEV_SIG_ENT_MAP_ID: "sensor.efektalab_ru_efekta_pws_lqi", },