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

ZHA entity ZCL reporting configuration #19177

Merged
merged 5 commits into from Dec 19, 2018
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
31 changes: 15 additions & 16 deletions homeassistant/components/binary_sensor/zha.py
Expand Up @@ -9,7 +9,7 @@
from homeassistant.components.binary_sensor import DOMAIN, BinarySensorDevice
from homeassistant.components.zha import helpers
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.helpers.dispatcher import async_dispatcher_connect

Expand Down Expand Up @@ -89,21 +89,7 @@ async def _async_setup_remote(discovery_info):
remote = Remote(**discovery_info)

if discovery_info['new_join']:
from zigpy.zcl.clusters.general import OnOff, LevelControl
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
)

await remote.async_configure()
return remote


Expand Down Expand Up @@ -238,6 +224,14 @@ def __init__(self, **kwargs):
general.OnOff.cluster_id: self.OnOffListener(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
def should_poll(self) -> bool:
Expand All @@ -257,6 +251,11 @@ def device_state_attributes(self):
})
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):
"""Increment the level, setting state if appropriate."""
if not self._state and change > 0:
Expand Down
31 changes: 28 additions & 3 deletions homeassistant/components/fan/zha.py
Expand Up @@ -11,7 +11,7 @@
FanEntity)
from homeassistant.components.zha import helpers
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.helpers.dispatcher import async_dispatcher_connect

Expand Down Expand Up @@ -70,7 +70,10 @@ async def _async_setup_entities(hass, config_entry, async_add_entities,
"""Set up the ZHA fans."""
entities = []
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)

Expand All @@ -79,6 +82,19 @@ class ZhaFan(ZhaEntity, FanEntity):
"""Representation of a ZHA fan."""

_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
def supported_features(self) -> int:
Expand Down Expand Up @@ -129,7 +145,7 @@ async def async_set_speed(self, speed: str) -> None:

async def async_update(self):
"""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,
only_cache=(not self._initialized))
new_value = result.get('fan_mode', None)
Expand All @@ -142,3 +158,12 @@ def should_poll(self) -> bool:
False if entity pushes its state to HA.
"""
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()
21 changes: 19 additions & 2 deletions homeassistant/components/light/zha.py
Expand Up @@ -9,7 +9,8 @@
from homeassistant.components import light
from homeassistant.components.zha import helpers
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.helpers.dispatcher import async_dispatcher_connect
import homeassistant.util.color as color_util
Expand Down Expand Up @@ -73,7 +74,10 @@ async def _async_setup_entities(hass, config_entry, async_add_entities,
UNSUPPORTED_ATTRIBUTE):
discovery_info['color_capabilities'] |= \
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)

Expand Down Expand Up @@ -105,6 +109,19 @@ def __init__(self, **kwargs):
self._supported_features |= light.SUPPORT_COLOR
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
def is_on(self) -> bool:
"""Return true if entity is on."""
Expand Down
36 changes: 27 additions & 9 deletions homeassistant/components/sensor/zha.py
Expand Up @@ -9,7 +9,8 @@
from homeassistant.components.sensor import DOMAIN
from homeassistant.components.zha import helpers
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.const import TEMP_CELSIUS
from homeassistant.helpers.dispatcher import async_dispatcher_connect
Expand Down Expand Up @@ -81,11 +82,7 @@ async def make_sensor(discovery_info):
sensor = Sensor(**discovery_info)

if discovery_info['new_join']:
cluster = list(in_clusters.values())[0]
await helpers.configure_reporting(
sensor.entity_id, cluster, sensor.value_attribute,
reportable_change=sensor.min_reportable_change
)
await sensor.async_configure()

return sensor

Expand All @@ -95,7 +92,28 @@ class Sensor(ZhaEntity):

_domain = DOMAIN
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
def should_poll(self) -> bool:
Expand All @@ -119,7 +137,7 @@ def attribute_updated(self, attribute, value):
async def async_update(self):
"""Retrieve latest state."""
result = await helpers.safe_read(
list(self._in_clusters.values())[0],
self.cluster,
[self.value_attribute],
allow_cache=False,
only_cache=(not self._initialized)
Expand Down Expand Up @@ -251,6 +269,6 @@ async def async_update(self):
_LOGGER.debug("%s async_update", self.entity_id)

result = await helpers.safe_read(
self._endpoint.electrical_measurement, ['active_power'],
self.cluster, ['active_power'],
allow_cache=False, only_cache=(not self._initialized))
self._state = result.get('active_power', self._state)
22 changes: 14 additions & 8 deletions homeassistant/components/switch/zha.py
Expand Up @@ -9,7 +9,7 @@
from homeassistant.components.switch import DOMAIN, SwitchDevice
from homeassistant.components.zha import helpers
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.helpers.dispatcher import async_dispatcher_connect

Expand Down Expand Up @@ -44,17 +44,11 @@ async def async_discover(discovery_info):
async def _async_setup_entities(hass, config_entry, async_add_entities,
discovery_infos):
"""Set up the ZHA switches."""
from zigpy.zcl.clusters.general import OnOff
entities = []
for discovery_info in discovery_infos:
switch = Switch(**discovery_info)
if discovery_info['new_join']:
in_clusters = discovery_info['in_clusters']
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
)
await switch.async_configure()
entities.append(switch)

async_add_entities(entities, update_before_add=True)
Expand All @@ -76,6 +70,18 @@ def attribute_updated(self, attribute, value):
self._state = value
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
def should_poll(self) -> bool:
"""Let zha handle polling."""
Expand Down
21 changes: 21 additions & 0 deletions homeassistant/components/zha/const.py
Expand Up @@ -56,6 +56,27 @@ def list(cls):
COMPONENT_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():
"""Populate data using constants from bellows.
Expand Down