Skip to content

Commit

Permalink
Add support for EFFECT_OFF (#99)
Browse files Browse the repository at this point in the history
* 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 <TheJulianJES@users.noreply.github.com>
  • Loading branch information
dmulcahey and TheJulianJES authored Oct 16, 2024
1 parent c48278b commit ff8c635
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 18 deletions.
4 changes: 2 additions & 2 deletions tests/test_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
)
from zha.application.helpers import ZHAData
from zha.application.platforms import GroupEntity
from zha.application.platforms.light.const import LightEntityFeature
from zha.application.platforms.light.const import EFFECT_OFF, LightEntityFeature
from zha.zigbee.device import Device
from zha.zigbee.group import Group, GroupMemberReference

Expand Down Expand Up @@ -313,7 +313,7 @@ async def test_gateway_group_methods(
assert info.supported_features == LightEntityFeature.TRANSITION
assert info.min_mireds == 153
assert info.max_mireds == 500
assert info.effect_list is None
assert info.effect_list == [EFFECT_OFF]

device_1_light_entity = get_entity(device_light_1, platform=Platform.LIGHT)
device_2_light_entity = get_entity(device_light_2, platform=Platform.LIGHT)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -2021,12 +2021,12 @@ async def test_light_state_restoration(
color_temp=None,
xy_color=None,
color_mode=None,
effect=None, # Effect is the only `None` value actually restored
effect=None,
)

assert entity.state["on"] is True
assert entity.state["brightness"] == 34
assert entity.state["color_temp"] == 500
assert entity.state["xy_color"] == (1, 2)
assert entity.state["color_mode"] == ColorMode.XY
assert entity.state["effect"] is None
assert entity.state["effect"] == "colorloop"
26 changes: 12 additions & 14 deletions zha/application/platforms/light/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
DEFAULT_MIN_TRANSITION_MANUFACTURERS,
DEFAULT_ON_OFF_TRANSITION,
EFFECT_COLORLOOP,
EFFECT_OFF,
FLASH_EFFECTS,
ColorMode,
LightEntityFeature,
Expand Down Expand Up @@ -122,7 +123,7 @@ def __init__(self, *args, **kwargs):
self._off_with_transition: bool = False
self._off_brightness: int | None = None
self._effect_list: list[str] | None = None
self._effect: str | None = None
self._effect: str = EFFECT_OFF
self._supported_color_modes: set[ColorMode] = set()
self._external_supported_color_modes: set[ColorMode] = set()
self._zha_config_transition: int = self._DEFAULT_MIN_TRANSITION_TIME
Expand Down Expand Up @@ -174,7 +175,7 @@ def effect_list(self) -> list[str] | None:
return self._effect_list

@property
def effect(self) -> str | None:
def effect(self) -> str:
"""Return the current effect."""
return self._effect

Expand Down Expand Up @@ -461,7 +462,7 @@ async def async_turn_on(self, **kwargs: Any) -> None:
start_hue=0,
)
t_log["color_loop_set"] = result
self._effect = None
self._effect = EFFECT_OFF

if flash is not None:
result = await self._identify_cluster_handler.trigger_effect(
Expand Down Expand Up @@ -663,7 +664,7 @@ def __init__(
if self._color_cluster_handler:
self._min_mireds: int = self._color_cluster_handler.min_mireds
self._max_mireds: int = self._color_cluster_handler.max_mireds
effect_list = []
effect_list = [EFFECT_OFF]

light_options = device.gateway.config.config.light_options

Expand Down Expand Up @@ -888,7 +889,7 @@ async def async_update(self) -> None:
if color_loop_active == 1:
self._effect = EFFECT_COLORLOOP
else:
self._effect = None
self._effect = EFFECT_OFF
self.maybe_emit_state_changed_event()

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

supported_modes = self._supported_color_modes
effect_list = self._effect_list

# unset "off brightness" and "off with transition"
# if group turned on this light
Expand Down Expand Up @@ -942,10 +944,7 @@ def _assume_group_state(self, update_params) -> None:
self._color_temp = color_temp
if xy_color is not None and ColorMode.XY in supported_modes:
self._xy_color = xy_color
# the effect is always deactivated in async_turn_on if not provided
if effect is None:
self._effect = None
elif self._effect_list and effect in self._effect_list:
if effect is not None and effect_list and effect in effect_list:
self._effect = effect

self.maybe_emit_state_changed_event()
Expand Down Expand Up @@ -977,9 +976,8 @@ def restore_external_state_attributes(
self._xy_color = xy_color
if color_mode is not None:
self._color_mode = color_mode

# Effect is always restored, as `None` indicates that no effect is active
self._effect = effect
if effect is not None:
self._effect = effect


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

self._effect = None
self._effect = EFFECT_OFF
all_effects = list(find_state_attributes(on_states, ATTR_EFFECT))
if all_effects:
# Report the most common effect.
Expand Down Expand Up @@ -1248,7 +1246,7 @@ def _make_members_assume_group_state(
update_params[ATTR_COLOR_MODE] = self._color_mode
update_params[ATTR_XY_COLOR] = self._xy_color

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

for platform_entity in self.group.get_platform_entities(Light.PLATFORM):
Expand Down
1 change: 1 addition & 0 deletions zha/application/platforms/light/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class ColorMode(StrEnum):
EFFECT_COLORLOOP: Final[str] = "colorloop"
EFFECT_RANDOM: Final[str] = "random"
EFFECT_WHITE: Final[str] = "white"
EFFECT_OFF: Final[str] = "off"

ATTR_SUPPORTED_FEATURES: Final[str] = "supported_features"

Expand Down

0 comments on commit ff8c635

Please sign in to comment.