Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion homeassistant/components/zha/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ async def async_update(self):
"""Attempt to retrieve on off state from the binary sensor."""
await super().async_update()
attribute = getattr(self._channel, "value_attribute", "on_off")
self._state = await self._channel.get_attribute_value(attribute)
attr_value = await self._channel.get_attribute_value(attribute)
if attr_value is not None:
self._state = attr_value


@STRICT_MATCH(channel_names=CHANNEL_ACCELEROMETER)
Expand Down
10 changes: 10 additions & 0 deletions homeassistant/components/zha/core/channels/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ def nwk(self) -> int:
"""Device NWK for logging."""
return self._channels.zha_device.nwk

@property
def is_mains_powered(self) -> bool:
"""Device is_mains_powered."""
return self._channels.zha_device.is_mains_powered

@property
def manufacturer(self) -> Optional[str]:
"""Return device manufacturer."""
Expand All @@ -201,6 +206,11 @@ def manufacturer_code(self) -> Optional[int]:
"""Return device manufacturer."""
return self._channels.zha_device.manufacturer_code

@property
def hass(self):
"""Return hass."""
return self._channels.zha_device.hass

@property
def model(self) -> Optional[str]:
"""Return device model."""
Expand Down
33 changes: 30 additions & 3 deletions homeassistant/components/zha/core/channels/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
REPORT_CONFIG_RPT_CHANGE,
SIGNAL_ATTR_UPDATED,
)
from ..helpers import LogMixin, get_attr_id_by_name, safe_read
from ..helpers import LogMixin, safe_read

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -98,7 +98,7 @@ def __init__(
if not hasattr(self, "_value_attribute") and len(self._report_config) > 0:
attr = self._report_config[0].get("attr")
if isinstance(attr, str):
self.value_attribute = get_attr_id_by_name(self.cluster, attr)
self.value_attribute = self.cluster.attridx.get(attr)
else:
self.value_attribute = attr
self._status = ChannelStatus.CREATED
Expand Down Expand Up @@ -212,8 +212,11 @@ async def async_configure(self):
async def async_initialize(self, from_cache):
"""Initialize channel."""
self.debug("initializing channel: from_cache: %s", from_cache)
attributes = []
for report_config in self._report_config:
await self.get_attribute_value(report_config["attr"], from_cache=from_cache)
attributes.append(report_config["attr"])
if len(attributes) > 0:
await self.get_attributes(attributes, from_cache=from_cache)
self._status = ChannelStatus.INITIALIZED

@callback
Expand Down Expand Up @@ -267,6 +270,30 @@ async def get_attribute_value(self, attribute, from_cache=True):
)
return result.get(attribute)

async def get_attributes(self, attributes, from_cache=True):
"""Get the values for a list of attributes."""
manufacturer = None
manufacturer_code = self._ch_pool.manufacturer_code
if self.cluster.cluster_id >= 0xFC00 and manufacturer_code:
manufacturer = manufacturer_code
try:
result, _ = await self.cluster.read_attributes(
attributes,
allow_cache=from_cache,
only_cache=from_cache,
manufacturer=manufacturer,
)
results = {attribute: result.get(attribute) for attribute in attributes}
except (asyncio.TimeoutError, zigpy.exceptions.DeliveryError) as ex:
self.debug(
"failed to get attributes '%s' on '%s' cluster: %s",
attributes,
self.cluster.ep_attribute,
str(ex),
)
results = {}
return results

def log(self, level, msg, *args):
"""Log a message."""
msg = f"[%s:%s]: {msg}"
Expand Down
21 changes: 11 additions & 10 deletions homeassistant/components/zha/core/channels/closures.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ class DoorLockChannel(ZigbeeChannel):
async def async_update(self):
"""Retrieve latest state."""
result = await self.get_attribute_value("lock_state", from_cache=True)

self.async_send_signal(
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", 0, "lock_state", result
)
if result is not None:
self.async_send_signal(
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", 0, "lock_state", result
)

@callback
def attribute_updated(self, attrid, value):
Expand Down Expand Up @@ -67,12 +67,13 @@ async def async_update(self):
"current_position_lift_percentage", from_cache=False
)
self.debug("read current position: %s", result)
self.async_send_signal(
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}",
8,
"current_position_lift_percentage",
result,
)
if result is not None:
self.async_send_signal(
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}",
8,
"current_position_lift_percentage",
result,
)

@callback
def attribute_updated(self, attrid, value):
Expand Down
37 changes: 20 additions & 17 deletions homeassistant/components/zha/core/channels/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
SIGNAL_SET_LEVEL,
SIGNAL_STATE_ATTR,
)
from ..helpers import get_attr_id_by_name
from .base import ZigbeeChannel, parse_and_log_command

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -90,9 +89,11 @@ async def async_configure(self):

