mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 03:37:07 +00:00
Home connect light generalization and RGB support (#126144)
This commit is contained in:
parent
01bdda0ae6
commit
a77cb1e579
@ -10,6 +10,7 @@ from homeconnect.api import HomeConnectError
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_RGB_COLOR,
|
||||
ColorMode,
|
||||
LightEntity,
|
||||
LightEntityDescription,
|
||||
@ -19,7 +20,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
import homeassistant.util.color as color_util
|
||||
|
||||
from .api import HomeConnectDevice
|
||||
from .api import ConfigEntryAuth, HomeConnectDevice
|
||||
from .const import (
|
||||
ATTR_VALUE,
|
||||
BSH_AMBIENT_LIGHT_BRIGHTNESS,
|
||||
@ -44,20 +45,41 @@ _LOGGER = logging.getLogger(__name__)
|
||||
class HomeConnectLightEntityDescription(LightEntityDescription):
|
||||
"""Light entity description."""
|
||||
|
||||
brightness_key: str | None
|
||||
brightness_key: str | None = None
|
||||
color_key: str | None = None
|
||||
enable_custom_color_value_key: str | None = None
|
||||
custom_color_key: str | None = None
|
||||
brightness_scale: tuple[float, float] = (0.0, 100.0)
|
||||
|
||||
|
||||
LIGHTS: tuple[HomeConnectLightEntityDescription, ...] = (
|
||||
HomeConnectLightEntityDescription(
|
||||
key=REFRIGERATION_INTERNAL_LIGHT_POWER,
|
||||
brightness_key=REFRIGERATION_INTERNAL_LIGHT_BRIGHTNESS,
|
||||
brightness_scale=(1.0, 100.0),
|
||||
translation_key="internal_light",
|
||||
),
|
||||
HomeConnectLightEntityDescription(
|
||||
key=REFRIGERATION_EXTERNAL_LIGHT_POWER,
|
||||
brightness_key=REFRIGERATION_EXTERNAL_LIGHT_BRIGHTNESS,
|
||||
brightness_scale=(1.0, 100.0),
|
||||
translation_key="external_light",
|
||||
),
|
||||
HomeConnectLightEntityDescription(
|
||||
key=COOKING_LIGHTING,
|
||||
brightness_key=COOKING_LIGHTING_BRIGHTNESS,
|
||||
brightness_scale=(10.0, 100.0),
|
||||
translation_key="cooking_lighting",
|
||||
),
|
||||
HomeConnectLightEntityDescription(
|
||||
key=BSH_AMBIENT_LIGHT_ENABLED,
|
||||
brightness_key=BSH_AMBIENT_LIGHT_BRIGHTNESS,
|
||||
color_key=BSH_AMBIENT_LIGHT_COLOR,
|
||||
enable_custom_color_value_key=BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR,
|
||||
custom_color_key=BSH_AMBIENT_LIGHT_CUSTOM_COLOR,
|
||||
brightness_scale=(10.0, 100.0),
|
||||
translation_key="ambient_light",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -70,41 +92,13 @@ async def async_setup_entry(
|
||||
|
||||
def get_entities() -> list[LightEntity]:
|
||||
"""Get a list of entities."""
|
||||
entities: list[LightEntity] = []
|
||||
hc_api = hass.data[DOMAIN][config_entry.entry_id]
|
||||
for device in hc_api.devices:
|
||||
if COOKING_LIGHTING in device.appliance.status:
|
||||
entities.append(
|
||||
HomeConnectLight(
|
||||
device,
|
||||
LightEntityDescription(
|
||||
key=COOKING_LIGHTING,
|
||||
translation_key="cooking_lighting",
|
||||
),
|
||||
False,
|
||||
)
|
||||
)
|
||||
if BSH_AMBIENT_LIGHT_ENABLED in device.appliance.status:
|
||||
entities.append(
|
||||
HomeConnectLight(
|
||||
device,
|
||||
LightEntityDescription(
|
||||
key=BSH_AMBIENT_LIGHT_ENABLED,
|
||||
translation_key="ambient_light",
|
||||
),
|
||||
True,
|
||||
)
|
||||
)
|
||||
entities.extend(
|
||||
HomeConnectCoolingLight(
|
||||
device=device,
|
||||
ambient=False,
|
||||
entity_description=description,
|
||||
)
|
||||
for description in LIGHTS
|
||||
if description.key in device.appliance.status
|
||||
)
|
||||
return entities
|
||||
hc_api: ConfigEntryAuth = hass.data[DOMAIN][config_entry.entry_id]
|
||||
return [
|
||||
HomeConnectLight(device, description)
|
||||
for description in LIGHTS
|
||||
for device in hc_api.devices
|
||||
if description.key in device.appliance.status
|
||||
]
|
||||
|
||||
async_add_entities(await hass.async_add_executor_job(get_entities), True)
|
||||
|
||||
@ -115,80 +109,99 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
|
||||
entity_description: LightEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device: HomeConnectDevice,
|
||||
desc: LightEntityDescription,
|
||||
ambient: bool,
|
||||
self, device: HomeConnectDevice, desc: HomeConnectLightEntityDescription
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
super().__init__(device, desc)
|
||||
self._ambient = ambient
|
||||
self._percentage_scale = (10, 100)
|
||||
self._brightness_key: str | None
|
||||
self._custom_color_key: str | None
|
||||
self._color_key: str | None
|
||||
if ambient:
|
||||
self._brightness_key = BSH_AMBIENT_LIGHT_BRIGHTNESS
|
||||
self._custom_color_key = BSH_AMBIENT_LIGHT_CUSTOM_COLOR
|
||||
self._color_key = BSH_AMBIENT_LIGHT_COLOR
|
||||
self._attr_color_mode = ColorMode.HS
|
||||
self._attr_supported_color_modes = {ColorMode.HS}
|
||||
else:
|
||||
self._brightness_key = COOKING_LIGHTING_BRIGHTNESS
|
||||
self._custom_color_key = None
|
||||
self._color_key = None
|
||||
self._attr_color_mode = ColorMode.BRIGHTNESS
|
||||
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
|
||||
|
||||
def get_setting_key_if_setting_exists(setting_key: str | None) -> str | None:
|
||||
if setting_key and setting_key in device.appliance.status:
|
||||
return setting_key
|
||||
return None
|
||||
|
||||
self._brightness_key = get_setting_key_if_setting_exists(desc.brightness_key)
|
||||
self._custom_color_key = get_setting_key_if_setting_exists(
|
||||
desc.custom_color_key
|
||||
)
|
||||
self._color_key = get_setting_key_if_setting_exists(desc.color_key)
|
||||
self._enable_custom_color_value_key = desc.enable_custom_color_value_key
|
||||
self._custom_color_key = get_setting_key_if_setting_exists(
|
||||
desc.custom_color_key
|
||||
)
|
||||
self._brightness_scale = desc.brightness_scale
|
||||
|
||||
match (self._brightness_key, self._custom_color_key):
|
||||
case (None, None):
|
||||
self._attr_color_mode = ColorMode.ONOFF
|
||||
self._attr_supported_color_modes = {ColorMode.ONOFF}
|
||||
case (_, None):
|
||||
self._attr_color_mode = ColorMode.BRIGHTNESS
|
||||
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
|
||||
case (_, _):
|
||||
self._attr_color_mode = ColorMode.HS
|
||||
self._attr_supported_color_modes = {ColorMode.HS, ColorMode.RGB}
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Switch the light on, change brightness, change color."""
|
||||
if self._ambient:
|
||||
_LOGGER.debug("Switching ambient light on for: %s", self.name)
|
||||
try:
|
||||
await self.hass.async_add_executor_job(
|
||||
self.device.appliance.set_setting, self.bsh_key, True
|
||||
)
|
||||
except HomeConnectError as err:
|
||||
_LOGGER.error("Error while trying to turn on ambient light: %s", err)
|
||||
return
|
||||
if ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs:
|
||||
_LOGGER.debug("Switching light on for: %s", self.name)
|
||||
try:
|
||||
await self.hass.async_add_executor_job(
|
||||
self.device.appliance.set_setting, self.bsh_key, True
|
||||
)
|
||||
except HomeConnectError as err:
|
||||
_LOGGER.error("Error while trying to turn on light: %s", err)
|
||||
return
|
||||
if self._custom_color_key:
|
||||
if (
|
||||
ATTR_RGB_COLOR in kwargs or ATTR_HS_COLOR in kwargs
|
||||
) and self._enable_custom_color_value_key:
|
||||
try:
|
||||
await self.hass.async_add_executor_job(
|
||||
self.device.appliance.set_setting,
|
||||
self._color_key,
|
||||
BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR,
|
||||
self._enable_custom_color_value_key,
|
||||
)
|
||||
except HomeConnectError as err:
|
||||
_LOGGER.error("Error while trying selecting customcolor: %s", err)
|
||||
if self._attr_brightness is not None:
|
||||
brightness_arg = self._attr_brightness
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
brightness_arg = kwargs[ATTR_BRIGHTNESS]
|
||||
_LOGGER.error("Error while trying selecting custom color: %s", err)
|
||||
return
|
||||
|
||||
brightness = ceil(
|
||||
color_util.brightness_to_value(
|
||||
self._percentage_scale, brightness_arg
|
||||
)
|
||||
if ATTR_RGB_COLOR in kwargs:
|
||||
hex_val = color_util.color_rgb_to_hex(*kwargs[ATTR_RGB_COLOR])
|
||||
try:
|
||||
await self.hass.async_add_executor_job(
|
||||
self.device.appliance.set_setting,
|
||||
self._custom_color_key,
|
||||
f"#{hex_val}",
|
||||
)
|
||||
hs_color = kwargs.get(ATTR_HS_COLOR, self._attr_hs_color)
|
||||
except HomeConnectError as err:
|
||||
_LOGGER.error("Error while trying setting the color: %s", err)
|
||||
elif (ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs) and (
|
||||
self._attr_brightness is not None or ATTR_BRIGHTNESS in kwargs
|
||||
):
|
||||
brightness = 10 + ceil(
|
||||
color_util.brightness_to_value(
|
||||
self._brightness_scale,
|
||||
kwargs.get(ATTR_BRIGHTNESS, self._attr_brightness),
|
||||
)
|
||||
)
|
||||
|
||||
if hs_color is not None:
|
||||
rgb = color_util.color_hsv_to_RGB(
|
||||
hs_color[0], hs_color[1], brightness
|
||||
hs_color = kwargs.get(ATTR_HS_COLOR, self._attr_hs_color)
|
||||
|
||||
if hs_color is not None:
|
||||
rgb = color_util.color_hsv_to_RGB(
|
||||
hs_color[0], hs_color[1], brightness
|
||||
)
|
||||
hex_val = color_util.color_rgb_to_hex(*rgb)
|
||||
try:
|
||||
await self.hass.async_add_executor_job(
|
||||
self.device.appliance.set_setting,
|
||||
self._custom_color_key,
|
||||
f"#{hex_val}",
|
||||
)
|
||||
hex_val = color_util.color_rgb_to_hex(rgb[0], rgb[1], rgb[2])
|
||||
try:
|
||||
await self.hass.async_add_executor_job(
|
||||
self.device.appliance.set_setting,
|
||||
self._custom_color_key,
|
||||
f"#{hex_val}",
|
||||
)
|
||||
except HomeConnectError as err:
|
||||
_LOGGER.error(
|
||||
"Error while trying setting the color: %s", err
|
||||
)
|
||||
except HomeConnectError as err:
|
||||
_LOGGER.error("Error while trying setting the color: %s", err)
|
||||
|
||||
elif ATTR_BRIGHTNESS in kwargs:
|
||||
elif self._brightness_key and ATTR_BRIGHTNESS in kwargs:
|
||||
_LOGGER.debug(
|
||||
"Changing brightness for: %s, to: %s",
|
||||
self.name,
|
||||
@ -196,7 +209,7 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
|
||||
)
|
||||
brightness = ceil(
|
||||
color_util.brightness_to_value(
|
||||
self._percentage_scale, kwargs[ATTR_BRIGHTNESS]
|
||||
self._brightness_scale, kwargs[ATTR_BRIGHTNESS]
|
||||
)
|
||||
)
|
||||
try:
|
||||
@ -205,14 +218,6 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
|
||||
)
|
||||
except HomeConnectError as err:
|
||||
_LOGGER.error("Error while trying set the brightness: %s", err)
|
||||
else:
|
||||
_LOGGER.debug("Switching light on for: %s", self.name)
|
||||
try:
|
||||
await self.hass.async_add_executor_job(
|
||||
self.device.appliance.set_setting, self.bsh_key, True
|
||||
)
|
||||
except HomeConnectError as err:
|
||||
_LOGGER.error("Error while trying to turn on light: %s", err)
|
||||
|
||||
self.async_entity_update()
|
||||
|
||||
@ -240,44 +245,33 @@ class HomeConnectLight(HomeConnectEntity, LightEntity):
|
||||
|
||||
_LOGGER.debug("Updated, new light state: %s", self._attr_is_on)
|
||||
|
||||
if self._ambient:
|
||||
if self._custom_color_key:
|
||||
color = self.device.appliance.status.get(self._custom_color_key, {})
|
||||
|
||||
if not color:
|
||||
self._attr_rgb_color = None
|
||||
self._attr_hs_color = None
|
||||
self._attr_brightness = None
|
||||
else:
|
||||
colorvalue = color.get(ATTR_VALUE)[1:]
|
||||
rgb = color_util.rgb_hex_to_rgb_list(colorvalue)
|
||||
hsv = color_util.color_RGB_to_hsv(rgb[0], rgb[1], rgb[2])
|
||||
color_value = color.get(ATTR_VALUE)[1:]
|
||||
rgb = color_util.rgb_hex_to_rgb_list(color_value)
|
||||
self._attr_rgb_color = (rgb[0], rgb[1], rgb[2])
|
||||
hsv = color_util.color_RGB_to_hsv(*rgb)
|
||||
self._attr_hs_color = (hsv[0], hsv[1])
|
||||
self._attr_brightness = color_util.value_to_brightness(
|
||||
self._percentage_scale, hsv[2]
|
||||
self._brightness_scale, hsv[2]
|
||||
)
|
||||
_LOGGER.debug("Updated, new brightness: %s", self._attr_brightness)
|
||||
|
||||
else:
|
||||
_LOGGER.debug(
|
||||
"Updated, new color (%s) and new brightness (%s) ",
|
||||
color_value,
|
||||
self._attr_brightness,
|
||||
)
|
||||
elif self._brightness_key:
|
||||
brightness = self.device.appliance.status.get(self._brightness_key, {})
|
||||
if brightness is None:
|
||||
self._attr_brightness = None
|
||||
else:
|
||||
self._attr_brightness = color_util.value_to_brightness(
|
||||
self._percentage_scale, brightness[ATTR_VALUE]
|
||||
self._brightness_scale, brightness[ATTR_VALUE]
|
||||
)
|
||||
_LOGGER.debug("Updated, new brightness: %s", self._attr_brightness)
|
||||
|
||||
|
||||
class HomeConnectCoolingLight(HomeConnectLight):
|
||||
"""Light entity for Cooling Appliances."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device: HomeConnectDevice,
|
||||
ambient: bool,
|
||||
entity_description: HomeConnectLightEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize Cooling Light Entity."""
|
||||
super().__init__(device, entity_description, ambient)
|
||||
self.entity_description = entity_description
|
||||
self._brightness_key = entity_description.brightness_key
|
||||
self._percentage_scale = (1, 100)
|
||||
|
@ -8,6 +8,7 @@ import pytest
|
||||
|
||||
from homeassistant.components.home_connect.const import (
|
||||
BSH_AMBIENT_LIGHT_BRIGHTNESS,
|
||||
BSH_AMBIENT_LIGHT_COLOR,
|
||||
BSH_AMBIENT_LIGHT_CUSTOM_COLOR,
|
||||
BSH_AMBIENT_LIGHT_ENABLED,
|
||||
COOKING_LIGHTING,
|
||||
@ -150,6 +151,22 @@ async def test_light(
|
||||
STATE_ON,
|
||||
"Hood",
|
||||
),
|
||||
(
|
||||
"light.hood_ambient_light",
|
||||
{
|
||||
BSH_AMBIENT_LIGHT_ENABLED: {"value": True},
|
||||
BSH_AMBIENT_LIGHT_COLOR: {
|
||||
"value": "",
|
||||
},
|
||||
BSH_AMBIENT_LIGHT_CUSTOM_COLOR: {},
|
||||
},
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
"rgb_color": [255, 255, 0],
|
||||
},
|
||||
STATE_ON,
|
||||
"Hood",
|
||||
),
|
||||
(
|
||||
"light.fridgefreezer_external_light",
|
||||
{
|
||||
@ -280,7 +297,7 @@ async def test_light_functionality(
|
||||
SERVICE_TURN_ON,
|
||||
{"brightness": 200},
|
||||
"set_setting",
|
||||
[HomeConnectError, None, HomeConnectError, HomeConnectError],
|
||||
[HomeConnectError, None, HomeConnectError],
|
||||
"Hood",
|
||||
),
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user