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.
This commit is contained in:
Alexei Chetroi 2020-03-21 19:59:32 -04:00 committed by GitHub
parent d5e606640c
commit 991afccbd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 62 additions and 40 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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