Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc. ZHA enhancements #24559

Merged
merged 7 commits into from Jun 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions homeassistant/components/zha/core/device.py
Expand Up @@ -18,7 +18,7 @@
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

Expand Down Expand Up @@ -189,6 +189,7 @@ def device_info(self):
ieee = str(self.ieee)
return {
IEEE: ieee,
NWK: self.nwk,
ATTR_MANUFACTURER: self.manufacturer,
MODEL: self.model,
NAME: self.name or ieee,
Expand Down Expand Up @@ -390,7 +391,7 @@ async def write_zigbee_attribute(self, endpoint_id, cluster_id,
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,
Expand Down
50 changes: 38 additions & 12 deletions homeassistant/components/zha/core/discovery.py
Expand Up @@ -21,9 +21,10 @@
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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand All @@ -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
Adminiuga marked this conversation as resolved.
Show resolved Hide resolved
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(
Expand Down
6 changes: 4 additions & 2 deletions homeassistant/components/zha/core/gateway.py
Expand Up @@ -32,7 +32,7 @@
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__)
Expand Down Expand Up @@ -274,8 +274,10 @@ async def async_device_initialized(self, device, is_new_join):
)
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
Expand Down
37 changes: 33 additions & 4 deletions homeassistant/components/zha/core/registries.py
Expand Up @@ -30,11 +30,14 @@
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()
Expand All @@ -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
Expand Down Expand Up @@ -101,15 +109,21 @@ def get_deconz_radio():
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,
Expand Down Expand Up @@ -181,6 +195,21 @@ def get_deconz_radio():
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: [],
Expand Down