Allow ZHA coordinator binding/unbinding (#42854)

* Allow coordinator ZDO binding/unbinding operations

* Let coordinator to provide endpoint it

* Refactor ClusterPair to a dataclass

* Rename ClusterPair
This commit is contained in:
Alexei Chetroi 2020-11-06 17:33:13 -05:00 committed by GitHub
parent 121872c546
commit 4b7829d777
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 19 deletions

View file

@ -807,18 +807,12 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati
clusters_to_bind = await get_matched_clusters(source_device, target_device)
zdo = source_device.device.zdo
bind_tasks = []
for cluster_pair in clusters_to_bind:
destination_address = zdo_types.MultiAddress()
destination_address.addrmode = 3
destination_address.ieee = target_device.ieee
destination_address.endpoint = cluster_pair.target_cluster.endpoint.endpoint_id
zdo = cluster_pair.source_cluster.endpoint.device.zdo
for binding_pair in clusters_to_bind:
op_msg = "cluster: %s %s --> [%s]"
op_params = (
cluster_pair.source_cluster.cluster_id,
binding_pair.source_cluster.cluster_id,
operation.name,
target_ieee,
)
@ -829,9 +823,9 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati
zdo.request(
operation,
source_device.ieee,
cluster_pair.source_cluster.endpoint.endpoint_id,
cluster_pair.source_cluster.cluster_id,
destination_address,
binding_pair.source_cluster.endpoint.endpoint_id,
binding_pair.source_cluster.cluster_id,
binding_pair.destination_address,
),
op_msg,
op_params,

View file

@ -7,7 +7,7 @@ https://home-assistant.io/integrations/zha/
import asyncio
import binascii
import collections
from dataclasses import dataclass
import functools
import itertools
import logging
@ -19,13 +19,29 @@ import voluptuous as vol
import zigpy.exceptions
import zigpy.types
import zigpy.util
import zigpy.zdo.types as zdo_types
from homeassistant.core import State, callback
from .const import CLUSTER_TYPE_IN, CLUSTER_TYPE_OUT, DATA_ZHA, DATA_ZHA_GATEWAY
from .registries import BINDABLE_CLUSTERS
from .typing import ZhaDeviceType, ZigpyClusterType
ClusterPair = collections.namedtuple("ClusterPair", "source_cluster target_cluster")
@dataclass
class BindingPair:
"""Information for binding."""
source_cluster: ZigpyClusterType
target_ieee: zigpy.types.EUI64
target_ep_id: int
@property
def destination_address(self) -> zdo_types.MultiAddress:
"""Return a ZDO multi address instance."""
return zdo_types.MultiAddress(
addrmode=3, ieee=self.target_ieee, endpoint=self.target_ep_id
)
async def safe_read(
@ -49,7 +65,9 @@ async def safe_read(
return {}
async def get_matched_clusters(source_zha_device, target_zha_device):
async def get_matched_clusters(
source_zha_device: ZhaDeviceType, target_zha_device: ZhaDeviceType
) -> List[BindingPair]:
"""Get matched input/output cluster pairs for 2 devices."""
source_clusters = source_zha_device.async_get_std_clusters()
target_clusters = target_zha_device.async_get_std_clusters()
@ -59,15 +77,26 @@ async def get_matched_clusters(source_zha_device, target_zha_device):
for cluster_id in source_clusters[endpoint_id][CLUSTER_TYPE_OUT]:
if cluster_id not in BINDABLE_CLUSTERS:
continue
for t_endpoint_id in target_clusters:
if cluster_id in target_clusters[t_endpoint_id][CLUSTER_TYPE_IN]:
cluster_pair = ClusterPair(
if target_zha_device.nwk == 0x0000:
cluster_pair = BindingPair(
source_cluster=source_clusters[endpoint_id][CLUSTER_TYPE_OUT][
cluster_id
],
target_cluster=target_clusters[t_endpoint_id][CLUSTER_TYPE_IN][
target_ieee=target_zha_device.ieee,
target_ep_id=target_zha_device.device.application.get_endpoint_id(
cluster_id, is_server_cluster=True
),
)
clusters_to_bind.append(cluster_pair)
continue
for t_endpoint_id in target_clusters:
if cluster_id in target_clusters[t_endpoint_id][CLUSTER_TYPE_IN]:
cluster_pair = BindingPair(
source_cluster=source_clusters[endpoint_id][CLUSTER_TYPE_OUT][
cluster_id
],
target_ieee=target_zha_device.ieee,
target_ep_id=t_endpoint_id,
)
clusters_to_bind.append(cluster_pair)
return clusters_to_bind
@ -76,6 +105,9 @@ async def get_matched_clusters(source_zha_device, target_zha_device):
@callback
def async_is_bindable_target(source_zha_device, target_zha_device):
"""Determine if target is bindable to source."""
if target_zha_device.nwk == 0x0000:
return True
source_clusters = source_zha_device.async_get_std_clusters()
target_clusters = target_zha_device.async_get_std_clusters()