zha: Handle both input and output clusters (#8410)
bellows 0.3.0 changes the API to have both, renaming the attribute which used to be for input clusters in the process. This is in preparation for remotes.
This commit is contained in:
parent
7a4cc8e082
commit
2f474a0ed8
6 changed files with 42 additions and 28 deletions
|
@ -34,10 +34,10 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
|
||||
from bellows.zigbee.zcl.clusters.security import IasZone
|
||||
|
||||
clusters = discovery_info['clusters']
|
||||
in_clusters = discovery_info['in_clusters']
|
||||
|
||||
device_class = None
|
||||
cluster = [c for c in clusters if isinstance(c, IasZone)][0]
|
||||
cluster = in_clusters[IasZone.cluster_id]
|
||||
if discovery_info['new_join']:
|
||||
yield from cluster.bind()
|
||||
ieee = cluster.endpoint.device.application.ieee
|
||||
|
@ -64,7 +64,7 @@ class BinarySensor(zha.Entity, BinarySensorDevice):
|
|||
super().__init__(**kwargs)
|
||||
self._device_class = device_class
|
||||
from bellows.zigbee.zcl.clusters.security import IasZone
|
||||
self._ias_zone_cluster = self._clusters[IasZone.cluster_id]
|
||||
self._ias_zone_cluster = self._in_clusters[IasZone.cluster_id]
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
|
|
|
@ -46,10 +46,10 @@ class Light(zha.Entity, light.Light):
|
|||
self._brightness = None
|
||||
|
||||
import bellows.zigbee.zcl.clusters as zcl_clusters
|
||||
if zcl_clusters.general.LevelControl.cluster_id in self._clusters:
|
||||
if zcl_clusters.general.LevelControl.cluster_id in self._in_clusters:
|
||||
self._supported_features |= light.SUPPORT_BRIGHTNESS
|
||||
self._brightness = 0
|
||||
if zcl_clusters.lighting.Color.cluster_id in self._clusters:
|
||||
if zcl_clusters.lighting.Color.cluster_id in self._in_clusters:
|
||||
# Not sure all color lights necessarily support this directly
|
||||
# Should we emulate it?
|
||||
self._supported_features |= light.SUPPORT_COLOR_TEMP
|
||||
|
|
|
@ -31,17 +31,16 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
|||
@asyncio.coroutine
|
||||
def make_sensor(discovery_info):
|
||||
"""Create ZHA sensors factory."""
|
||||
from bellows.zigbee import zcl
|
||||
if isinstance(discovery_info['clusters'][0],
|
||||
zcl.clusters.measurement.TemperatureMeasurement):
|
||||
from bellows.zigbee.zcl.clusters.measurement import TemperatureMeasurement
|
||||
in_clusters = discovery_info['in_clusters']
|
||||
if TemperatureMeasurement.cluster_id in in_clusters:
|
||||
sensor = TemperatureSensor(**discovery_info)
|
||||
else:
|
||||
sensor = Sensor(**discovery_info)
|
||||
|
||||
clusters = discovery_info['clusters']
|
||||
attr = sensor.value_attribute
|
||||
if discovery_info['new_join']:
|
||||
cluster = clusters[0]
|
||||
cluster = list(in_clusters.values())[0]
|
||||
yield from cluster.bind()
|
||||
yield from cluster.configure_reporting(
|
||||
attr, 300, 600, sensor.min_reportable_change,
|
||||
|
|
|
@ -14,7 +14,7 @@ from homeassistant import const as ha_const
|
|||
from homeassistant.helpers import discovery, entity
|
||||
from homeassistant.util import slugify
|
||||
|
||||
REQUIREMENTS = ['bellows==0.2.7']
|
||||
REQUIREMENTS = ['bellows==0.3.2']
|
||||
|
||||
DOMAIN = 'zha'
|
||||
|
||||
|
@ -128,6 +128,10 @@ class ApplicationListener:
|
|||
"""Handle device joined and basic information discovered."""
|
||||
self._hass.async_add_job(self.async_device_initialized(device, True))
|
||||
|
||||
def device_left(self, device):
|
||||
"""Handle device leaving the network."""
|
||||
pass
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_device_initialized(self, device, join):
|
||||
"""Handle device joined and basic information discovered (async)."""
|
||||
|
@ -142,7 +146,7 @@ class ApplicationListener:
|
|||
discovered_info = yield from _discover_endpoint_info(endpoint)
|
||||
|
||||
component = None
|
||||
used_clusters = []
|
||||
profile_clusters = ([], [])
|
||||
device_key = '%s-%s' % (str(device.ieee), endpoint_id)
|
||||
node_config = self._config[DOMAIN][CONF_DEVICE_CONFIG].get(
|
||||
device_key, {})
|
||||
|
@ -152,20 +156,25 @@ class ApplicationListener:
|
|||
if zha_const.DEVICE_CLASS.get(endpoint.profile_id,
|
||||
{}).get(endpoint.device_type,
|
||||
None):
|
||||
used_clusters = profile.CLUSTERS[endpoint.device_type]
|
||||
profile_clusters = profile.CLUSTERS[endpoint.device_type]
|
||||
profile_info = zha_const.DEVICE_CLASS[endpoint.profile_id]
|
||||
component = profile_info[endpoint.device_type]
|
||||
|
||||
if ha_const.CONF_TYPE in node_config:
|
||||
component = node_config[ha_const.CONF_TYPE]
|
||||
used_clusters = zha_const.COMPONENT_CLUSTERS[component]
|
||||
profile_clusters = zha_const.COMPONENT_CLUSTERS[component]
|
||||
|
||||
if component:
|
||||
clusters = [endpoint.clusters[c] for c in used_clusters if c in
|
||||
endpoint.clusters]
|
||||
in_clusters = [endpoint.in_clusters[c]
|
||||
for c in profile_clusters[0]
|
||||
if c in endpoint.in_clusters]
|
||||
out_clusters = [endpoint.out_clusters[c]
|
||||
for c in profile_clusters[1]
|
||||
if c in endpoint.out_clusters]
|
||||
discovery_info = {
|
||||
'endpoint': endpoint,
|
||||
'clusters': clusters,
|
||||
'in_clusters': {c.cluster_id: c for c in in_clusters},
|
||||
'out_clusters': {c.cluster_id: c for c in out_clusters},
|
||||
'new_join': join,
|
||||
}
|
||||
discovery_info.update(discovered_info)
|
||||
|
@ -179,9 +188,9 @@ class ApplicationListener:
|
|||
self._config,
|
||||
)
|
||||
|
||||
for cluster_id, cluster in endpoint.clusters.items():
|
||||
for cluster_id, cluster in endpoint.in_clusters.items():
|
||||
cluster_type = type(cluster)
|
||||
if cluster_id in used_clusters:
|
||||
if cluster_id in profile_clusters[0]:
|
||||
continue
|
||||
if cluster_type not in zha_const.SINGLE_CLUSTER_DEVICE_CLASS:
|
||||
continue
|
||||
|
@ -189,7 +198,8 @@ class ApplicationListener:
|
|||
component = zha_const.SINGLE_CLUSTER_DEVICE_CLASS[cluster_type]
|
||||
discovery_info = {
|
||||
'endpoint': endpoint,
|
||||
'clusters': [cluster],
|
||||
'in_clusters': {cluster.cluster_id: cluster},
|
||||
'out_clusters': {},
|
||||
'new_join': join,
|
||||
}
|
||||
discovery_info.update(discovered_info)
|
||||
|
@ -210,7 +220,8 @@ class Entity(entity.Entity):
|
|||
|
||||
_domain = None # Must be overriden by subclasses
|
||||
|
||||
def __init__(self, endpoint, clusters, manufacturer, model, **kwargs):
|
||||
def __init__(self, endpoint, in_clusters, out_clusters, manufacturer,
|
||||
model, **kwargs):
|
||||
"""Init ZHA entity."""
|
||||
self._device_state_attributes = {}
|
||||
ieeetail = ''.join([
|
||||
|
@ -234,10 +245,13 @@ class Entity(entity.Entity):
|
|||
ieeetail,
|
||||
endpoint.endpoint_id,
|
||||
)
|
||||
for cluster in clusters:
|
||||
for cluster in in_clusters.values():
|
||||
cluster.add_listener(self)
|
||||
for cluster in out_clusters.values():
|
||||
cluster.add_listener(self)
|
||||
self._endpoint = endpoint
|
||||
self._clusters = {c.cluster_id: c for c in clusters}
|
||||
self._in_clusters = in_clusters
|
||||
self._out_clusters = out_clusters
|
||||
self._state = ha_const.STATE_UNKNOWN
|
||||
|
||||
def attribute_updated(self, attribute, value):
|
||||
|
@ -261,13 +275,13 @@ def _discover_endpoint_info(endpoint):
|
|||
'manufacturer': None,
|
||||
'model': None,
|
||||
}
|
||||
if 0 not in endpoint.clusters:
|
||||
if 0 not in endpoint.in_clusters:
|
||||
return extra_info
|
||||
|
||||
@asyncio.coroutine
|
||||
def read(attributes):
|
||||
"""Read attributes and update extra_info convenience function."""
|
||||
result, _ = yield from endpoint.clusters[0].read_attributes(
|
||||
result, _ = yield from endpoint.in_clusters[0].read_attributes(
|
||||
attributes,
|
||||
allow_cache=True,
|
||||
)
|
||||
|
|
|
@ -46,6 +46,7 @@ def populate_data():
|
|||
profile = PROFILES[profile_id]
|
||||
for device_type, component in classes.items():
|
||||
if component not in COMPONENT_CLUSTERS:
|
||||
COMPONENT_CLUSTERS[component] = set()
|
||||
COMPONENT_CLUSTERS[component] = (set(), set())
|
||||
clusters = profile.CLUSTERS[device_type]
|
||||
COMPONENT_CLUSTERS[component].update(clusters)
|
||||
COMPONENT_CLUSTERS[component][0].update(clusters[0])
|
||||
COMPONENT_CLUSTERS[component][1].update(clusters[1])
|
||||
|
|
|
@ -93,7 +93,7 @@ batinfo==0.4.2
|
|||
beautifulsoup4==4.6.0
|
||||
|
||||
# homeassistant.components.zha
|
||||
bellows==0.2.7
|
||||
bellows==0.3.2
|
||||
|
||||
# homeassistant.components.blink
|
||||
blinkpy==0.6.0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue