From d729016c2121fc1fb39f9e89dd2d772319db22f4 Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Wed, 25 Feb 2026 03:16:26 +0100 Subject: [PATCH 1/4] Remove request `isinstance` `Exception` checks from switch --- zha/application/platforms/switch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zha/application/platforms/switch.py b/zha/application/platforms/switch.py index d3f60f4f8..e4a6b4b11 100644 --- a/zha/application/platforms/switch.py +++ b/zha/application/platforms/switch.py @@ -292,7 +292,7 @@ def is_on(self) -> bool: async def async_turn_on(self) -> None: """Turn the entity on.""" result = await self._on_off_cluster_handler.on() - if isinstance(result, Exception) or result[1] is not Status.SUCCESS: + if result[1] is not Status.SUCCESS: return self._state = True self.maybe_emit_state_changed_event() @@ -300,7 +300,7 @@ async def async_turn_on(self) -> None: async def async_turn_off(self) -> None: """Turn the entity off.""" result = await self._on_off_cluster_handler.off() - if isinstance(result, Exception) or result[1] is not Status.SUCCESS: + if result[1] is not Status.SUCCESS: return self._state = False self.maybe_emit_state_changed_event() From 3aa44c292b600e567e052a539bb586b1fc99c957 Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Wed, 25 Feb 2026 03:27:08 +0100 Subject: [PATCH 2/4] Remove from platforms --- zha/application/platforms/cover/__init__.py | 53 +++++---------------- zha/application/platforms/light/__init__.py | 37 -------------- zha/application/platforms/lock/__init__.py | 11 +---- zha/application/platforms/switch.py | 9 +--- zha/application/platforms/update.py | 9 +--- zha/zigbee/cluster_handlers/general.py | 10 +--- 6 files changed, 18 insertions(+), 111 deletions(-) diff --git a/zha/application/platforms/cover/__init__.py b/zha/application/platforms/cover/__init__.py index 599ecbe17..770d14957 100644 --- a/zha/application/platforms/cover/__init__.py +++ b/zha/application/platforms/cover/__init__.py @@ -12,7 +12,6 @@ from zigpy.profiles import zha from zigpy.zcl.clusters.closures import WindowCovering from zigpy.zcl.clusters.general import OnOff, OnOff as OnOffCluster -from zigpy.zcl.foundation import Status from zha.application import Platform from zha.application.platforms import ( @@ -33,7 +32,6 @@ CoverState, WCAttrs, ) -from zha.exceptions import ZHAException from zha.zigbee.cluster_handlers import ClusterAttributeUpdatedEvent from zha.zigbee.cluster_handlers.closures import WindowCoveringClusterHandler from zha.zigbee.cluster_handlers.const import ( @@ -575,10 +573,7 @@ def async_update_state(self, state): async def async_open_cover(self) -> None: """Open the cover.""" self._set_lift_transition_target(POSITION_OPEN) - res = await self._cover_cluster_handler.up_open() - if res[1] is not Status.SUCCESS: - self._clear_lift_transition() - raise ZHAException(f"Failed to open cover: {res[1]}") + await self._cover_cluster_handler.up_open() if self.current_cover_position != POSITION_OPEN: self.async_update_state(CoverState.OPENING) @@ -587,12 +582,9 @@ async def async_open_cover(self) -> None: async def async_open_cover_tilt(self) -> None: """Open the cover tilt.""" self._set_tilt_transition_target(POSITION_OPEN) - res = await self._cover_cluster_handler.go_to_tilt_percentage( + await self._cover_cluster_handler.go_to_tilt_percentage( self._ha_position_to_zcl(POSITION_OPEN) ) - if res[1] is not Status.SUCCESS: - self._clear_tilt_transition() - raise ZHAException(f"Failed to open cover tilt: {res[1]}") if self.current_cover_tilt_position != POSITION_OPEN: self.async_update_state(CoverState.OPENING) @@ -601,10 +593,7 @@ async def async_open_cover_tilt(self) -> None: async def async_close_cover(self) -> None: """Close the cover.""" self._set_lift_transition_target(POSITION_CLOSED) - res = await self._cover_cluster_handler.down_close() - if res[1] is not Status.SUCCESS: - self._clear_lift_transition() - raise ZHAException(f"Failed to close cover: {res[1]}") + await self._cover_cluster_handler.down_close() if self.current_cover_position != POSITION_CLOSED: self.async_update_state(CoverState.CLOSING) @@ -613,12 +602,9 @@ async def async_close_cover(self) -> None: async def async_close_cover_tilt(self) -> None: """Close the cover tilt.""" self._set_tilt_transition_target(POSITION_CLOSED) - res = await self._cover_cluster_handler.go_to_tilt_percentage( + await self._cover_cluster_handler.go_to_tilt_percentage( self._ha_position_to_zcl(POSITION_CLOSED) ) - if res[1] is not Status.SUCCESS: - self._clear_tilt_transition() - raise ZHAException(f"Failed to close cover tilt: {res[1]}") if self.current_cover_tilt_position != POSITION_CLOSED: self.async_update_state(CoverState.CLOSING) @@ -630,12 +616,9 @@ async def async_set_cover_position(self, position: int) -> None: target_position = position self._set_lift_transition_target(target_position) - res = await self._cover_cluster_handler.go_to_lift_percentage( + await self._cover_cluster_handler.go_to_lift_percentage( self._ha_position_to_zcl(target_position) ) - if res[1] is not Status.SUCCESS: - self._clear_lift_transition() - raise ZHAException(f"Failed to set cover position: {res[1]}") if target_position != self.current_cover_position: self.async_update_state( @@ -651,12 +634,9 @@ async def async_set_cover_tilt_position(self, tilt_position: int) -> None: target_position = tilt_position self._set_tilt_transition_target(target_position) - res = await self._cover_cluster_handler.go_to_tilt_percentage( + await self._cover_cluster_handler.go_to_tilt_percentage( self._ha_position_to_zcl(target_position) ) - if res[1] is not Status.SUCCESS: - self._clear_tilt_transition() - raise ZHAException(f"Failed to set cover tilt position: {res[1]}") if target_position != self.current_cover_tilt_position: self.async_update_state( @@ -671,9 +651,7 @@ async def async_stop_cover(self) -> None: Upon receipt of this command the cover stops both lift and tilt movement. """ - res = await self._cover_cluster_handler.stop() - if res[1] is not Status.SUCCESS: - raise ZHAException(f"Failed to stop cover: {res[1]}") + await self._cover_cluster_handler.stop() self._clear_lift_transition() self._clear_tilt_transition() self._determine_cover_state(refresh=True) @@ -834,18 +812,14 @@ def handle_cluster_handler_set_level(self, event: LevelChangeEvent) -> None: async def async_open_cover(self) -> None: """Open the window cover.""" - res = await self._on_off_cluster_handler.on() - if res[1] != Status.SUCCESS: - raise ZHAException(f"Failed to open cover: {res[1]}") + await self._on_off_cluster_handler.on() self._is_open = True self.maybe_emit_state_changed_event() async def async_close_cover(self) -> None: """Close the window cover.""" - res = await self._on_off_cluster_handler.off() - if res[1] != Status.SUCCESS: - raise ZHAException(f"Failed to close cover: {res[1]}") + await self._on_off_cluster_handler.off() self._is_open = False self.maybe_emit_state_changed_event() @@ -856,13 +830,10 @@ async def async_set_cover_position(self, position: int) -> None: return new_pos = position - res = await self._level_cluster_handler.move_to_level_with_on_off( + await self._level_cluster_handler.move_to_level_with_on_off( self._ha_position_to_zcl_level(new_pos), 1 ) - if res[1] != Status.SUCCESS: - raise ZHAException(f"Failed to set cover position: {res[1]}") - self._position = new_pos self.maybe_emit_state_changed_event() @@ -871,9 +842,7 @@ async def async_stop_cover(self) -> None: if not self._level_cluster_handler: return - res = await self._level_cluster_handler.stop() - if res[1] != Status.SUCCESS: - raise ZHAException(f"Failed to stop cover: {res[1]}") + await self._level_cluster_handler.stop() @staticmethod def _ha_position_to_zcl_level(position: int) -> int: diff --git a/zha/application/platforms/light/__init__.py b/zha/application/platforms/light/__init__.py index 2bb5e6bd9..525318560 100644 --- a/zha/application/platforms/light/__init__.py +++ b/zha/application/platforms/light/__init__.py @@ -17,7 +17,6 @@ from zigpy.zcl.clusters.general import Identify, LevelControl, OnOff from zigpy.zcl.clusters.lighting import Color -from zigpy.zcl.foundation import Status from zha.application import Platform from zha.application.platforms import ( @@ -466,14 +465,6 @@ async def _async_turn_on_impl( # noqa: C901 transition_time=int(10 * self._DEFAULT_MIN_TRANSITION_TIME), ) t_log["move_to_level_with_on_off"] = result - if result[1] is not Status.SUCCESS: - # First 'move to level' call failed, so if the transitioning delay - # isn't running from a previous call, - # the flag can be unset immediately - if set_transition_flag and not self._transition_listener: - self.async_transition_complete() - self.debug("turned on: %s", t_log) - return # Currently only setting it to "on", as the correct level state will # be set at the second move_to_level call self._state = True @@ -507,13 +498,6 @@ async def _async_turn_on_impl( # noqa: C901 transition_time=int(10 * duration), ) t_log["move_to_level_with_on_off"] = result - if result[1] is not Status.SUCCESS: - # First 'move to level' call failed, so if the transitioning delay - # isn't running from a previous call, the flag can be unset immediately - if set_transition_flag and not self._transition_listener: - self.async_transition_complete() - self.debug("turned on: %s", t_log) - return self._state = bool(level) if level: self._brightness = level @@ -530,13 +514,6 @@ async def _async_turn_on_impl( # noqa: C901 # if brightness is not 0. result = await self._on_off_cluster_handler.on() t_log["on_off"] = result - if result[1] is not Status.SUCCESS: - # 'On' call failed, but as brightness may still transition - # (for FORCE_ON lights), we start the timer to unset the flag after - # the transition_time if necessary. - self.async_transition_start_timer(transition_time) - self.debug("turned on: %s", t_log) - return self._state = True if not execute_if_off_supported: @@ -563,14 +540,6 @@ async def _async_turn_on_impl( # noqa: C901 level=level, transition_time=int(10 * duration) ) t_log["move_to_level_if_color"] = result - if result[1] is not Status.SUCCESS: - # Second 'move to level' call failed; the light is on but at the - # wrong brightness. If no previous timer is running, unset the flag - # immediately so attribute reports are not ignored indefinitely. - if set_transition_flag and not self._transition_listener: - self.async_transition_complete() - self.debug("turned on: %s", t_log) - return self._state = bool(level) if level: self._brightness = level @@ -656,8 +625,6 @@ async def async_turn_off(self, *, transition: float | None = None) -> None: if self._zha_config_enable_light_transitioning_flag: self.async_transition_start_timer(transition_time) self.debug("turned off: %s", result) - if result[1] is not Status.SUCCESS: - return self._state = False if brightness_supported and not self._off_with_transition: @@ -702,8 +669,6 @@ async def async_handle_color_commands( transition_time=int(10 * transition_time), ) t_log["move_to_color_temp"] = result - if result[1] is not Status.SUCCESS: - return False self._color_mode = ColorMode.COLOR_TEMP self._color_temp = color_temp self._xy_color = None @@ -717,8 +682,6 @@ async def async_handle_color_commands( transition_time=int(10 * transition_time), ) t_log["move_to_color"] = result - if result[1] is not Status.SUCCESS: - return False self._color_mode = ColorMode.XY self._xy_color = xy_color self._color_temp = None diff --git a/zha/application/platforms/lock/__init__.py b/zha/application/platforms/lock/__init__.py index 124ff15c3..e4b349812 100644 --- a/zha/application/platforms/lock/__init__.py +++ b/zha/application/platforms/lock/__init__.py @@ -6,7 +6,6 @@ from typing import TYPE_CHECKING, Any, Literal, cast from zigpy.zcl.clusters.closures import DoorLock as DoorLockCluster -from zigpy.zcl.foundation import Status from zha.application import Platform from zha.application.platforms import ( @@ -104,20 +103,14 @@ def is_locked(self) -> bool: async def async_lock(self) -> None: """Lock the lock.""" - result = await self._doorlock_cluster_handler.lock_door() - if result[0] is not Status.SUCCESS: - self.error("Error with lock_door: %s", result) - return + await self._doorlock_cluster_handler.lock_door() self._state = STATE_LOCKED self.maybe_emit_state_changed_event() async def async_unlock(self) -> None: """Unlock the lock.""" - result = await self._doorlock_cluster_handler.unlock_door() - if result[0] is not Status.SUCCESS: - self.error("Error with unlock_door: %s", result) - return + await self._doorlock_cluster_handler.unlock_door() self._state = STATE_UNLOCKED self.maybe_emit_state_changed_event() diff --git a/zha/application/platforms/switch.py b/zha/application/platforms/switch.py index e4a6b4b11..88977bb6d 100644 --- a/zha/application/platforms/switch.py +++ b/zha/application/platforms/switch.py @@ -14,7 +14,6 @@ from zigpy.zcl.clusters.closures import ConfigStatus, WindowCovering, WindowCoveringMode from zigpy.zcl.clusters.general import Basic, BinaryOutput, OnOff from zigpy.zcl.clusters.hvac import Thermostat -from zigpy.zcl.foundation import Status from zha.application import Platform from zha.application.platforms import ( @@ -291,17 +290,13 @@ def is_on(self) -> bool: async def async_turn_on(self) -> None: """Turn the entity on.""" - result = await self._on_off_cluster_handler.on() - if result[1] is not Status.SUCCESS: - return + await self._on_off_cluster_handler.on() self._state = True self.maybe_emit_state_changed_event() async def async_turn_off(self) -> None: """Turn the entity off.""" - result = await self._on_off_cluster_handler.off() - if result[1] is not Status.SUCCESS: - return + await self._on_off_cluster_handler.off() self._state = False self.maybe_emit_state_changed_event() diff --git a/zha/application/platforms/update.py b/zha/application/platforms/update.py index 66dc89e79..8645af5d4 100644 --- a/zha/application/platforms/update.py +++ b/zha/application/platforms/update.py @@ -12,7 +12,6 @@ from zigpy.ota import OtaImagesResult, OtaImageWithMetadata from zigpy.zcl.clusters.general import Ota, QueryNextImageCommand -from zigpy.zcl.foundation import Status from zha.application import Platform from zha.application.platforms import ( @@ -253,7 +252,7 @@ async def async_install(self, version: str | None) -> None: self.maybe_emit_state_changed_event() try: - result = await self.device.device.update_firmware( + await self.device.device.update_firmware( image=firmware, progress_callback=self._update_progress, ) @@ -262,12 +261,6 @@ async def async_install(self, version: str | None) -> None: self.maybe_emit_state_changed_event() raise ZHAException(f"Update was not successful: {ex}") from ex - # If the update finished but was not successful, we should also throw an error - if result != Status.SUCCESS: - self._attr_in_progress = False - self.maybe_emit_state_changed_event() - raise ZHAException(f"Update was not successful: {result}") - # Clear the state self._attr_in_progress = False self.maybe_emit_state_changed_event() diff --git a/zha/zigbee/cluster_handlers/general.py b/zha/zigbee/cluster_handlers/general.py index acd0344a0..005752704 100644 --- a/zha/zigbee/cluster_handlers/general.py +++ b/zha/zigbee/cluster_handlers/general.py @@ -47,9 +47,7 @@ Time, ) from zigpy.zcl.clusters.general_const import ApplicationType -from zigpy.zcl.foundation import Status -from zha.exceptions import ZHAException from zha.zigbee.cluster_handlers import ( AttrReportConfig, ClientClusterHandler, @@ -635,16 +633,12 @@ def on_off(self) -> bool | None: async def turn_on(self) -> None: """Turn the on off cluster on.""" - result = await self.on() - if result[1] is not Status.SUCCESS: - raise ZHAException(f"Failed to turn on: {result[1]}") + await self.on() self.cluster.update_attribute(OnOff.AttributeDefs.on_off.id, t.Bool.true) async def turn_off(self) -> None: """Turn the on off cluster off.""" - result = await self.off() - if result[1] is not Status.SUCCESS: - raise ZHAException(f"Failed to turn off: {result[1]}") + await self.off() self.cluster.update_attribute(OnOff.AttributeDefs.on_off.id, t.Bool.false) async def async_update(self): From 547a5e8677ce1079085b602b9bb004dedf6a3a0e Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Wed, 25 Feb 2026 03:27:29 +0100 Subject: [PATCH 3/4] Remove from attribute reporting --- zha/zigbee/cluster_handlers/__init__.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/zha/zigbee/cluster_handlers/__init__.py b/zha/zigbee/cluster_handlers/__init__.py index bb84e0278..ef3c87a9e 100644 --- a/zha/zigbee/cluster_handlers/__init__.py +++ b/zha/zigbee/cluster_handlers/__init__.py @@ -466,24 +466,12 @@ def _configure_reporting_status( event_data[self.cluster.find_attribute(record.attrid).name]["status"] = ( record.status.name ) - failed = [ - self.cluster.find_attribute(record.attrid).name - for record in res - if record.status != Status.SUCCESS - ] - self.debug( - "Failed to configure reporting for '%s' on '%s' cluster: %s", - failed, - self.name, - res, - ) - success = attr_names - set(failed) self.debug( "Successfully configured reporting for '%s' on '%s' cluster", - success, + attr_names, self.name, ) - for attr_name in success: + for attr_name in attr_names: event_data[attr_name]["status"] = Status.SUCCESS.name async def async_configure(self) -> None: From 14ca7a4d333bc8cc3ce30bfff9ac6bee2294327c Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Wed, 25 Feb 2026 03:27:44 +0100 Subject: [PATCH 4/4] Remove from `write_attributes_safe` --- zha/zigbee/cluster_handlers/__init__.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/zha/zigbee/cluster_handlers/__init__.py b/zha/zigbee/cluster_handlers/__init__.py index ef3c87a9e..8e04ab813 100644 --- a/zha/zigbee/cluster_handlers/__init__.py +++ b/zha/zigbee/cluster_handlers/__init__.py @@ -638,19 +638,7 @@ async def write_attributes_safe( ) -> None: """Wrap `write_attributes` to throw an exception on attribute write failure.""" - res = await self.write_attributes(attributes, manufacturer=manufacturer) - for record in res[0]: - if record.status != Status.SUCCESS: - try: - name = self.cluster.attributes[record.attrid].name - value = attributes.get(name, "unknown") - except KeyError: - name = f"0x{record.attrid:04x}" - value = "unknown" - - raise ZHAException( - f"Failed to write attribute {name}={value}: {record.status}", - ) + await self.write_attributes(attributes, manufacturer=manufacturer) def log(self, level, msg, *args, **kwargs) -> None: """Log a message."""