Skip to content

Commit ff8c635

Browse files
Add support for EFFECT_OFF (#99)
* Add support for EFFECT_NONE * off not None * review comment * Adjust typing for `effect` in `restore_external_state_attributes` * Fix effect behavior in `_assume_group_state` * Fix effect behavior in `restore_external_state_attributes` * Adjust `None` state restoration tests for new effect behavior * Move out `self._effect_list` into `effect_list` * Only add `EFFECT_OFF` if there are other effects * Revert "Only add `EFFECT_OFF` if there are other effects" This reverts commit aa870ef. * Always set effect on members Changing any other attributes always turns off the effect at the moment, so we need to pass that to the members. * Fix group light test expecting `None` `effect_list` --------- Co-authored-by: TheJulianJES <[email protected]>
1 parent c48278b commit ff8c635

File tree

4 files changed

+17
-18
lines changed

4 files changed

+17
-18
lines changed

tests/test_gateway.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
)
4242
from zha.application.helpers import ZHAData
4343
from zha.application.platforms import GroupEntity
44-
from zha.application.platforms.light.const import LightEntityFeature
44+
from zha.application.platforms.light.const import EFFECT_OFF, LightEntityFeature
4545
from zha.zigbee.device import Device
4646
from zha.zigbee.group import Group, GroupMemberReference
4747

@@ -313,7 +313,7 @@ async def test_gateway_group_methods(
313313
assert info.supported_features == LightEntityFeature.TRANSITION
314314
assert info.min_mireds == 153
315315
assert info.max_mireds == 500
316-
assert info.effect_list is None
316+
assert info.effect_list == [EFFECT_OFF]
317317

318318
device_1_light_entity = get_entity(device_light_1, platform=Platform.LIGHT)
319319
device_2_light_entity = get_entity(device_light_2, platform=Platform.LIGHT)

tests/test_light.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,12 +2021,12 @@ async def test_light_state_restoration(
20212021
color_temp=None,
20222022
xy_color=None,
20232023
color_mode=None,
2024-
effect=None, # Effect is the only `None` value actually restored
2024+
effect=None,
20252025
)
20262026

20272027
assert entity.state["on"] is True
20282028
assert entity.state["brightness"] == 34
20292029
assert entity.state["color_temp"] == 500
20302030
assert entity.state["xy_color"] == (1, 2)
20312031
assert entity.state["color_mode"] == ColorMode.XY
2032-
assert entity.state["effect"] is None
2032+
assert entity.state["effect"] == "colorloop"

zha/application/platforms/light/__init__.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
DEFAULT_MIN_TRANSITION_MANUFACTURERS,
5454
DEFAULT_ON_OFF_TRANSITION,
5555
EFFECT_COLORLOOP,
56+
EFFECT_OFF,
5657
FLASH_EFFECTS,
5758
ColorMode,
5859
LightEntityFeature,
@@ -122,7 +123,7 @@ def __init__(self, *args, **kwargs):
122123
self._off_with_transition: bool = False
123124
self._off_brightness: int | None = None
124125
self._effect_list: list[str] | None = None
125-
self._effect: str | None = None
126+
self._effect: str = EFFECT_OFF
126127
self._supported_color_modes: set[ColorMode] = set()
127128
self._external_supported_color_modes: set[ColorMode] = set()
128129
self._zha_config_transition: int = self._DEFAULT_MIN_TRANSITION_TIME
@@ -174,7 +175,7 @@ def effect_list(self) -> list[str] | None:
174175
return self._effect_list
175176

176177
@property
177-
def effect(self) -> str | None:
178+
def effect(self) -> str:
178179
"""Return the current effect."""
179180
return self._effect
180181

@@ -461,7 +462,7 @@ async def async_turn_on(self, **kwargs: Any) -> None:
461462
start_hue=0,
462463
)
463464
t_log["color_loop_set"] = result
464-
self._effect = None
465+
self._effect = EFFECT_OFF
465466

466467
if flash is not None:
467468
result = await self._identify_cluster_handler.trigger_effect(
@@ -663,7 +664,7 @@ def __init__(
663664
if self._color_cluster_handler:
664665
self._min_mireds: int = self._color_cluster_handler.min_mireds
665666
self._max_mireds: int = self._color_cluster_handler.max_mireds
666-
effect_list = []
667+
effect_list = [EFFECT_OFF]
667668

668669
light_options = device.gateway.config.config.light_options
669670

@@ -888,7 +889,7 @@ async def async_update(self) -> None:
888889
if color_loop_active == 1:
889890
self._effect = EFFECT_COLORLOOP
890891
else:
891-
self._effect = None
892+
self._effect = EFFECT_OFF
892893
self.maybe_emit_state_changed_event()
893894

894895
def _assume_group_state(self, update_params) -> None:
@@ -904,6 +905,7 @@ def _assume_group_state(self, update_params) -> None:
904905
effect = update_params.get(ATTR_EFFECT)
905906

906907
supported_modes = self._supported_color_modes
908+
effect_list = self._effect_list
907909

908910
# unset "off brightness" and "off with transition"
909911
# if group turned on this light
@@ -942,10 +944,7 @@ def _assume_group_state(self, update_params) -> None:
942944
self._color_temp = color_temp
943945
if xy_color is not None and ColorMode.XY in supported_modes:
944946
self._xy_color = xy_color
945-
# the effect is always deactivated in async_turn_on if not provided
946-
if effect is None:
947-
self._effect = None
948-
elif self._effect_list and effect in self._effect_list:
947+
if effect is not None and effect_list and effect in effect_list:
949948
self._effect = effect
950949

951950
self.maybe_emit_state_changed_event()
@@ -977,9 +976,8 @@ def restore_external_state_attributes(
977976
self._xy_color = xy_color
978977
if color_mode is not None:
979978
self._color_mode = color_mode
980-
981-
# Effect is always restored, as `None` indicates that no effect is active
982-
self._effect = effect
979+
if effect is not None:
980+
self._effect = effect
983981

984982

985983
@STRICT_MATCH(
@@ -1164,7 +1162,7 @@ def update(self, _: Any = None) -> None:
11641162
# Merge all effects from all effect_lists with a union merge.
11651163
self._effect_list = list(set().union(*all_effect_lists))
11661164

1167-
self._effect = None
1165+
self._effect = EFFECT_OFF
11681166
all_effects = list(find_state_attributes(on_states, ATTR_EFFECT))
11691167
if all_effects:
11701168
# Report the most common effect.
@@ -1248,7 +1246,7 @@ def _make_members_assume_group_state(
12481246
update_params[ATTR_COLOR_MODE] = self._color_mode
12491247
update_params[ATTR_XY_COLOR] = self._xy_color
12501248

1251-
# we always update effect for now, as we don't know if it was set or not
1249+
# setting any other attribute will turn the effect off, so we always set this
12521250
update_params[ATTR_EFFECT] = self._effect
12531251

12541252
for platform_entity in self.group.get_platform_entities(Light.PLATFORM):

zha/application/platforms/light/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class ColorMode(StrEnum):
6363
EFFECT_COLORLOOP: Final[str] = "colorloop"
6464
EFFECT_RANDOM: Final[str] = "random"
6565
EFFECT_WHITE: Final[str] = "white"
66+
EFFECT_OFF: Final[str] = "off"
6667

6768
ATTR_SUPPORTED_FEATURES: Final[str] = "supported_features"
6869

0 commit comments

Comments
 (0)