async def async_initialize(self, from_cache):
"""Initialize channel."""
self._power_source = await self.get_attribute_value(
power_source = await self.get_attribute_value(
"power_source", from_cache=from_cache
)
if power_source is not None:
self._power_source = power_source
await super().async_initialize(from_cache)

def get_power_source(self):
Expand Down Expand Up @@ -269,7 +270,7 @@ def cluster_command(self, tsn, command_id, args):
self.attribute_updated(self.ON_OFF, True)
if on_time > 0:
self._off_listener = async_call_later(
self.device.hass,
self._ch_pool.hass,
(on_time / 10), # value is in 10ths of a second
self.set_to_off,
)
Expand All @@ -293,19 +294,20 @@ def attribute_updated(self, attrid, value):

async def async_initialize(self, from_cache):
"""Initialize channel."""
self._state = bool(
await self.get_attribute_value(self.ON_OFF, from_cache=from_cache)
)
state = await self.get_attribute_value(self.ON_OFF, from_cache=from_cache)
if state is not None:
self._state = bool(state)
await super().async_initialize(from_cache)

async def async_update(self):
"""Initialize channel."""
if self.cluster.is_client:
return
self.debug("attempting to update onoff state - from cache: False")
self._state = bool(
await self.get_attribute_value(self.ON_OFF, from_cache=False)
)
from_cache = not self._ch_pool.is_mains_powered
self.debug("attempting to update onoff state - from cache: %s", from_cache)
state = await self.get_attribute_value(self.ON_OFF, from_cache=from_cache)
if state is not None:
self._state = bool(state)
await super().async_update()


Expand Down Expand Up @@ -352,7 +354,7 @@ def attribute_updated(self, attrid, value):
"""Handle attribute updates on this cluster."""
attr = self._report_config[1].get("attr")
if isinstance(attr, str):
attr_id = get_attr_id_by_name(self.cluster, attr)
attr_id = self.cluster.attridx.get(attr)
else:
attr_id = attr
if attrid == attr_id:
Expand All @@ -379,12 +381,13 @@ async def async_update(self):

async def async_read_state(self, from_cache):
"""Read data from the cluster."""
await self.get_attribute_value("battery_size", from_cache=from_cache)
await self.get_attribute_value(
"battery_percentage_remaining", from_cache=from_cache
)
await self.get_attribute_value("battery_voltage", from_cache=from_cache)
await self.get_attribute_value("battery_quantity", from_cache=from_cache)
attributes = [
"battery_size",
"battery_percentage_remaining",
"battery_voltage",
"battery_quantity",
]
await self.get_attributes(attributes, from_cache=from_cache)


@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.PowerProfile.cluster_id)
Expand Down
14 changes: 11 additions & 3 deletions homeassistant/components/zha/core/channels/homeautomation.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,13 @@ async def async_update(self):

# This is a polling channel. Don't allow cache.
result = await self.get_attribute_value("active_power", from_cache=False)
self.async_send_signal(
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", 0x050B, "active_power", result
)
if result is not None:
self.async_send_signal(
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}",
0x050B,
"active_power",
result,
)

async def async_initialize(self, from_cache):
"""Initialize channel."""
Expand All @@ -92,6 +96,8 @@ async def fetch_config(self, from_cache):
divisor = await self.get_attribute_value(
"power_divisor", from_cache=from_cache
)
if divisor is None:
divisor = 1
self._divisor = divisor

mult = await self.get_attribute_value(
Expand All @@ -101,6 +107,8 @@ async def fetch_config(self, from_cache):
mult = await self.get_attribute_value(
"power_multiplier", from_cache=from_cache
)
if mult is None:
mult = 1
self._multiplier = mult

@property
Expand Down
7 changes: 4 additions & 3 deletions homeassistant/components/zha/core/channels/hvac.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ async def async_set_speed(self, value) -> None:
async def async_update(self):
"""Retrieve latest state."""
result = await self.get_attribute_value("fan_mode", from_cache=True)
self.async_send_signal(
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", 0, "fan_mode", result
)
if result is not None:
self.async_send_signal(
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", 0, "fan_mode", result
)

@callback
def attribute_updated(self, attrid, value):
Expand Down
9 changes: 4 additions & 5 deletions homeassistant/components/zha/core/channels/lighting.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ColorChannel(ZigbeeChannel):
)

def __init__(
self, cluster: zha_typing.ZigpyClusterType, ch_pool: zha_typing.ChannelPoolType,
self, cluster: zha_typing.ZigpyClusterType, ch_pool: zha_typing.ChannelPoolType
) -> None:
"""Initialize ColorChannel."""
super().__init__(cluster, ch_pool)
Expand All @@ -52,9 +52,8 @@ async def async_configure(self):
async def async_initialize(self, from_cache):
"""Initialize channel."""
await self.fetch_color_capabilities(True)
await self.get_attribute_value("color_temperature", from_cache=from_cache)
await self.get_attribute_value("current_x", from_cache=from_cache)
await self.get_attribute_value("current_y", from_cache=from_cache)
attributes = ["color_temperature", "current_x", "current_y"]
await self.get_attributes(attributes, from_cache=from_cache)

async def fetch_color_capabilities(self, from_cache):
"""Get the color configuration."""
Expand All @@ -72,7 +71,7 @@ async def fetch_color_capabilities(self, from_cache):
"color_temperature", from_cache=from_cache
)

if result is not self.UNSUPPORTED_ATTRIBUTE:
if result is not None and result is not self.UNSUPPORTED_ATTRIBUTE:
capabilities |= self.CAPABILITIES_COLOR_TEMP
self._color_capabilities = capabilities
await super().async_initialize(from_cache)
4 changes: 2 additions & 2 deletions homeassistant/components/zha/core/channels/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,6 @@ def attribute_updated(self, attrid, value):

async def async_initialize(self, from_cache):
"""Initialize channel."""
await self.get_attribute_value("zone_status", from_cache=from_cache)
await self.get_attribute_value("zone_state", from_cache=from_cache)
attributes = ["zone_status", "zone_state"]
await self.get_attributes(attributes, from_cache=from_cache)
await super().async_initialize(from_cache)
12 changes: 0 additions & 12 deletions homeassistant/components/zha/core/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,6 @@ async def safe_read(
return {}


def get_attr_id_by_name(cluster, attr_name):
"""Get the attribute id for a cluster attribute by its name."""
return next(
(
attrid
for attrid, (attrname, datatype) in cluster.attributes.items()
if attr_name == attrname
),
None,
)


async def get_matched_clusters(source_zha_device, target_zha_device):
"""Get matched input/output cluster pairs for 2 devices."""
source_clusters = source_zha_device.async_get_std_clusters()
Expand Down
Loading