mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 04:37:06 +00:00
Refactor ZHA core channel initialization (#43953)
* Cleanup Basic channnel Remove unused methods. * Refactor async_configure() method Split async_configure() into async_configure() and async_configure_channel_specfici() * Refactor async_initilize() method Split into two different methods and configure channel specifics via async_configure_channel_specific() * Fixes
This commit is contained in:
parent
b19c705867
commit
125ceb7449
@ -73,13 +73,9 @@ class BinarySensor(ZhaEntity, BinarySensorEntity):
|
||||
self._channel = channels[0]
|
||||
self._device_class = self.DEVICE_CLASS
|
||||
|
||||
async def get_device_class(self):
|
||||
"""Get the HA device class from the channel."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Run when about to be added to hass."""
|
||||
await super().async_added_to_hass()
|
||||
await self.get_device_class()
|
||||
self.async_accept_signal(
|
||||
self._channel, SIGNAL_ATTR_UPDATED, self.async_set_state
|
||||
)
|
||||
@ -168,10 +164,10 @@ class IASZone(BinarySensor):
|
||||
|
||||
SENSOR_ATTR = "zone_status"
|
||||
|
||||
async def get_device_class(self) -> None:
|
||||
"""Get the HA device class from the channel."""
|
||||
zone_type = await self._channel.get_attribute_value("zone_type")
|
||||
self._device_class = CLASS_MAPPING.get(zone_type)
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
"""Return device class from component DEVICE_CLASSES."""
|
||||
return CLASS_MAPPING.get(self._channel.cluster.get("zone_type"))
|
||||
|
||||
async def async_update(self):
|
||||
"""Attempt to retrieve on off state from the binary sensor."""
|
||||
|
@ -187,29 +187,36 @@ class ZigbeeChannel(LogMixin):
|
||||
str(ex),
|
||||
)
|
||||
|
||||
async def async_configure(self):
|
||||
async def async_configure(self) -> None:
|
||||
"""Set cluster binding and attribute reporting."""
|
||||
if not self._ch_pool.skip_configuration:
|
||||
await self.bind()
|
||||
if self.cluster.is_server:
|
||||
await self.configure_reporting()
|
||||
ch_specific_cfg = getattr(self, "async_configure_channel_specific", None)
|
||||
if ch_specific_cfg:
|
||||
await ch_specific_cfg()
|
||||
self.debug("finished channel configuration")
|
||||
else:
|
||||
self.debug("skipping channel configuration")
|
||||
self._status = ChannelStatus.CONFIGURED
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
async def async_initialize(self, from_cache: bool) -> None:
|
||||
"""Initialize channel."""
|
||||
if not from_cache and self._ch_pool.skip_configuration:
|
||||
self._status = ChannelStatus.INITIALIZED
|
||||
return
|
||||
|
||||
self.debug("initializing channel: from_cache: %s", from_cache)
|
||||
attributes = []
|
||||
for report_config in self._report_config:
|
||||
attributes.append(report_config["attr"])
|
||||
attributes = [cfg["attr"] for cfg in self._report_config]
|
||||
if attributes:
|
||||
await self.get_attributes(attributes, from_cache=from_cache)
|
||||
|
||||
ch_specific_init = getattr(self, "async_initialize_channel_specific", None)
|
||||
if ch_specific_init:
|
||||
await ch_specific_init(from_cache=from_cache)
|
||||
|
||||
self.debug("finished channel configuration")
|
||||
self._status = ChannelStatus.INITIALIZED
|
||||
|
||||
@callback
|
||||
|
@ -35,11 +35,6 @@ class DoorLockChannel(ZigbeeChannel):
|
||||
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", attrid, attr_name, value
|
||||
)
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
"""Initialize channel."""
|
||||
await self.get_attribute_value(self._value_attribute, from_cache=from_cache)
|
||||
await super().async_initialize(from_cache)
|
||||
|
||||
|
||||
@registries.ZIGBEE_CHANNEL_REGISTRY.register(closures.Shade.cluster_id)
|
||||
class Shade(ZigbeeChannel):
|
||||
@ -85,8 +80,3 @@ class WindowCovering(ZigbeeChannel):
|
||||
self.async_send_signal(
|
||||
f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", attrid, attr_name, value
|
||||
)
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
"""Initialize channel."""
|
||||
await self.get_attribute_value(self._value_attribute, from_cache=from_cache)
|
||||
await super().async_initialize(from_cache)
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""General channels module for Zigbee Home Automation."""
|
||||
import asyncio
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any, Coroutine, List, Optional
|
||||
|
||||
import zigpy.exceptions
|
||||
import zigpy.zcl.clusters.general as general
|
||||
@ -19,7 +19,7 @@ from ..const import (
|
||||
SIGNAL_SET_LEVEL,
|
||||
SIGNAL_UPDATE_DEVICE,
|
||||
)
|
||||
from .base import ChannelStatus, ClientChannel, ZigbeeChannel, parse_and_log_command
|
||||
from .base import ClientChannel, ZigbeeChannel, parse_and_log_command
|
||||
|
||||
|
||||
@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.Alarms.cluster_id)
|
||||
@ -71,21 +71,6 @@ class BasicChannel(ZigbeeChannel):
|
||||
6: "Emergency mains and transfer switch",
|
||||
}
|
||||
|
||||
async def async_configure(self):
|
||||
"""Configure this channel."""
|
||||
await super().async_configure()
|
||||
await self.async_initialize(False)
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
"""Initialize channel."""
|
||||
if not self._ch_pool.skip_configuration or from_cache:
|
||||
await self.get_attribute_value("power_source", from_cache=from_cache)
|
||||
await super().async_initialize(from_cache)
|
||||
|
||||
def get_power_source(self):
|
||||
"""Get the power source."""
|
||||
return self.cluster.get("power_source")
|
||||
|
||||
|
||||
@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.BinaryInput.cluster_id)
|
||||
class BinaryInput(ZigbeeChannel):
|
||||
@ -189,11 +174,6 @@ class LevelControlChannel(ZigbeeChannel):
|
||||
"""Dispatch level change."""
|
||||
self.async_send_signal(f"{self.unique_id}_{command}", level)
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
"""Initialize channel."""
|
||||
await self.get_attribute_value(self.CURRENT_LEVEL, from_cache=from_cache)
|
||||
await super().async_initialize(from_cache)
|
||||
|
||||
|
||||
@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.MultistateInput.cluster_id)
|
||||
class MultistateInput(ZigbeeChannel):
|
||||
@ -284,12 +264,9 @@ class OnOffChannel(ZigbeeChannel):
|
||||
)
|
||||
self._state = bool(value)
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
async def async_initialize_channel_specific(self, from_cache: bool) -> None:
|
||||
"""Initialize channel."""
|
||||
await super().async_initialize(from_cache)
|
||||
state = await self.get_attribute_value(self.ON_OFF, from_cache=True)
|
||||
if state is not None:
|
||||
self._state = bool(state)
|
||||
self._state = self.on_off
|
||||
|
||||
async def async_update(self):
|
||||
"""Initialize channel."""
|
||||
@ -338,7 +315,7 @@ class PollControl(ZigbeeChannel):
|
||||
CHECKIN_FAST_POLL_TIMEOUT = 2 * 4 # 2s
|
||||
LONG_POLL = 6 * 4 # 6s
|
||||
|
||||
async def async_configure(self) -> None:
|
||||
async def async_configure_channel_specific(self) -> None:
|
||||
"""Configure channel: set check-in interval."""
|
||||
try:
|
||||
res = await self.cluster.write_attributes(
|
||||
@ -347,7 +324,6 @@ class PollControl(ZigbeeChannel):
|
||||
self.debug("%ss check-in interval set: %s", self.CHECKIN_INTERVAL / 4, res)
|
||||
except (asyncio.TimeoutError, zigpy.exceptions.ZigbeeException) as ex:
|
||||
self.debug("Couldn't set check-in interval: %s", ex)
|
||||
await super().async_configure()
|
||||
|
||||
@callback
|
||||
def cluster_command(
|
||||
@ -375,16 +351,13 @@ class PowerConfigurationChannel(ZigbeeChannel):
|
||||
{"attr": "battery_percentage_remaining", "config": REPORT_CONFIG_BATTERY_SAVE},
|
||||
)
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
"""Initialize channel."""
|
||||
def async_initialize_channel_specific(self, from_cache: bool) -> Coroutine:
|
||||
"""Initialize channel specific attrs."""
|
||||
attributes = [
|
||||
"battery_size",
|
||||
"battery_percentage_remaining",
|
||||
"battery_voltage",
|
||||
"battery_quantity",
|
||||
]
|
||||
await self.get_attributes(attributes, from_cache=from_cache)
|
||||
self._status = ChannelStatus.INITIALIZED
|
||||
return self.get_attributes(attributes, from_cache=from_cache)
|
||||
|
||||
|
||||
@registries.ZIGBEE_CHANNEL_REGISTRY.register(general.PowerProfile.cluster_id)
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""Home automation channels module for Zigbee Home Automation."""
|
||||
from typing import Optional
|
||||
from typing import Coroutine, Optional
|
||||
|
||||
import zigpy.zcl.clusters.homeautomation as homeautomation
|
||||
|
||||
@ -62,23 +62,17 @@ class ElectricalMeasurementChannel(ZigbeeChannel):
|
||||
result,
|
||||
)
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
"""Initialize channel."""
|
||||
await self.fetch_config(True)
|
||||
await super().async_initialize(from_cache)
|
||||
def async_initialize_channel_specific(self, from_cache: bool) -> Coroutine:
|
||||
"""Initialize channel specific attributes."""
|
||||
|
||||
async def fetch_config(self, from_cache):
|
||||
"""Fetch config from device and updates format specifier."""
|
||||
|
||||
# prime the cache
|
||||
await self.get_attributes(
|
||||
return self.get_attributes(
|
||||
[
|
||||
"ac_power_divisor",
|
||||
"power_divisor",
|
||||
"ac_power_multiplier",
|
||||
"power_multiplier",
|
||||
],
|
||||
from_cache=from_cache,
|
||||
from_cache=True,
|
||||
)
|
||||
|
||||
@property
|
||||
|
@ -362,7 +362,7 @@ class ThermostatChannel(ZigbeeChannel):
|
||||
)
|
||||
|
||||
@retryable_req(delays=(1, 1, 3))
|
||||
async def async_initialize(self, from_cache):
|
||||
async def async_initialize_channel_specific(self, from_cache: bool) -> None:
|
||||
"""Initialize channel."""
|
||||
|
||||
cached = [a for a, cached in self._init_attrs.items() if cached]
|
||||
@ -370,7 +370,6 @@ class ThermostatChannel(ZigbeeChannel):
|
||||
|
||||
await self._chunk_attr_read(cached, cached=True)
|
||||
await self._chunk_attr_read(uncached, cached=False)
|
||||
await super().async_initialize(from_cache)
|
||||
|
||||
async def async_set_operation_mode(self, mode) -> bool:
|
||||
"""Set Operation mode."""
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""Lighting channels module for Zigbee Home Automation."""
|
||||
from typing import Optional
|
||||
from typing import Coroutine, Optional
|
||||
|
||||
import zigpy.zcl.clusters.lighting as lighting
|
||||
|
||||
@ -75,15 +75,13 @@ class ColorChannel(ZigbeeChannel):
|
||||
"""Return the warmest color_temp that this channel supports."""
|
||||
return self.cluster.get("color_temp_physical_max", self.MAX_MIREDS)
|
||||
|
||||
async def async_configure(self) -> None:
|
||||
def async_configure_channel_specific(self) -> Coroutine:
|
||||
"""Configure channel."""
|
||||
await self.fetch_color_capabilities(False)
|
||||
await super().async_configure()
|
||||
return self.fetch_color_capabilities(False)
|
||||
|
||||
async def async_initialize(self, from_cache: bool) -> None:
|
||||
def async_initialize_channel_specific(self, from_cache: bool) -> Coroutine:
|
||||
"""Initialize channel."""
|
||||
await self.fetch_color_capabilities(True)
|
||||
await super().async_initialize(from_cache)
|
||||
return self.fetch_color_capabilities(True)
|
||||
|
||||
async def fetch_color_capabilities(self, from_cache: bool) -> None:
|
||||
"""Get the color configuration."""
|
||||
|
@ -5,6 +5,7 @@ For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/integrations/zha/
|
||||
"""
|
||||
import asyncio
|
||||
from typing import Coroutine
|
||||
|
||||
from zigpy.exceptions import ZigbeeException
|
||||
import zigpy.zcl.clusters.security as security
|
||||
@ -20,7 +21,7 @@ from ..const import (
|
||||
WARNING_DEVICE_STROBE_HIGH,
|
||||
WARNING_DEVICE_STROBE_YES,
|
||||
)
|
||||
from .base import ZigbeeChannel
|
||||
from .base import ChannelStatus, ZigbeeChannel
|
||||
|
||||
|
||||
@registries.ZIGBEE_CHANNEL_REGISTRY.register(security.IasAce.cluster_id)
|
||||
@ -155,14 +156,10 @@ class IASZoneChannel(ZigbeeChannel):
|
||||
str(ex),
|
||||
)
|
||||
|
||||
try:
|
||||
self.debug("Sending pro-active IAS enroll response")
|
||||
await self._cluster.enroll_response(0, 0)
|
||||
except ZigbeeException as ex:
|
||||
self.debug(
|
||||
"Failed to send pro-active IAS enroll response: %s",
|
||||
str(ex),
|
||||
)
|
||||
self.debug("Sending pro-active IAS enroll response")
|
||||
self._cluster.create_catching_task(self._cluster.enroll_response(0, 0))
|
||||
|
||||
self._status = ChannelStatus.CONFIGURED
|
||||
self.debug("finished IASZoneChannel configuration")
|
||||
|
||||
@callback
|
||||
@ -177,8 +174,7 @@ class IASZoneChannel(ZigbeeChannel):
|
||||
value,
|
||||
)
|
||||
|
||||
async def async_initialize(self, from_cache):
|
||||
def async_initialize_channel_specific(self, from_cache: bool) -> Coroutine:
|
||||
"""Initialize channel."""
|
||||
attributes = ["zone_status", "zone_state"]
|
||||
await self.get_attributes(attributes, from_cache=from_cache)
|
||||
await super().async_initialize(from_cache)
|
||||
attributes = ["zone_status", "zone_state", "zone_type"]
|
||||
return self.get_attributes(attributes, from_cache=from_cache)
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""Smart energy channels module for Zigbee Home Automation."""
|
||||
from typing import Union
|
||||
from typing import Coroutine, Union
|
||||
|
||||
import zigpy.zcl.clusters.smartenergy as smartenergy
|
||||
|
||||
@ -96,15 +96,13 @@ class Metering(ZigbeeChannel):
|
||||
"""Return multiplier for the value."""
|
||||
return self.cluster.get("multiplier")
|
||||
|
||||
async def async_configure(self) -> None:
|
||||
def async_configure_channel_specific(self) -> Coroutine:
|
||||
"""Configure channel."""
|
||||
await self.fetch_config(False)
|
||||
await super().async_configure()
|
||||
return self.fetch_config(False)
|
||||
|
||||
async def async_initialize(self, from_cache: bool) -> None:
|
||||
def async_initialize_channel_specific(self, from_cache: bool) -> Coroutine:
|
||||
"""Initialize channel."""
|
||||
await self.fetch_config(True)
|
||||
await super().async_initialize(from_cache)
|
||||
return self.fetch_config(True)
|
||||
|
||||
@callback
|
||||
def attribute_updated(self, attrid: int, value: int) -> None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user