mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 23:27:37 +00:00
Fix ColorMode.WHITE support in Tuya (#126242)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
3f67ba4c02
commit
5a771b501d
@ -12,6 +12,7 @@ from homeassistant.components.light import (
|
|||||||
ATTR_BRIGHTNESS,
|
ATTR_BRIGHTNESS,
|
||||||
ATTR_COLOR_TEMP_KELVIN,
|
ATTR_COLOR_TEMP_KELVIN,
|
||||||
ATTR_HS_COLOR,
|
ATTR_HS_COLOR,
|
||||||
|
ATTR_WHITE,
|
||||||
ColorMode,
|
ColorMode,
|
||||||
LightEntity,
|
LightEntity,
|
||||||
LightEntityDescription,
|
LightEntityDescription,
|
||||||
@ -488,6 +489,7 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||||||
_color_data_type: ColorTypeData | None = None
|
_color_data_type: ColorTypeData | None = None
|
||||||
_color_mode: DPCode | None = None
|
_color_mode: DPCode | None = None
|
||||||
_color_temp: IntegerTypeData | None = None
|
_color_temp: IntegerTypeData | None = None
|
||||||
|
_white_color_mode = ColorMode.COLOR_TEMP
|
||||||
_fixed_color_mode: ColorMode | None = None
|
_fixed_color_mode: ColorMode | None = None
|
||||||
_attr_min_color_temp_kelvin = 2000 # 500 Mireds
|
_attr_min_color_temp_kelvin = 2000 # 500 Mireds
|
||||||
_attr_max_color_temp_kelvin = 6500 # 153 Mireds
|
_attr_max_color_temp_kelvin = 6500 # 153 Mireds
|
||||||
@ -526,6 +528,13 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||||||
):
|
):
|
||||||
self._color_temp = int_type
|
self._color_temp = int_type
|
||||||
color_modes.add(ColorMode.COLOR_TEMP)
|
color_modes.add(ColorMode.COLOR_TEMP)
|
||||||
|
# If entity does not have color_temp, check if it has work_mode "white"
|
||||||
|
elif color_mode_enum := self.find_dpcode(
|
||||||
|
description.color_mode, dptype=DPType.ENUM, prefer_function=True
|
||||||
|
):
|
||||||
|
if WorkMode.WHITE.value in color_mode_enum.range:
|
||||||
|
color_modes.add(ColorMode.WHITE)
|
||||||
|
self._white_color_mode = ColorMode.WHITE
|
||||||
|
|
||||||
if (
|
if (
|
||||||
dpcode := self.find_dpcode(description.color_data, prefer_function=True)
|
dpcode := self.find_dpcode(description.color_data, prefer_function=True)
|
||||||
@ -566,8 +575,9 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||||||
"""Turn on or control the light."""
|
"""Turn on or control the light."""
|
||||||
commands = [{"code": self.entity_description.key, "value": True}]
|
commands = [{"code": self.entity_description.key, "value": True}]
|
||||||
|
|
||||||
if self._color_temp and ATTR_COLOR_TEMP_KELVIN in kwargs:
|
if self._color_mode_dpcode and (
|
||||||
if self._color_mode_dpcode:
|
ATTR_WHITE in kwargs or ATTR_COLOR_TEMP_KELVIN in kwargs
|
||||||
|
):
|
||||||
commands += [
|
commands += [
|
||||||
{
|
{
|
||||||
"code": self._color_mode_dpcode,
|
"code": self._color_mode_dpcode,
|
||||||
@ -575,6 +585,7 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if self._color_temp and ATTR_COLOR_TEMP_KELVIN in kwargs:
|
||||||
commands += [
|
commands += [
|
||||||
{
|
{
|
||||||
"code": self._color_temp.dpcode,
|
"code": self._color_temp.dpcode,
|
||||||
@ -596,6 +607,7 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||||||
or (
|
or (
|
||||||
ATTR_BRIGHTNESS in kwargs
|
ATTR_BRIGHTNESS in kwargs
|
||||||
and self.color_mode == ColorMode.HS
|
and self.color_mode == ColorMode.HS
|
||||||
|
and ATTR_WHITE not in kwargs
|
||||||
and ATTR_COLOR_TEMP_KELVIN not in kwargs
|
and ATTR_COLOR_TEMP_KELVIN not in kwargs
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
@ -755,15 +767,15 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||||||
# The light supports only a single color mode, return it
|
# The light supports only a single color mode, return it
|
||||||
return self._fixed_color_mode
|
return self._fixed_color_mode
|
||||||
|
|
||||||
# The light supports both color temperature and HS, determine which mode the
|
# The light supports both white (with or without adjustable color temperature)
|
||||||
# light is in. We consider it to be in HS color mode, when work mode is anything
|
# and HS, determine which mode the light is in. We consider it to be in HS color
|
||||||
# else than "white".
|
# mode, when work mode is anything else than "white".
|
||||||
if (
|
if (
|
||||||
self._color_mode_dpcode
|
self._color_mode_dpcode
|
||||||
and self.device.status.get(self._color_mode_dpcode) != WorkMode.WHITE
|
and self.device.status.get(self._color_mode_dpcode) != WorkMode.WHITE
|
||||||
):
|
):
|
||||||
return ColorMode.HS
|
return ColorMode.HS
|
||||||
return ColorMode.COLOR_TEMP
|
return self._white_color_mode
|
||||||
|
|
||||||
def _get_color_data(self) -> ColorData | None:
|
def _get_color_data(self) -> ColorData | None:
|
||||||
"""Get current color data from device."""
|
"""Get current color data from device."""
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
'capabilities': dict({
|
'capabilities': dict({
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
|
<ColorMode.WHITE: 'white'>,
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
'config_entry_id': <ANY>,
|
'config_entry_id': <ANY>,
|
||||||
@ -99,25 +100,16 @@
|
|||||||
StateSnapshot({
|
StateSnapshot({
|
||||||
'attributes': ReadOnlyDict({
|
'attributes': ReadOnlyDict({
|
||||||
'brightness': 138,
|
'brightness': 138,
|
||||||
'color_mode': <ColorMode.HS: 'hs'>,
|
'color_mode': <ColorMode.WHITE: 'white'>,
|
||||||
'friendly_name': 'Garage light',
|
'friendly_name': 'Garage light',
|
||||||
'hs_color': tuple(
|
'hs_color': None,
|
||||||
243.0,
|
'rgb_color': None,
|
||||||
86.0,
|
|
||||||
),
|
|
||||||
'rgb_color': tuple(
|
|
||||||
47,
|
|
||||||
36,
|
|
||||||
255,
|
|
||||||
),
|
|
||||||
'supported_color_modes': list([
|
'supported_color_modes': list([
|
||||||
<ColorMode.HS: 'hs'>,
|
<ColorMode.HS: 'hs'>,
|
||||||
|
<ColorMode.WHITE: 'white'>,
|
||||||
]),
|
]),
|
||||||
'supported_features': <LightEntityFeature: 0>,
|
'supported_features': <LightEntityFeature: 0>,
|
||||||
'xy_color': tuple(
|
'xy_color': None,
|
||||||
0.148,
|
|
||||||
0.055,
|
|
||||||
),
|
|
||||||
}),
|
}),
|
||||||
'context': <ANY>,
|
'context': <ANY>,
|
||||||
'entity_id': 'light.garage_light',
|
'entity_id': 'light.garage_light',
|
||||||
|
@ -8,6 +8,11 @@ import pytest
|
|||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
from tuya_sharing import CustomerDevice
|
from tuya_sharing import CustomerDevice
|
||||||
|
|
||||||
|
from homeassistant.components.light import (
|
||||||
|
DOMAIN as LIGHT_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
)
|
||||||
from homeassistant.components.tuya import ManagerCompat
|
from homeassistant.components.tuya import ManagerCompat
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -55,3 +60,66 @@ async def test_platform_setup_no_discovery(
|
|||||||
assert not er.async_entries_for_config_entry(
|
assert not er.async_entries_for_config_entry(
|
||||||
entity_registry, mock_config_entry.entry_id
|
entity_registry, mock_config_entry.entry_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"mock_device_code",
|
||||||
|
["dj_smart_light_bulb"],
|
||||||
|
)
|
||||||
|
async def test_turn_on_white(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_manager: ManagerCompat,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_device: CustomerDevice,
|
||||||
|
) -> None:
|
||||||
|
"""Test turn_on service."""
|
||||||
|
entity_id = "light.garage_light"
|
||||||
|
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None, f"{entity_id} does not exist"
|
||||||
|
await hass.services.async_call(
|
||||||
|
LIGHT_DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{
|
||||||
|
"entity_id": entity_id,
|
||||||
|
"white": 150,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
mock_manager.send_commands.assert_called_once_with(
|
||||||
|
mock_device.id,
|
||||||
|
[
|
||||||
|
{"code": "switch_led", "value": True},
|
||||||
|
{"code": "work_mode", "value": "white"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"mock_device_code",
|
||||||
|
["dj_smart_light_bulb"],
|
||||||
|
)
|
||||||
|
async def test_turn_off(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_manager: ManagerCompat,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_device: CustomerDevice,
|
||||||
|
) -> None:
|
||||||
|
"""Test turn_off service."""
|
||||||
|
entity_id = "light.garage_light"
|
||||||
|
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state is not None, f"{entity_id} does not exist"
|
||||||
|
await hass.services.async_call(
|
||||||
|
LIGHT_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{
|
||||||
|
"entity_id": entity_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
mock_manager.send_commands.assert_called_once_with(
|
||||||
|
mock_device.id, [{"code": "switch_led", "value": False}]
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user