Misc. ZHA enhancements (#24559)

* add nwk to device info
* input bind only cluster support
* cleanup channel only clusters
* dirty hack to correct xiaomi vibration sensor
* exclude remaining remote binary sensors
* review comments
* fix comment
This commit is contained in:
David F. Mulcahey 2019-06-16 13:17:53 -04:00 committed by Alexei Chetroi
parent b782ed6bbb
commit c173a3be44
4 changed files with 78 additions and 20 deletions

View file

@ -18,7 +18,7 @@ from .const import (
ATTR_COMMAND_TYPE, ATTR_ARGS, CLIENT_COMMANDS, SERVER_COMMANDS,
ATTR_ENDPOINT_ID, IEEE, MODEL, NAME, UNKNOWN, QUIRK_APPLIED,
QUIRK_CLASS, ZDO_CHANNEL, MANUFACTURER_CODE, POWER_SOURCE, MAINS_POWERED,
BATTERY_OR_UNKNOWN
BATTERY_OR_UNKNOWN, NWK
)
from .channels import EventRelayChannel
@ -189,6 +189,7 @@ class ZHADevice:
ieee = str(self.ieee)
return {
IEEE: ieee,
NWK: self.nwk,
ATTR_MANUFACTURER: self.manufacturer,
MODEL: self.model,
NAME: self.name or ieee,
@ -390,7 +391,7 @@ class ZHADevice:
manufacturer=manufacturer
)
_LOGGER.debug(
'set: %s for attr: %s to cluster: %s for entity: %s - res: %s',
'set: %s for attr: %s to cluster: %s for ept: %s - res: %s',
value,
attribute,
cluster_id,

View file

@ -21,9 +21,10 @@ from .const import (
SENSOR_TYPE, UNKNOWN, GENERIC, POWER_CONFIGURATION_CHANNEL
)
from .registries import (
BINARY_SENSOR_TYPES, NO_SENSOR_CLUSTERS, EVENT_RELAY_CLUSTERS,
BINARY_SENSOR_TYPES, CHANNEL_ONLY_CLUSTERS, EVENT_RELAY_CLUSTERS,
SENSOR_TYPES, DEVICE_CLASS, COMPONENT_CLUSTERS,
SINGLE_INPUT_CLUSTER_DEVICE_CLASS, SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS
SINGLE_INPUT_CLUSTER_DEVICE_CLASS, SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS,
OUTPUT_CHANNEL_ONLY_CLUSTERS, REMOTE_DEVICE_TYPES
)
from ..device_entity import ZhaDeviceEntity
@ -87,6 +88,12 @@ def async_process_endpoint(
def _async_create_cluster_channel(cluster, zha_device, is_new_join,
channels=None, channel_class=None):
"""Create a cluster channel and attach it to a device."""
# really ugly hack to deal with xiaomi using the door lock cluster
# incorrectly.
if hasattr(cluster, 'ep_attribute') and \
cluster.ep_attribute == 'multistate_input':
channel_class = AttributeListeningChannel
# end of ugly hack
if channel_class is None:
channel_class = ZIGBEE_CHANNEL_REGISTRY.get(cluster.cluster_id,
AttributeListeningChannel)
@ -161,17 +168,18 @@ def _async_handle_single_cluster_matches(hass, endpoint, zha_device,
profile_clusters, device_key,
is_new_join):
"""Dispatch single cluster matches to HA components."""
from zigpy.zcl.clusters.general import OnOff
cluster_matches = []
cluster_match_results = []
for cluster in endpoint.in_clusters.values():
# don't let profiles prevent these channels from being created
if cluster.cluster_id in NO_SENSOR_CLUSTERS:
if cluster.cluster_id in CHANNEL_ONLY_CLUSTERS:
cluster_match_results.append(
_async_handle_channel_only_cluster_match(
zha_device,
cluster,
is_new_join,
))
continue
if cluster.cluster_id not in profile_clusters:
cluster_match_results.append(_async_handle_single_cluster_match(
@ -184,15 +192,33 @@ def _async_handle_single_cluster_matches(hass, endpoint, zha_device,
))
for cluster in endpoint.out_clusters.values():
if cluster.cluster_id in OUTPUT_CHANNEL_ONLY_CLUSTERS:
cluster_match_results.append(
_async_handle_channel_only_cluster_match(
zha_device,
cluster,
is_new_join,
))
continue
device_type = cluster.endpoint.device_type
profile_id = cluster.endpoint.profile_id
if cluster.cluster_id not in profile_clusters:
cluster_match_results.append(_async_handle_single_cluster_match(
hass,
zha_device,
cluster,
device_key,
SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS,
is_new_join,
))
# prevent remotes and controllers from getting entities
if not (cluster.cluster_id == OnOff.cluster_id and profile_id in
REMOTE_DEVICE_TYPES and device_type in
REMOTE_DEVICE_TYPES[profile_id]):
cluster_match_results.append(
_async_handle_single_cluster_match(
hass,
zha_device,
cluster,
device_key,
SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS,
is_new_join,
)
)
if cluster.cluster_id in EVENT_RELAY_CLUSTERS:
_async_create_cluster_channel(

View file

@ -32,7 +32,7 @@ from .discovery import (
async_create_device_entity, async_dispatch_discovery_info,
async_process_endpoint)
from .patches import apply_application_controller_patch
from .registries import RADIO_TYPES
from .registries import RADIO_TYPES, INPUT_BIND_ONLY_CLUSTERS
from .store import async_get_registry
_LOGGER = logging.getLogger(__name__)
@ -274,8 +274,10 @@ class ZHAGateway:
)
if endpoint_id != 0:
for cluster in endpoint.in_clusters.values():
cluster.bind_only = False
cluster.bind_only = \
cluster.cluster_id in INPUT_BIND_ONLY_CLUSTERS
for cluster in endpoint.out_clusters.values():
# output clusters are always bind only
cluster.bind_only = True
else:
is_rejoin = is_new_join is True

View file

@ -30,11 +30,14 @@ SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS = {}
SENSOR_TYPES = {}
RADIO_TYPES = {}
BINARY_SENSOR_TYPES = {}
REMOTE_DEVICE_TYPES = {}
CLUSTER_REPORT_CONFIGS = {}
CUSTOM_CLUSTER_MAPPINGS = {}
EVENT_RELAY_CLUSTERS = []
NO_SENSOR_CLUSTERS = []
CHANNEL_ONLY_CLUSTERS = []
OUTPUT_CHANNEL_ONLY_CLUSTERS = []
BINDABLE_CLUSTERS = []
INPUT_BIND_ONLY_CLUSTERS = []
BINARY_SENSOR_CLUSTERS = set()
LIGHT_CLUSTERS = set()
SWITCH_CLUSTERS = set()
@ -59,6 +62,11 @@ def establish_device_mappings():
if zll.PROFILE_ID not in DEVICE_CLASS:
DEVICE_CLASS[zll.PROFILE_ID] = {}
if zha.PROFILE_ID not in REMOTE_DEVICE_TYPES:
REMOTE_DEVICE_TYPES[zha.PROFILE_ID] = []
if zll.PROFILE_ID not in REMOTE_DEVICE_TYPES:
REMOTE_DEVICE_TYPES[zll.PROFILE_ID] = []
def get_ezsp_radio():
import bellows.ezsp
from bellows.zigbee.application import ControllerApplication
@ -101,15 +109,21 @@ def establish_device_mappings():
EVENT_RELAY_CLUSTERS.append(zcl.clusters.general.LevelControl.cluster_id)
EVENT_RELAY_CLUSTERS.append(zcl.clusters.general.OnOff.cluster_id)
NO_SENSOR_CLUSTERS.append(zcl.clusters.general.Basic.cluster_id)
NO_SENSOR_CLUSTERS.append(
CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.general.Basic.cluster_id)
CHANNEL_ONLY_CLUSTERS.append(
zcl.clusters.general.PowerConfiguration.cluster_id)
NO_SENSOR_CLUSTERS.append(zcl.clusters.lightlink.LightLink.cluster_id)
CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.lightlink.LightLink.cluster_id)
OUTPUT_CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.general.Scenes.cluster_id)
BINDABLE_CLUSTERS.append(zcl.clusters.general.LevelControl.cluster_id)
BINDABLE_CLUSTERS.append(zcl.clusters.general.OnOff.cluster_id)
BINDABLE_CLUSTERS.append(zcl.clusters.lighting.Color.cluster_id)
INPUT_BIND_ONLY_CLUSTERS.append(
zcl.clusters.lightlink.LightLink.cluster_id
)
DEVICE_CLASS[zha.PROFILE_ID].update({
zha.DeviceType.SMART_PLUG: SWITCH,
zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT: LIGHT,
@ -181,6 +195,21 @@ def establish_device_mappings():
SMARTTHINGS_ACCELERATION_CLUSTER: ACCELERATION,
})
zhap = zha.PROFILE_ID
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.NON_COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.NON_COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.REMOTE_CONTROL)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.SCENE_SELECTOR)
zllp = zll.PROFILE_ID
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.CONTROL_BRIDGE)
CLUSTER_REPORT_CONFIGS.update({
zcl.clusters.general.Alarms.cluster_id: [],
zcl.clusters.general.Basic.cluster_id: [],