From 991afccbd4b8c9396b790eb3998fc355b8ddf43f Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Sat, 21 Mar 2020 19:59:32 -0400 Subject: [PATCH] Refactor ZHA EventChannels (#32709) * Refactor EventChannels. * Rename EventRelayChannel. * Fully rename EventRelayChannel. - update docstrings - rename all references from "relay" to "client" * Remove CHANNEL_NAME. * Update stale docstring. --- .../components/zha/core/channels/__init__.py | 28 +++++++++---------- .../components/zha/core/channels/base.py | 10 ++----- .../components/zha/core/channels/general.py | 26 ++++++++++++++--- .../components/zha/core/channels/lighting.py | 10 +++++-- .../components/zha/core/registries.py | 2 +- homeassistant/components/zha/core/typing.py | 4 +-- tests/components/zha/test_channels.py | 14 ++++++---- tests/components/zha/test_device_action.py | 2 +- tests/components/zha/test_device_trigger.py | 2 +- tests/components/zha/test_discover.py | 4 +-- 10 files changed, 62 insertions(+), 40 deletions(-) diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index a4848fbaa63..91a23e17f12 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -163,12 +163,12 @@ class ChannelPool: self._channels: Channels = channels self._claimed_channels: ChannelsDict = {} self._id: int = ep_id - self._relay_channels: Dict[str, zha_typing.EventRelayChannelType] = {} + self._client_channels: Dict[str, zha_typing.ClientChannelType] = {} self._unique_id: str = f"{channels.unique_id}-{ep_id}" @property def all_channels(self) -> ChannelsDict: - """All channels of an endpoint.""" + """All server channels of an endpoint.""" return self._all_channels @property @@ -176,6 +176,11 @@ class ChannelPool: """Channels in use.""" return self._claimed_channels + @property + def client_channels(self) -> Dict[str, zha_typing.ClientChannelType]: + """Return a dict of client channels.""" + return self._client_channels + @property def endpoint(self) -> zha_typing.ZigpyEndpointType: """Return endpoint of zigpy device.""" @@ -216,11 +221,6 @@ class ChannelPool: """Return device model.""" return self._channels.zha_device.model - @property - def relay_channels(self) -> Dict[str, zha_typing.EventRelayChannelType]: - """Return a dict of event relay channels.""" - return self._relay_channels - @property def skip_configuration(self) -> bool: """Return True if device does not require channel configuration.""" @@ -236,7 +236,7 @@ class ChannelPool: """Create new channels for an endpoint.""" pool = cls(channels, ep_id) pool.add_all_channels() - pool.add_relay_channels() + pool.add_client_channels() zha_disc.PROBE.discover_entities(pool) return pool @@ -270,13 +270,13 @@ class ChannelPool: self.all_channels[channel.id] = channel @callback - def add_relay_channels(self) -> None: - """Create relay channels for all output clusters if in the registry.""" - for cluster_id in zha_regs.EVENT_RELAY_CLUSTERS: + 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 = base.EventRelayChannel(cluster, self) - self.relay_channels[channel.id] = channel + channel = channel_class(cluster, self) + self.client_channels[channel.id] = channel async def async_initialize(self, from_cache: bool = False) -> None: """Initialize claimed channels.""" @@ -293,7 +293,7 @@ class ChannelPool: async with self._channels.semaphore: return await coro - channels = [*self.claimed_channels.values(), *self.relay_channels.values()] + channels = [*self.claimed_channels.values(), *self.client_channels.values()] tasks = [_throttle(getattr(ch, func_name)(*args)) for ch in channels] results = await asyncio.gather(*tasks, return_exceptions=True) for channel, outcome in zip(channels, results): diff --git a/homeassistant/components/zha/core/channels/base.py b/homeassistant/components/zha/core/channels/base.py index dfe564ec2c1..e718e688c50 100644 --- a/homeassistant/components/zha/core/channels/base.py +++ b/homeassistant/components/zha/core/channels/base.py @@ -19,7 +19,6 @@ from ..const import ( ATTR_COMMAND, ATTR_UNIQUE_ID, ATTR_VALUE, - CHANNEL_EVENT_RELAY, CHANNEL_ZDO, REPORT_CONFIG_MAX_INT, REPORT_CONFIG_MIN_INT, @@ -78,7 +77,6 @@ class ChannelStatus(Enum): class ZigbeeChannel(LogMixin): """Base channel for a Zigbee cluster.""" - CHANNEL_NAME = None REPORT_CONFIG = () def __init__( @@ -87,8 +85,6 @@ class ZigbeeChannel(LogMixin): """Initialize ZigbeeChannel.""" self._generic_id = f"channel_0x{cluster.cluster_id:04x}" self._channel_name = getattr(cluster, "ep_attribute", self._generic_id) - if self.CHANNEL_NAME: - self._channel_name = self.CHANNEL_NAME self._ch_pool = ch_pool self._cluster = cluster self._id = f"{ch_pool.id}:0x{cluster.cluster_id:04x}" @@ -361,10 +357,8 @@ class ZDOChannel(LogMixin): _LOGGER.log(level, msg, *args) -class EventRelayChannel(ZigbeeChannel): - """Event relay that can be attached to zigbee clusters.""" - - CHANNEL_NAME = CHANNEL_EVENT_RELAY +class ClientChannel(ZigbeeChannel): + """Channel listener for Zigbee client (output) clusters.""" @callback def attribute_updated(self, attrid, value): diff --git a/homeassistant/components/zha/core/channels/general.py b/homeassistant/components/zha/core/channels/general.py index 783188248f3..ffd5a03fc13 100644 --- a/homeassistant/components/zha/core/channels/general.py +++ b/homeassistant/components/zha/core/channels/general.py @@ -20,7 +20,7 @@ from ..const import ( SIGNAL_SET_LEVEL, SIGNAL_STATE_ATTR, ) -from .base import ZigbeeChannel, parse_and_log_command +from .base import ClientChannel, ZigbeeChannel, parse_and_log_command _LOGGER = logging.getLogger(__name__) @@ -166,8 +166,14 @@ 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): + """LevelControl client cluster.""" + + pass + + @registries.BINDABLE_CLUSTERS.register(general.LevelControl.cluster_id) -@registries.EVENT_RELAY_CLUSTERS.register(general.LevelControl.cluster_id) @registries.LIGHT_CLUSTERS.register(general.LevelControl.cluster_id) @registries.ZIGBEE_CHANNEL_REGISTRY.register(general.LevelControl.cluster_id) class LevelControlChannel(ZigbeeChannel): @@ -233,9 +239,15 @@ class MultistateValue(ZigbeeChannel): REPORT_CONFIG = [{"attr": "present_value", "config": REPORT_CONFIG_DEFAULT}] +@registries.CLIENT_CHANNELS_REGISTRY.register(general.OnOff.cluster_id) +class OnOffClientChannel(ClientChannel): + """OnOff client channel.""" + + pass + + @registries.BINARY_SENSOR_CLUSTERS.register(general.OnOff.cluster_id) @registries.BINDABLE_CLUSTERS.register(general.OnOff.cluster_id) -@registries.EVENT_RELAY_CLUSTERS.register(general.OnOff.cluster_id) @registries.LIGHT_CLUSTERS.register(general.OnOff.cluster_id) @registries.SWITCH_CLUSTERS.register(general.OnOff.cluster_id) @registries.ZIGBEE_CHANNEL_REGISTRY.register(general.OnOff.cluster_id) @@ -437,7 +449,13 @@ class RSSILocation(ZigbeeChannel): pass -@registries.EVENT_RELAY_CLUSTERS.register(general.Scenes.cluster_id) +@registries.CLIENT_CHANNELS_REGISTRY.register(general.Scenes.cluster_id) +class ScenesClientChannel(ClientChannel): + """Scenes channel.""" + + pass + + @registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Scenes.cluster_id) class Scenes(ZigbeeChannel): """Scenes channel.""" diff --git a/homeassistant/components/zha/core/channels/lighting.py b/homeassistant/components/zha/core/channels/lighting.py index 7dc98d04515..25f6c05d739 100644 --- a/homeassistant/components/zha/core/channels/lighting.py +++ b/homeassistant/components/zha/core/channels/lighting.py @@ -5,7 +5,7 @@ import zigpy.zcl.clusters.lighting as lighting from .. import registries, typing as zha_typing from ..const import REPORT_CONFIG_DEFAULT -from .base import ZigbeeChannel +from .base import ClientChannel, ZigbeeChannel _LOGGER = logging.getLogger(__name__) @@ -17,8 +17,14 @@ class Ballast(ZigbeeChannel): pass +@registries.CLIENT_CHANNELS_REGISTRY.register(lighting.Color.cluster_id) +class ColorClientChannel(ClientChannel): + """Color client channel.""" + + pass + + @registries.BINDABLE_CLUSTERS.register(lighting.Color.cluster_id) -@registries.EVENT_RELAY_CLUSTERS.register(lighting.Color.cluster_id) @registries.LIGHT_CLUSTERS.register(lighting.Color.cluster_id) @registries.ZIGBEE_CHANNEL_REGISTRY.register(lighting.Color.cluster_id) class ColorChannel(ZigbeeChannel): diff --git a/homeassistant/components/zha/core/registries.py b/homeassistant/components/zha/core/registries.py index 9aeb7832f63..0a1a81df5ff 100644 --- a/homeassistant/components/zha/core/registries.py +++ b/homeassistant/components/zha/core/registries.py @@ -123,9 +123,9 @@ DEVICE_CLASS = { DEVICE_CLASS = collections.defaultdict(dict, DEVICE_CLASS) DEVICE_TRACKER_CLUSTERS = SetRegistry() -EVENT_RELAY_CLUSTERS = SetRegistry() LIGHT_CLUSTERS = SetRegistry() OUTPUT_CHANNEL_ONLY_CLUSTERS = SetRegistry() +CLIENT_CHANNELS_REGISTRY = DictRegistry() RADIO_TYPES = { RadioType.deconz.name: { diff --git a/homeassistant/components/zha/core/typing.py b/homeassistant/components/zha/core/typing.py index fb397ea15ae..a1cbc9f0fef 100644 --- a/homeassistant/components/zha/core/typing.py +++ b/homeassistant/components/zha/core/typing.py @@ -12,7 +12,7 @@ CALLABLE_T = TypeVar("CALLABLE_T", bound=Callable) ChannelType = "ZigbeeChannel" ChannelsType = "Channels" ChannelPoolType = "ChannelPool" -EventRelayChannelType = "EventRelayChannel" +ClientChannelType = "ClientChannel" ZDOChannelType = "ZDOChannel" ZhaDeviceType = "ZHADevice" ZhaEntityType = "ZHAEntity" @@ -33,7 +33,7 @@ if TYPE_CHECKING: ChannelType = base_channels.ZigbeeChannel ChannelsType = channels.Channels ChannelPoolType = channels.ChannelPool - EventRelayChannelType = base_channels.EventRelayChannel + ClientChannelType = base_channels.ClientChannel ZDOChannelType = base_channels.ZDOChannel ZhaDeviceType = homeassistant.components.zha.core.device.ZHADevice ZhaEntityType = homeassistant.components.zha.entity.ZhaEntity diff --git a/tests/components/zha/test_channels.py b/tests/components/zha/test_channels.py index ec9c172430c..1196cdc3b40 100644 --- a/tests/components/zha/test_channels.py +++ b/tests/components/zha/test_channels.py @@ -274,7 +274,9 @@ def test_epch_claim_channels(channel): assert "1:0x0300" in ep_channels.claimed_channels -@mock.patch("homeassistant.components.zha.core.channels.ChannelPool.add_relay_channels") +@mock.patch( + "homeassistant.components.zha.core.channels.ChannelPool.add_client_channels" +) @mock.patch( "homeassistant.components.zha.core.discovery.PROBE.discover_entities", mock.MagicMock(), @@ -319,7 +321,9 @@ def test_ep_channels_all_channels(m1, zha_device_mock): assert "2:0x0300" in ep_channels.all_channels -@mock.patch("homeassistant.components.zha.core.channels.ChannelPool.add_relay_channels") +@mock.patch( + "homeassistant.components.zha.core.channels.ChannelPool.add_client_channels" +) @mock.patch( "homeassistant.components.zha.core.discovery.PROBE.discover_entities", mock.MagicMock(), @@ -387,14 +391,14 @@ async def test_ep_channels_configure(channel): ep_channels = zha_channels.ChannelPool(channels, mock.sentinel.ep) claimed = {ch_1.id: ch_1, ch_2.id: ch_2, ch_3.id: ch_3} - relay = {ch_4.id: ch_4, ch_5.id: ch_5} + client_chans = {ch_4.id: ch_4, ch_5.id: ch_5} with mock.patch.dict(ep_channels.claimed_channels, claimed, clear=True): - with mock.patch.dict(ep_channels.relay_channels, relay, clear=True): + with 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) - for ch in [*claimed.values(), *relay.values()]: + for ch in [*claimed.values(), *client_chans.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 diff --git a/tests/components/zha/test_device_action.py b/tests/components/zha/test_device_action.py index c779dda6cf8..40e64934f89 100644 --- a/tests/components/zha/test_device_action.py +++ b/tests/components/zha/test_device_action.py @@ -103,7 +103,7 @@ async def test_action(hass, device_ias): await hass.async_block_till_done() calls = async_mock_service(hass, DOMAIN, "warning_device_warn") - channel = zha_device.channels.pools[0].relay_channels["1:0x0006"] + channel = zha_device.channels.pools[0].client_channels["1:0x0006"] channel.zha_send_event(COMMAND_SINGLE, []) await hass.async_block_till_done() diff --git a/tests/components/zha/test_device_trigger.py b/tests/components/zha/test_device_trigger.py index 9b69ba06e4f..266094963f2 100644 --- a/tests/components/zha/test_device_trigger.py +++ b/tests/components/zha/test_device_trigger.py @@ -172,7 +172,7 @@ async def test_if_fires_on_event(hass, mock_devices, calls): await hass.async_block_till_done() - channel = zha_device.channels.pools[0].relay_channels["1:0x0006"] + channel = zha_device.channels.pools[0].client_channels["1:0x0006"] channel.zha_send_event(COMMAND_SINGLE, []) await hass.async_block_till_done() diff --git a/tests/components/zha/test_discover.py b/tests/components/zha/test_discover.py index e1733ac44bd..e58fd740655 100644 --- a/tests/components/zha/test_discover.py +++ b/tests/components/zha/test_discover.py @@ -111,7 +111,7 @@ async def test_devices( ) event_channels = { - ch.id for pool in zha_dev.channels.pools for ch in pool.relay_channels.values() + ch.id for pool in zha_dev.channels.pools for ch in pool.client_channels.values() } entity_map = device["entity_map"] @@ -266,7 +266,7 @@ async def test_discover_endpoint(device_info, channels_mock, hass): ) assert device_info["event_channels"] == sorted( - [ch.id for pool in channels.pools for ch in pool.relay_channels.values()] + [ch.id for pool in channels.pools for ch in pool.client_channels.values()] ) assert new_ent.call_count == len( [