Use last event as color mode in SmartThings (#139473)

* Use last event as color mode in SmartThings

* Use last event as color mode in SmartThings

* Fix
pull/125870/merge
Joost Lekkerkerker 2025-02-28 20:39:49 +01:00 committed by GitHub
parent 39bc37d225
commit 455363871f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 135 additions and 18 deletions

View File

@ -3,12 +3,13 @@
from __future__ import annotations
import asyncio
from typing import Any
from typing import Any, cast
from pysmartthings import Attribute, Capability, Command, SmartThings
from pysmartthings import Attribute, Capability, Command, DeviceEvent, SmartThings
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_MODE,
ATTR_COLOR_TEMP_KELVIN,
ATTR_HS_COLOR,
ATTR_TRANSITION,
@ -19,6 +20,7 @@ from homeassistant.components.light import (
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from . import FullDevice, SmartThingsConfigEntry
from .const import MAIN
@ -53,7 +55,7 @@ def convert_scale(
return round(value * target_scale / value_scale, round_digits)
class SmartThingsLight(SmartThingsEntity, LightEntity):
class SmartThingsLight(SmartThingsEntity, LightEntity, RestoreEntity):
"""Define a SmartThings Light."""
_attr_name = None
@ -84,18 +86,28 @@ class SmartThingsLight(SmartThingsEntity, LightEntity):
color_modes = set()
if self.supports_capability(Capability.COLOR_TEMPERATURE):
color_modes.add(ColorMode.COLOR_TEMP)
self._attr_color_mode = ColorMode.COLOR_TEMP
if self.supports_capability(Capability.COLOR_CONTROL):
color_modes.add(ColorMode.HS)
self._attr_color_mode = ColorMode.HS
if not color_modes and self.supports_capability(Capability.SWITCH_LEVEL):
color_modes.add(ColorMode.BRIGHTNESS)
if not color_modes:
color_modes.add(ColorMode.ONOFF)
if len(color_modes) == 1:
self._attr_color_mode = list(color_modes)[0]
self._attr_supported_color_modes = color_modes
features = LightEntityFeature(0)
if self.supports_capability(Capability.SWITCH_LEVEL):
features |= LightEntityFeature.TRANSITION
self._attr_supported_features = features
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
if (last_state := await self.async_get_last_extra_data()) is not None:
self._attr_color_mode = last_state.as_dict()[ATTR_COLOR_MODE]
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
tasks = []
@ -195,17 +207,14 @@ class SmartThingsLight(SmartThingsEntity, LightEntity):
argument=[level, duration],
)
@property
def color_mode(self) -> ColorMode:
"""Return the color mode of the light."""
if len(self._attr_supported_color_modes) == 1:
# The light supports only a single color mode
return list(self._attr_supported_color_modes)[0]
# The light supports hs + color temp, determine which one it is
if self._attr_hs_color and self._attr_hs_color[1]:
return ColorMode.HS
return ColorMode.COLOR_TEMP
def _update_handler(self, event: DeviceEvent) -> None:
"""Handle device updates."""
if event.capability in (Capability.COLOR_CONTROL, Capability.COLOR_TEMPERATURE):
self._attr_color_mode = {
Capability.COLOR_CONTROL: ColorMode.HS,
Capability.COLOR_TEMPERATURE: ColorMode.COLOR_TEMP,
}[cast(Capability, event.capability)]
super()._update_handler(event)
@property
def is_on(self) -> bool:

View File

@ -12,7 +12,12 @@ from homeassistant.components.light import (
ATTR_COLOR_MODE,
ATTR_COLOR_TEMP_KELVIN,
ATTR_HS_COLOR,
ATTR_MAX_COLOR_TEMP_KELVIN,
ATTR_MIN_COLOR_TEMP_KELVIN,
ATTR_RGB_COLOR,
ATTR_SUPPORTED_COLOR_MODES,
ATTR_TRANSITION,
ATTR_XY_COLOR,
DOMAIN as LIGHT_DOMAIN,
ColorMode,
)
@ -25,7 +30,7 @@ from homeassistant.const import (
STATE_ON,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, State
from homeassistant.helpers import entity_registry as er
from . import (
@ -35,7 +40,7 @@ from . import (
trigger_update,
)
from tests.common import MockConfigEntry
from tests.common import MockConfigEntry, mock_restore_cache_with_extra_data
async def test_all_entities(
@ -228,6 +233,15 @@ async def test_updating_brightness(
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
await setup_integration(hass, mock_config_entry)
await trigger_update(
hass,
devices,
"cb958955-b015-498c-9e62-fc0c51abd054",
Capability.COLOR_CONTROL,
Attribute.HUE,
40,
)
assert hass.states.get("light.standing_light").attributes[ATTR_BRIGHTNESS] == 178
await trigger_update(
@ -252,8 +266,17 @@ async def test_updating_hs(
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
await setup_integration(hass, mock_config_entry)
await trigger_update(
hass,
devices,
"cb958955-b015-498c-9e62-fc0c51abd054",
Capability.COLOR_CONTROL,
Attribute.HUE,
40,
)
assert hass.states.get("light.standing_light").attributes[ATTR_HS_COLOR] == (
218.906,
144.0,
60,
)
@ -280,9 +303,17 @@ async def test_updating_color_temp(
) -> None:
"""Test color temperature update."""
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
set_attribute_value(devices, Capability.COLOR_CONTROL, Attribute.SATURATION, 0)
await setup_integration(hass, mock_config_entry)
await trigger_update(
hass,
devices,
"cb958955-b015-498c-9e62-fc0c51abd054",
Capability.COLOR_TEMPERATURE,
Attribute.COLOR_TEMPERATURE,
3000,
)
assert (
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
is ColorMode.COLOR_TEMP
@ -305,3 +336,80 @@ async def test_updating_color_temp(
hass.states.get("light.standing_light").attributes[ATTR_COLOR_TEMP_KELVIN]
== 2000
)
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
async def test_color_modes(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test color mode changes."""
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
set_attribute_value(devices, Capability.COLOR_CONTROL, Attribute.SATURATION, 50)
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
is ColorMode.HS
)
await trigger_update(
hass,
devices,
"cb958955-b015-498c-9e62-fc0c51abd054",
Capability.COLOR_TEMPERATURE,
Attribute.COLOR_TEMPERATURE,
2000,
)
assert (
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
is ColorMode.COLOR_TEMP
)
await trigger_update(
hass,
devices,
"cb958955-b015-498c-9e62-fc0c51abd054",
Capability.COLOR_CONTROL,
Attribute.HUE,
20,
)
assert (
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
is ColorMode.HS
)
@pytest.mark.parametrize("device_fixture", ["hue_rgbw_color_bulb"])
async def test_color_mode_after_startup(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test color mode after startup."""
set_attribute_value(devices, Capability.SWITCH, Attribute.SWITCH, "on")
RESTORE_DATA = {
ATTR_BRIGHTNESS: 178,
ATTR_COLOR_MODE: ColorMode.COLOR_TEMP,
ATTR_COLOR_TEMP_KELVIN: 3000,
ATTR_HS_COLOR: (144.0, 60),
ATTR_MAX_COLOR_TEMP_KELVIN: 9000,
ATTR_MIN_COLOR_TEMP_KELVIN: 2000,
ATTR_RGB_COLOR: (255, 128, 0),
ATTR_SUPPORTED_COLOR_MODES: [ColorMode.COLOR_TEMP, ColorMode.HS],
ATTR_XY_COLOR: (0.61, 0.35),
}
mock_restore_cache_with_extra_data(
hass, ((State("light.standing_light", STATE_ON), RESTORE_DATA),)
)
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("light.standing_light").attributes[ATTR_COLOR_MODE]
is ColorMode.COLOR_TEMP
)