Fix ZHA electrical measurement sensor initialization (#37915)

* Refactor cached ZHA channel reads.

If doing a cached ZCL attribute read, do "only_from_cache" read for
battery operated devices only. Mains operated devices will do a network
read in case of a cache miss.

* Use cached attributes for ZHA electrical measurement

* Bump up ZHA zigpy dependency.
This commit is contained in:
Alexei Chetroi 2020-07-16 16:25:42 -04:00 committed by GitHub
parent 716cee6907
commit 33dc015083
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 23 deletions

View file

@ -245,7 +245,7 @@ class ZigbeeChannel(LogMixin):
self._cluster,
[attribute],
allow_cache=from_cache,
only_cache=from_cache,
only_cache=from_cache and not self._ch_pool.is_mains_powered,
manufacturer=manufacturer,
)
return result.get(attribute)
@ -260,7 +260,7 @@ class ZigbeeChannel(LogMixin):
result, _ = await self.cluster.read_attributes(
attributes,
allow_cache=from_cache,
only_cache=from_cache,
only_cache=from_cache and not self._ch_pool.is_mains_powered,
manufacturer=manufacturer,
)
return result

View file

@ -4,7 +4,7 @@ from typing import Optional
import zigpy.zcl.clusters.homeautomation as homeautomation
from .. import registries, typing as zha_typing
from .. import registries
from ..const import (
CHANNEL_ELECTRICAL_MEASUREMENT,
REPORT_CONFIG_DEFAULT,
@ -51,14 +51,6 @@ class ElectricalMeasurementChannel(ZigbeeChannel):
REPORT_CONFIG = ({"attr": "active_power", "config": REPORT_CONFIG_DEFAULT},)
def __init__(
self, cluster: zha_typing.ZigpyClusterType, ch_pool: zha_typing.ChannelPoolType
) -> None:
"""Initialize Metering."""
super().__init__(cluster, ch_pool)
self._divisor = None
self._multiplier = None
async def async_update(self):
"""Retrieve latest state."""
self.debug("async_update")
@ -80,7 +72,9 @@ class ElectricalMeasurementChannel(ZigbeeChannel):
async def fetch_config(self, from_cache):
"""Fetch config from device and updates format specifier."""
results = await self.get_attributes(
# prime the cache
await self.get_attributes(
[
"ac_power_divisor",
"power_divisor",
@ -89,22 +83,20 @@ class ElectricalMeasurementChannel(ZigbeeChannel):
],
from_cache=from_cache,
)
self._divisor = results.get(
"ac_power_divisor", results.get("power_divisor", self._divisor)
)
self._multiplier = results.get(
"ac_power_multiplier", results.get("power_multiplier", self._multiplier)
)
@property
def divisor(self) -> Optional[int]:
"""Return active power divisor."""
return self._divisor or 1
return self.cluster.get(
"ac_power_divisor", self.cluster.get("power_divisor", 1)
)
@property
def multiplier(self) -> Optional[int]:
"""Return active power divisor."""
return self._multiplier or 1
return self.cluster.get(
"ac_power_multiplier", self.cluster.get("power_multiplier", 1)
)
@registries.ZIGBEE_CHANNEL_REGISTRY.register(

View file

@ -9,7 +9,7 @@
"zha-quirks==0.0.42",
"zigpy-cc==0.4.4",
"zigpy-deconz==0.9.2",
"zigpy==0.22.1",
"zigpy==0.22.2",
"zigpy-xbee==0.12.1",
"zigpy-zigate==0.6.1"
],

View file

@ -2269,7 +2269,7 @@ zigpy-xbee==0.12.1
zigpy-zigate==0.6.1
# homeassistant.components.zha
zigpy==0.22.1
zigpy==0.22.2
# homeassistant.components.zoneminder
zm-py==0.4.0

View file

@ -999,4 +999,4 @@ zigpy-xbee==0.12.1
zigpy-zigate==0.6.1
# homeassistant.components.zha
zigpy==0.22.1
zigpy==0.22.2

View file

@ -265,3 +265,58 @@ async def test_temp_uom(
assert state is not None
assert round(float(state.state)) == expected
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == uom
async def test_electrical_measurement_init(
hass, zigpy_device_mock, zha_device_joined,
):
"""Test proper initialization of the electrical measurement cluster."""
cluster_id = homeautomation.ElectricalMeasurement.cluster_id
zigpy_device = zigpy_device_mock(
{
1: {
"in_clusters": [cluster_id, general.Basic.cluster_id],
"out_cluster": [],
"device_type": 0x0000,
}
}
)
cluster = zigpy_device.endpoints[1].in_clusters[cluster_id]
zha_device = await zha_device_joined(zigpy_device)
entity_id = await find_entity_id(DOMAIN, zha_device, hass)
# allow traffic to flow through the gateway and devices
await async_enable_traffic(hass, [zha_device])
# test that the sensor now have a state of unknown
assert hass.states.get(entity_id).state == STATE_UNKNOWN
await send_attributes_report(hass, cluster, {0: 1, 1291: 100, 10: 1000})
assert int(hass.states.get(entity_id).state) == 100
channel = zha_device.channels.pools[0].all_channels["1:0x0b04"]
assert channel.divisor == 1
assert channel.multiplier == 1
# update power divisor
await send_attributes_report(hass, cluster, {0: 1, 1291: 20, 0x0403: 5, 10: 1000})
assert channel.divisor == 5
assert channel.multiplier == 1
assert hass.states.get(entity_id).state == "4.0"
await send_attributes_report(hass, cluster, {0: 1, 1291: 30, 0x0605: 10, 10: 1000})
assert channel.divisor == 10
assert channel.multiplier == 1
assert hass.states.get(entity_id).state == "3.0"
# update power multiplier
await send_attributes_report(hass, cluster, {0: 1, 1291: 20, 0x0402: 6, 10: 1000})
assert channel.divisor == 10
assert channel.multiplier == 6
assert hass.states.get(entity_id).state == "12.0"
await send_attributes_report(hass, cluster, {0: 1, 1291: 30, 0x0604: 20, 10: 1000})
assert channel.divisor == 10
assert channel.multiplier == 20
assert hass.states.get(entity_id).state == "60.0"