ZHA entity ZCL reporting configuration (#19177)
* Implement async_configure() method for ZHA entities. Allow attribute reporting configuration to be stored as dict of zha entity. * Update ZHA platform to use new attribute reporting configuration. * Use const declaration instead of magic numbers. * Add support for manufacturer_id in ZCL attribute reporting configuration. * Refactor async_configure() method. Rename attribute reporting dict to zcl_reporting_config.
This commit is contained in:
parent
23a579421d
commit
4692605974
8 changed files with 214 additions and 42 deletions
|
@ -9,7 +9,7 @@ import logging
|
||||||
from homeassistant.components.binary_sensor import DOMAIN, BinarySensorDevice
|
from homeassistant.components.binary_sensor import DOMAIN, BinarySensorDevice
|
||||||
from homeassistant.components.zha import helpers
|
from homeassistant.components.zha import helpers
|
||||||
from homeassistant.components.zha.const import (
|
from homeassistant.components.zha.const import (
|
||||||
DATA_ZHA, DATA_ZHA_DISPATCHERS, ZHA_DISCOVERY_NEW)
|
DATA_ZHA, DATA_ZHA_DISPATCHERS, REPORT_CONFIG_IMMEDIATE, ZHA_DISCOVERY_NEW)
|
||||||
from homeassistant.components.zha.entities import ZhaEntity
|
from homeassistant.components.zha.entities import ZhaEntity
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
|
@ -89,21 +89,7 @@ async def _async_setup_remote(discovery_info):
|
||||||
remote = Remote(**discovery_info)
|
remote = Remote(**discovery_info)
|
||||||
|
|
||||||
if discovery_info['new_join']:
|
if discovery_info['new_join']:
|
||||||
from zigpy.zcl.clusters.general import OnOff, LevelControl
|
await remote.async_configure()
|
||||||
out_clusters = discovery_info['out_clusters']
|
|
||||||
if OnOff.cluster_id in out_clusters:
|
|
||||||
cluster = out_clusters[OnOff.cluster_id]
|
|
||||||
await helpers.configure_reporting(
|
|
||||||
remote.entity_id, cluster, 0, min_report=0, max_report=600,
|
|
||||||
reportable_change=1
|
|
||||||
)
|
|
||||||
if LevelControl.cluster_id in out_clusters:
|
|
||||||
cluster = out_clusters[LevelControl.cluster_id]
|
|
||||||
await helpers.configure_reporting(
|
|
||||||
remote.entity_id, cluster, 0, min_report=1, max_report=600,
|
|
||||||
reportable_change=1
|
|
||||||
)
|
|
||||||
|
|
||||||
return remote
|
return remote
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,6 +224,14 @@ class Remote(ZhaEntity, BinarySensorDevice):
|
||||||
general.OnOff.cluster_id: self.OnOffListener(self),
|
general.OnOff.cluster_id: self.OnOffListener(self),
|
||||||
general.LevelControl.cluster_id: self.LevelListener(self),
|
general.LevelControl.cluster_id: self.LevelListener(self),
|
||||||
}
|
}
|
||||||
|
out_clusters = kwargs.get('out_clusters')
|
||||||
|
self._zcl_reporting = {}
|
||||||
|
for cluster_id in [general.OnOff.cluster_id,
|
||||||
|
general.LevelControl.cluster_id]:
|
||||||
|
if cluster_id not in out_clusters:
|
||||||
|
continue
|
||||||
|
cluster = out_clusters[cluster_id]
|
||||||
|
self._zcl_reporting[cluster] = {0: REPORT_CONFIG_IMMEDIATE}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self) -> bool:
|
def should_poll(self) -> bool:
|
||||||
|
@ -257,6 +251,11 @@ class Remote(ZhaEntity, BinarySensorDevice):
|
||||||
})
|
})
|
||||||
return self._device_state_attributes
|
return self._device_state_attributes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zcl_reporting_config(self):
|
||||||
|
"""Return ZCL attribute reporting configuration."""
|
||||||
|
return self._zcl_reporting
|
||||||
|
|
||||||
def move_level(self, change):
|
def move_level(self, change):
|
||||||
"""Increment the level, setting state if appropriate."""
|
"""Increment the level, setting state if appropriate."""
|
||||||
if not self._state and change > 0:
|
if not self._state and change > 0:
|
||||||
|
|
|
@ -11,7 +11,7 @@ from homeassistant.components.fan import (
|
||||||
FanEntity)
|
FanEntity)
|
||||||
from homeassistant.components.zha import helpers
|
from homeassistant.components.zha import helpers
|
||||||
from homeassistant.components.zha.const import (
|
from homeassistant.components.zha.const import (
|
||||||
DATA_ZHA, DATA_ZHA_DISPATCHERS, ZHA_DISCOVERY_NEW)
|
DATA_ZHA, DATA_ZHA_DISPATCHERS, REPORT_CONFIG_OP, ZHA_DISCOVERY_NEW)
|
||||||
from homeassistant.components.zha.entities import ZhaEntity
|
from homeassistant.components.zha.entities import ZhaEntity
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
|
@ -70,7 +70,10 @@ async def _async_setup_entities(hass, config_entry, async_add_entities,
|
||||||
"""Set up the ZHA fans."""
|
"""Set up the ZHA fans."""
|
||||||
entities = []
|
entities = []
|
||||||
for discovery_info in discovery_infos:
|
for discovery_info in discovery_infos:
|
||||||
entities.append(ZhaFan(**discovery_info))
|
fan = ZhaFan(**discovery_info)
|
||||||
|
if discovery_info['new_join']:
|
||||||
|
await fan.async_configure()
|
||||||
|
entities.append(fan)
|
||||||
|
|
||||||
async_add_entities(entities, update_before_add=True)
|
async_add_entities(entities, update_before_add=True)
|
||||||
|
|
||||||
|
@ -79,6 +82,19 @@ class ZhaFan(ZhaEntity, FanEntity):
|
||||||
"""Representation of a ZHA fan."""
|
"""Representation of a ZHA fan."""
|
||||||
|
|
||||||
_domain = DOMAIN
|
_domain = DOMAIN
|
||||||
|
value_attribute = 0 # fan_mode
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zcl_reporting_config(self) -> dict:
|
||||||
|
"""Return a dict of attribute reporting configuration."""
|
||||||
|
return {
|
||||||
|
self.cluster: {self.value_attribute: REPORT_CONFIG_OP}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cluster(self):
|
||||||
|
"""Fan ZCL Cluster."""
|
||||||
|
return self._endpoint.fan
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self) -> int:
|
def supported_features(self) -> int:
|
||||||
|
@ -129,7 +145,7 @@ class ZhaFan(ZhaEntity, FanEntity):
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Retrieve latest state."""
|
"""Retrieve latest state."""
|
||||||
result = await helpers.safe_read(self._endpoint.fan, ['fan_mode'],
|
result = await helpers.safe_read(self.cluster, ['fan_mode'],
|
||||||
allow_cache=False,
|
allow_cache=False,
|
||||||
only_cache=(not self._initialized))
|
only_cache=(not self._initialized))
|
||||||
new_value = result.get('fan_mode', None)
|
new_value = result.get('fan_mode', None)
|
||||||
|
@ -142,3 +158,12 @@ class ZhaFan(ZhaEntity, FanEntity):
|
||||||
False if entity pushes its state to HA.
|
False if entity pushes its state to HA.
|
||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def attribute_updated(self, attribute, value):
|
||||||
|
"""Handle attribute update from device."""
|
||||||
|
attr_name = self.cluster.attributes.get(attribute, [attribute])[0]
|
||||||
|
_LOGGER.debug("%s: Attribute report '%s'[%s] = %s",
|
||||||
|
self.entity_id, self.cluster.name, attr_name, value)
|
||||||
|
if attribute == self.value_attribute:
|
||||||
|
self._state = VALUE_TO_SPEED.get(value, self._state)
|
||||||
|
self.async_schedule_update_ha_state()
|
||||||
|
|
|
@ -9,7 +9,8 @@ import logging
|
||||||
from homeassistant.components import light
|
from homeassistant.components import light
|
||||||
from homeassistant.components.zha import helpers
|
from homeassistant.components.zha import helpers
|
||||||
from homeassistant.components.zha.const import (
|
from homeassistant.components.zha.const import (
|
||||||
DATA_ZHA, DATA_ZHA_DISPATCHERS, ZHA_DISCOVERY_NEW)
|
DATA_ZHA, DATA_ZHA_DISPATCHERS, REPORT_CONFIG_ASAP, REPORT_CONFIG_DEFAULT,
|
||||||
|
REPORT_CONFIG_IMMEDIATE, ZHA_DISCOVERY_NEW)
|
||||||
from homeassistant.components.zha.entities import ZhaEntity
|
from homeassistant.components.zha.entities import ZhaEntity
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
import homeassistant.util.color as color_util
|
import homeassistant.util.color as color_util
|
||||||
|
@ -73,7 +74,10 @@ async def _async_setup_entities(hass, config_entry, async_add_entities,
|
||||||
UNSUPPORTED_ATTRIBUTE):
|
UNSUPPORTED_ATTRIBUTE):
|
||||||
discovery_info['color_capabilities'] |= \
|
discovery_info['color_capabilities'] |= \
|
||||||
CAPABILITIES_COLOR_TEMP
|
CAPABILITIES_COLOR_TEMP
|
||||||
entities.append(Light(**discovery_info))
|
zha_light = Light(**discovery_info)
|
||||||
|
if discovery_info['new_join']:
|
||||||
|
await zha_light.async_configure()
|
||||||
|
entities.append(zha_light)
|
||||||
|
|
||||||
async_add_entities(entities, update_before_add=True)
|
async_add_entities(entities, update_before_add=True)
|
||||||
|
|
||||||
|
@ -105,6 +109,19 @@ class Light(ZhaEntity, light.Light):
|
||||||
self._supported_features |= light.SUPPORT_COLOR
|
self._supported_features |= light.SUPPORT_COLOR
|
||||||
self._hs_color = (0, 0)
|
self._hs_color = (0, 0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zcl_reporting_config(self) -> dict:
|
||||||
|
"""Return attribute reporting configuration."""
|
||||||
|
return {
|
||||||
|
'on_off': {'on_off': REPORT_CONFIG_IMMEDIATE},
|
||||||
|
'level': {'current_level': REPORT_CONFIG_ASAP},
|
||||||
|
'light_color': {
|
||||||
|
'current_x': REPORT_CONFIG_DEFAULT,
|
||||||
|
'current_y': REPORT_CONFIG_DEFAULT,
|
||||||
|
'color_temperature': REPORT_CONFIG_DEFAULT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
"""Return true if entity is on."""
|
"""Return true if entity is on."""
|
||||||
|
|
|
@ -9,7 +9,8 @@ import logging
|
||||||
from homeassistant.components.sensor import DOMAIN
|
from homeassistant.components.sensor import DOMAIN
|
||||||
from homeassistant.components.zha import helpers
|
from homeassistant.components.zha import helpers
|
||||||
from homeassistant.components.zha.const import (
|
from homeassistant.components.zha.const import (
|
||||||
DATA_ZHA, DATA_ZHA_DISPATCHERS, ZHA_DISCOVERY_NEW)
|
DATA_ZHA, DATA_ZHA_DISPATCHERS, REPORT_CONFIG_MAX_INT,
|
||||||
|
REPORT_CONFIG_MIN_INT, REPORT_CONFIG_RPT_CHANGE, ZHA_DISCOVERY_NEW)
|
||||||
from homeassistant.components.zha.entities import ZhaEntity
|
from homeassistant.components.zha.entities import ZhaEntity
|
||||||
from homeassistant.const import TEMP_CELSIUS
|
from homeassistant.const import TEMP_CELSIUS
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
@ -81,11 +82,7 @@ async def make_sensor(discovery_info):
|
||||||
sensor = Sensor(**discovery_info)
|
sensor = Sensor(**discovery_info)
|
||||||
|
|
||||||
if discovery_info['new_join']:
|
if discovery_info['new_join']:
|
||||||
cluster = list(in_clusters.values())[0]
|
await sensor.async_configure()
|
||||||
await helpers.configure_reporting(
|
|
||||||
sensor.entity_id, cluster, sensor.value_attribute,
|
|
||||||
reportable_change=sensor.min_reportable_change
|
|
||||||
)
|
|
||||||
|
|
||||||
return sensor
|
return sensor
|
||||||
|
|
||||||
|
@ -95,7 +92,28 @@ class Sensor(ZhaEntity):
|
||||||
|
|
||||||
_domain = DOMAIN
|
_domain = DOMAIN
|
||||||
value_attribute = 0
|
value_attribute = 0
|
||||||
min_reportable_change = 1
|
min_report_interval = REPORT_CONFIG_MIN_INT
|
||||||
|
max_report_interval = REPORT_CONFIG_MAX_INT
|
||||||
|
min_reportable_change = REPORT_CONFIG_RPT_CHANGE
|
||||||
|
report_config = (min_report_interval, max_report_interval,
|
||||||
|
min_reportable_change)
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
"""Init ZHA Sensor instance."""
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self._cluster = list(kwargs['in_clusters'].values())[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zcl_reporting_config(self) -> dict:
|
||||||
|
"""Return a dict of attribute reporting configuration."""
|
||||||
|
return {
|
||||||
|
self.cluster: {self.value_attribute: self.report_config}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cluster(self):
|
||||||
|
"""Return Sensor's cluster."""
|
||||||
|
return self._cluster
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self) -> bool:
|
def should_poll(self) -> bool:
|
||||||
|
@ -119,7 +137,7 @@ class Sensor(ZhaEntity):
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Retrieve latest state."""
|
"""Retrieve latest state."""
|
||||||
result = await helpers.safe_read(
|
result = await helpers.safe_read(
|
||||||
list(self._in_clusters.values())[0],
|
self.cluster,
|
||||||
[self.value_attribute],
|
[self.value_attribute],
|
||||||
allow_cache=False,
|
allow_cache=False,
|
||||||
only_cache=(not self._initialized)
|
only_cache=(not self._initialized)
|
||||||
|
@ -251,6 +269,6 @@ class ElectricalMeasurementSensor(Sensor):
|
||||||
_LOGGER.debug("%s async_update", self.entity_id)
|
_LOGGER.debug("%s async_update", self.entity_id)
|
||||||
|
|
||||||
result = await helpers.safe_read(
|
result = await helpers.safe_read(
|
||||||
self._endpoint.electrical_measurement, ['active_power'],
|
self.cluster, ['active_power'],
|
||||||
allow_cache=False, only_cache=(not self._initialized))
|
allow_cache=False, only_cache=(not self._initialized))
|
||||||
self._state = result.get('active_power', self._state)
|
self._state = result.get('active_power', self._state)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import logging
|
||||||
from homeassistant.components.switch import DOMAIN, SwitchDevice
|
from homeassistant.components.switch import DOMAIN, SwitchDevice
|
||||||
from homeassistant.components.zha import helpers
|
from homeassistant.components.zha import helpers
|
||||||
from homeassistant.components.zha.const import (
|
from homeassistant.components.zha.const import (
|
||||||
DATA_ZHA, DATA_ZHA_DISPATCHERS, ZHA_DISCOVERY_NEW)
|
DATA_ZHA, DATA_ZHA_DISPATCHERS, REPORT_CONFIG_IMMEDIATE, ZHA_DISCOVERY_NEW)
|
||||||
from homeassistant.components.zha.entities import ZhaEntity
|
from homeassistant.components.zha.entities import ZhaEntity
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
|
@ -44,17 +44,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
async def _async_setup_entities(hass, config_entry, async_add_entities,
|
async def _async_setup_entities(hass, config_entry, async_add_entities,
|
||||||
discovery_infos):
|
discovery_infos):
|
||||||
"""Set up the ZHA switches."""
|
"""Set up the ZHA switches."""
|
||||||
from zigpy.zcl.clusters.general import OnOff
|
|
||||||
entities = []
|
entities = []
|
||||||
for discovery_info in discovery_infos:
|
for discovery_info in discovery_infos:
|
||||||
switch = Switch(**discovery_info)
|
switch = Switch(**discovery_info)
|
||||||
if discovery_info['new_join']:
|
if discovery_info['new_join']:
|
||||||
in_clusters = discovery_info['in_clusters']
|
await switch.async_configure()
|
||||||
cluster = in_clusters[OnOff.cluster_id]
|
|
||||||
await helpers.configure_reporting(
|
|
||||||
switch.entity_id, cluster, switch.value_attribute,
|
|
||||||
min_report=0, max_report=600, reportable_change=1
|
|
||||||
)
|
|
||||||
entities.append(switch)
|
entities.append(switch)
|
||||||
|
|
||||||
async_add_entities(entities, update_before_add=True)
|
async_add_entities(entities, update_before_add=True)
|
||||||
|
@ -76,6 +70,18 @@ class Switch(ZhaEntity, SwitchDevice):
|
||||||
self._state = value
|
self._state = value
|
||||||
self.async_schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zcl_reporting_config(self) -> dict:
|
||||||
|
"""Retrun a dict of attribute reporting configuration."""
|
||||||
|
return {
|
||||||
|
self.cluster: {'on_off': REPORT_CONFIG_IMMEDIATE}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cluster(self):
|
||||||
|
"""Entity's cluster."""
|
||||||
|
return self._endpoint.on_off
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self) -> bool:
|
def should_poll(self) -> bool:
|
||||||
"""Let zha handle polling."""
|
"""Let zha handle polling."""
|
||||||
|
|
|
@ -57,6 +57,27 @@ CUSTOM_CLUSTER_MAPPINGS = {}
|
||||||
COMPONENT_CLUSTERS = {}
|
COMPONENT_CLUSTERS = {}
|
||||||
EVENTABLE_CLUSTERS = []
|
EVENTABLE_CLUSTERS = []
|
||||||
|
|
||||||
|
REPORT_CONFIG_MAX_INT = 900
|
||||||
|
REPORT_CONFIG_MAX_INT_BATTERY_SAVE = 10800
|
||||||
|
REPORT_CONFIG_MIN_INT = 30
|
||||||
|
REPORT_CONFIG_MIN_INT_ASAP = 1
|
||||||
|
REPORT_CONFIG_MIN_INT_IMMEDIATE = 0
|
||||||
|
REPORT_CONFIG_MIN_INT_OP = 5
|
||||||
|
REPORT_CONFIG_MIN_INT_BATTERY_SAVE = 3600
|
||||||
|
REPORT_CONFIG_RPT_CHANGE = 1
|
||||||
|
REPORT_CONFIG_DEFAULT = (REPORT_CONFIG_MIN_INT, REPORT_CONFIG_MAX_INT,
|
||||||
|
REPORT_CONFIG_RPT_CHANGE)
|
||||||
|
REPORT_CONFIG_ASAP = (REPORT_CONFIG_MIN_INT_ASAP, REPORT_CONFIG_MAX_INT,
|
||||||
|
REPORT_CONFIG_RPT_CHANGE)
|
||||||
|
REPORT_CONFIG_BATTERY_SAVE = (REPORT_CONFIG_MIN_INT_BATTERY_SAVE,
|
||||||
|
REPORT_CONFIG_MAX_INT,
|
||||||
|
REPORT_CONFIG_RPT_CHANGE)
|
||||||
|
REPORT_CONFIG_IMMEDIATE = (REPORT_CONFIG_MIN_INT_IMMEDIATE,
|
||||||
|
REPORT_CONFIG_MAX_INT,
|
||||||
|
REPORT_CONFIG_RPT_CHANGE)
|
||||||
|
REPORT_CONFIG_OP = (REPORT_CONFIG_MIN_INT_OP, REPORT_CONFIG_MAX_INT,
|
||||||
|
REPORT_CONFIG_RPT_CHANGE)
|
||||||
|
|
||||||
|
|
||||||
def populate_data():
|
def populate_data():
|
||||||
"""Populate data using constants from bellows.
|
"""Populate data using constants from bellows.
|
||||||
|
|
|
@ -4,13 +4,20 @@ Entity for Zigbee Home Automation.
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/zha/
|
https://home-assistant.io/components/zha/
|
||||||
"""
|
"""
|
||||||
|
from asyncio import sleep
|
||||||
|
import logging
|
||||||
|
from random import uniform
|
||||||
|
|
||||||
from homeassistant.components.zha.const import (
|
from homeassistant.components.zha.const import (
|
||||||
DATA_ZHA, DATA_ZHA_BRIDGE_ID, DOMAIN)
|
DATA_ZHA, DATA_ZHA_BRIDGE_ID, DOMAIN)
|
||||||
|
from homeassistant.components.zha.helpers import configure_reporting
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import entity
|
from homeassistant.helpers import entity
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE
|
from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ZhaEntity(entity.Entity):
|
class ZhaEntity(entity.Entity):
|
||||||
"""A base class for ZHA entities."""
|
"""A base class for ZHA entities."""
|
||||||
|
@ -57,6 +64,7 @@ class ZhaEntity(entity.Entity):
|
||||||
self._out_listeners = {}
|
self._out_listeners = {}
|
||||||
|
|
||||||
self._initialized = False
|
self._initialized = False
|
||||||
|
self.manufacturer_code = None
|
||||||
application_listener.register_entity(ieee, self)
|
application_listener.register_entity(ieee, self)
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
|
@ -71,6 +79,79 @@ class ZhaEntity(entity.Entity):
|
||||||
|
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
|
|
||||||
|
async def async_configure(self):
|
||||||
|
"""Set cluster binding and attribute reporting."""
|
||||||
|
for cluster_key, attrs in self.zcl_reporting_config.items():
|
||||||
|
cluster = self._get_cluster_from_report_config(cluster_key)
|
||||||
|
if cluster is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
manufacturer = None
|
||||||
|
if cluster.cluster_id >= 0xfc00 and self.manufacturer_code:
|
||||||
|
manufacturer = self.manufacturer_code
|
||||||
|
|
||||||
|
skip_bind = False # bind cluster only for the 1st configured attr
|
||||||
|
for attr, details in attrs.items():
|
||||||
|
min_report_interval, max_report_interval, change = details
|
||||||
|
await configure_reporting(
|
||||||
|
self.entity_id, cluster, attr,
|
||||||
|
min_report=min_report_interval,
|
||||||
|
max_report=max_report_interval,
|
||||||
|
reportable_change=change,
|
||||||
|
skip_bind=skip_bind,
|
||||||
|
manufacturer=manufacturer
|
||||||
|
)
|
||||||
|
skip_bind = True
|
||||||
|
await sleep(uniform(0.1, 0.5))
|
||||||
|
_LOGGER.debug("%s: finished configuration", self.entity_id)
|
||||||
|
|
||||||
|
def _get_cluster_from_report_config(self, cluster_key):
|
||||||
|
"""Parse an entry from zcl_reporting_config dict."""
|
||||||
|
from zigpy.zcl import Cluster as Zcl_Cluster
|
||||||
|
|
||||||
|
cluster = None
|
||||||
|
if isinstance(cluster_key, Zcl_Cluster):
|
||||||
|
cluster = cluster_key
|
||||||
|
elif isinstance(cluster_key, str):
|
||||||
|
cluster = getattr(self._endpoint, cluster_key, None)
|
||||||
|
elif isinstance(cluster_key, int):
|
||||||
|
if cluster_key in self._in_clusters:
|
||||||
|
cluster = self._in_clusters[cluster_key]
|
||||||
|
elif cluster_key in self._out_clusters:
|
||||||
|
cluster = self._out_clusters[cluster_key]
|
||||||
|
elif issubclass(cluster_key, Zcl_Cluster):
|
||||||
|
cluster_id = cluster_key.cluster_id
|
||||||
|
if cluster_id in self._in_clusters:
|
||||||
|
cluster = self._in_clusters[cluster_id]
|
||||||
|
elif cluster_id in self._out_clusters:
|
||||||
|
cluster = self._out_clusters[cluster_id]
|
||||||
|
return cluster
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zcl_reporting_config(self):
|
||||||
|
"""Return a dict of ZCL attribute reporting configuration.
|
||||||
|
|
||||||
|
{
|
||||||
|
Cluster_Class: {
|
||||||
|
attr_id: (min_report_interval, max_report_interval, change),
|
||||||
|
attr_name: (min_rep_interval, max_rep_interval, change)
|
||||||
|
}
|
||||||
|
Cluster_Instance: {
|
||||||
|
attr_id: (min_report_interval, max_report_interval, change),
|
||||||
|
attr_name: (min_rep_interval, max_rep_interval, change)
|
||||||
|
}
|
||||||
|
cluster_id: {
|
||||||
|
attr_id: (min_report_interval, max_report_interval, change),
|
||||||
|
attr_name: (min_rep_interval, max_rep_interval, change)
|
||||||
|
}
|
||||||
|
'cluster_name': {
|
||||||
|
attr_id: (min_report_interval, max_report_interval, change),
|
||||||
|
attr_name: (min_rep_interval, max_rep_interval, change)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
return dict()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self) -> str:
|
def unique_id(self) -> str:
|
||||||
"""Return a unique ID."""
|
"""Return a unique ID."""
|
||||||
|
|
|
@ -7,7 +7,9 @@ https://home-assistant.io/components/zha/
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from .const import DEFAULT_BAUDRATE, RadioType
|
from .const import (
|
||||||
|
DEFAULT_BAUDRATE, REPORT_CONFIG_MAX_INT, REPORT_CONFIG_MIN_INT,
|
||||||
|
REPORT_CONFIG_RPT_CHANGE, RadioType)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -31,8 +33,10 @@ async def safe_read(cluster, attributes, allow_cache=True, only_cache=False):
|
||||||
|
|
||||||
|
|
||||||
async def configure_reporting(entity_id, cluster, attr, skip_bind=False,
|
async def configure_reporting(entity_id, cluster, attr, skip_bind=False,
|
||||||
min_report=300, max_report=900,
|
min_report=REPORT_CONFIG_MIN_INT,
|
||||||
reportable_change=1):
|
max_report=REPORT_CONFIG_MAX_INT,
|
||||||
|
reportable_change=REPORT_CONFIG_RPT_CHANGE,
|
||||||
|
manufacturer=None):
|
||||||
"""Configure attribute reporting for a cluster.
|
"""Configure attribute reporting for a cluster.
|
||||||
|
|
||||||
while swallowing the DeliverError exceptions in case of unreachable
|
while swallowing the DeliverError exceptions in case of unreachable
|
||||||
|
@ -56,7 +60,8 @@ async def configure_reporting(entity_id, cluster, attr, skip_bind=False,
|
||||||
|
|
||||||
try:
|
try:
|
||||||
res = await cluster.configure_reporting(attr, min_report,
|
res = await cluster.configure_reporting(attr, min_report,
|
||||||
max_report, reportable_change)
|
max_report, reportable_change,
|
||||||
|
manufacturer=manufacturer)
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"%s: reporting '%s' attr on '%s' cluster: %d/%d/%d: Result: '%s'",
|
"%s: reporting '%s' attr on '%s' cluster: %d/%d/%d: Result: '%s'",
|
||||||
entity_id, attr_name, cluster_name, min_report, max_report,
|
entity_id, attr_name, cluster_name, min_report, max_report,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue