Migrate hue lights to use Kelvin (#132835)

This commit is contained in:
epenet 2024-12-10 13:55:28 +01:00 committed by GitHub
parent 6f3a230524
commit 416a4c02b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 76 additions and 51 deletions

View File

@ -12,7 +12,7 @@ import aiohue
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_COLOR_TEMP_KELVIN,
ATTR_EFFECT,
ATTR_FLASH,
ATTR_HS_COLOR,
@ -35,7 +35,7 @@ from homeassistant.helpers.update_coordinator import (
DataUpdateCoordinator,
UpdateFailed,
)
from homeassistant.util import color
from homeassistant.util import color as color_util
from ..bridge import HueBridge
from ..const import (
@ -362,7 +362,7 @@ class HueLight(CoordinatorEntity, LightEntity):
"bulb in the Philips Hue App."
)
LOGGER.warning(err, self.name)
if self.gamut and not color.check_valid_gamut(self.gamut):
if self.gamut and not color_util.check_valid_gamut(self.gamut):
err = "Color gamut of %s: %s, not valid, setting gamut to None."
LOGGER.debug(err, self.name, str(self.gamut))
self.gamut_typ = GAMUT_TYPE_UNAVAILABLE
@ -427,49 +427,50 @@ class HueLight(CoordinatorEntity, LightEntity):
source = self.light.action if self.is_group else self.light.state
if mode in ("xy", "hs") and "xy" in source:
return color.color_xy_to_hs(*source["xy"], self.gamut)
return color_util.color_xy_to_hs(*source["xy"], self.gamut)
return None
@property
def color_temp(self):
"""Return the CT color value."""
def color_temp_kelvin(self) -> int | None:
"""Return the color temperature value in Kelvin."""
# Don't return color temperature unless in color temperature mode
if self._color_mode != "ct":
return None
if self.is_group:
return self.light.action.get("ct")
return self.light.state.get("ct")
ct = (
self.light.action.get("ct") if self.is_group else self.light.state.get("ct")
)
return color_util.color_temperature_mired_to_kelvin(ct) if ct else None
@property
def min_mireds(self):
"""Return the coldest color_temp that this light supports."""
def max_color_temp_kelvin(self) -> int:
"""Return the coldest color_temp_kelvin that this light supports."""
if self.is_group:
return super().min_mireds
return super().max_color_temp_kelvin
min_mireds = self.light.controlcapabilities.get("ct", {}).get("min")
# We filter out '0' too, which can be incorrectly reported by 3rd party buls
if not min_mireds:
return super().min_mireds
return super().max_color_temp_kelvin
return min_mireds
return color_util.color_temperature_mired_to_kelvin(min_mireds)
@property
def max_mireds(self):
"""Return the warmest color_temp that this light supports."""
def min_color_temp_kelvin(self) -> int:
"""Return the warmest color_temp_kelvin that this light supports."""
if self.is_group:
return super().max_mireds
return super().min_color_temp_kelvin
if self.is_livarno:
return 500
max_mireds = self.light.controlcapabilities.get("ct", {}).get("max")
if not max_mireds:
return super().max_mireds
return super().min_color_temp_kelvin
return max_mireds
return color_util.color_temperature_mired_to_kelvin(max_mireds)
@property
def is_on(self):
@ -541,11 +542,14 @@ class HueLight(CoordinatorEntity, LightEntity):
# Philips hue bulb models respond differently to hue/sat
# requests, so we convert to XY first to ensure a consistent
# color.
xy_color = color.color_hs_to_xy(*kwargs[ATTR_HS_COLOR], self.gamut)
xy_color = color_util.color_hs_to_xy(*kwargs[ATTR_HS_COLOR], self.gamut)
command["xy"] = xy_color
elif ATTR_COLOR_TEMP in kwargs:
temp = kwargs[ATTR_COLOR_TEMP]
command["ct"] = max(self.min_mireds, min(temp, self.max_mireds))
elif ATTR_COLOR_TEMP_KELVIN in kwargs:
temp_k = max(
self.min_color_temp_kelvin,
min(self.max_color_temp_kelvin, kwargs[ATTR_COLOR_TEMP_KELVIN]),
)
command["ct"] = color_util.color_temperature_kelvin_to_mired(temp_k)
if ATTR_BRIGHTNESS in kwargs:
command["bri"] = hass_to_hue_brightness(kwargs[ATTR_BRIGHTNESS])

View File

@ -12,7 +12,7 @@ from aiohue.v2.models.feature import DynamicStatus
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_COLOR_TEMP_KELVIN,
ATTR_FLASH,
ATTR_TRANSITION,
ATTR_XY_COLOR,
@ -27,6 +27,7 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.helpers.entity_registry as er
from homeassistant.util import color as color_util
from ..bridge import HueBridge
from ..const import DOMAIN
@ -157,7 +158,7 @@ class GroupedHueLight(HueBaseEntity, LightEntity):
"""Turn the grouped_light on."""
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
xy_color = kwargs.get(ATTR_XY_COLOR)
color_temp = normalize_hue_colortemp(kwargs.get(ATTR_COLOR_TEMP))
color_temp = normalize_hue_colortemp(kwargs.get(ATTR_COLOR_TEMP_KELVIN))
brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
flash = kwargs.get(ATTR_FLASH)
@ -235,9 +236,21 @@ class GroupedHueLight(HueBaseEntity, LightEntity):
if color_temp := light.color_temperature:
lights_with_color_temp_support += 1
# we assume mired values from the first capable light
self._attr_color_temp = color_temp.mirek
self._attr_max_mireds = color_temp.mirek_schema.mirek_maximum
self._attr_min_mireds = color_temp.mirek_schema.mirek_minimum
self._attr_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(color_temp.mirek)
if color_temp.mirek
else None
)
self._attr_min_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(
color_temp.mirek_schema.mirek_maximum
)
)
self._attr_max_color_temp_kelvin = (
color_util.color_temperature_mired_to_kelvin(
color_temp.mirek_schema.mirek_minimum
)
)
if color_temp.mirek is not None and color_temp.mirek_valid:
lights_in_colortemp_mode += 1
if color := light.color:

View File

@ -2,6 +2,8 @@
from __future__ import annotations
from homeassistant.util import color as color_util
def normalize_hue_brightness(brightness: float | None) -> float | None:
"""Return calculated brightness values."""
@ -21,10 +23,11 @@ def normalize_hue_transition(transition: float | None) -> float | None:
return transition
def normalize_hue_colortemp(colortemp: int | None) -> int | None:
def normalize_hue_colortemp(colortemp_k: int | None) -> int | None:
"""Return color temperature within Hue's ranges."""
if colortemp is not None:
# Hue only accepts a range between 153..500
colortemp = min(colortemp, 500)
colortemp = max(colortemp, 153)
return colortemp
if colortemp_k is None:
return None
colortemp = color_util.color_temperature_kelvin_to_mired(colortemp_k)
# Hue only accepts a range between 153..500
colortemp = min(colortemp, 500)
return max(colortemp, 153)

View File

@ -13,7 +13,7 @@ from aiohue.v2.models.light import Light
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_COLOR_TEMP_KELVIN,
ATTR_EFFECT,
ATTR_FLASH,
ATTR_TRANSITION,
@ -28,6 +28,7 @@ from homeassistant.components.light import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import color as color_util
from ..bridge import HueBridge
from ..const import DOMAIN
@ -39,9 +40,9 @@ from .helpers import (
)
EFFECT_NONE = "None"
FALLBACK_MIN_MIREDS = 153 # 6500 K
FALLBACK_MAX_MIREDS = 500 # 2000 K
FALLBACK_MIREDS = 173 # halfway
FALLBACK_MIN_KELVIN = 6500
FALLBACK_MAX_KELVIN = 2000
FALLBACK_KELVIN = 5800 # halfway
async def async_setup_entry(
@ -164,28 +165,32 @@ class HueLight(HueBaseEntity, LightEntity):
return None
@property
def color_temp(self) -> int:
"""Return the color temperature."""
def color_temp_kelvin(self) -> int | None:
"""Return the color temperature value in Kelvin."""
if color_temp := self.resource.color_temperature:
return color_temp.mirek
return color_util.color_temperature_mired_to_kelvin(color_temp.mirek)
# return a fallback value to prevent issues with mired->kelvin conversions
return FALLBACK_MIREDS
return FALLBACK_KELVIN
@property
def min_mireds(self) -> int:
"""Return the coldest color_temp that this light supports."""
def max_color_temp_kelvin(self) -> int:
"""Return the coldest color_temp_kelvin that this light supports."""
if color_temp := self.resource.color_temperature:
return color_temp.mirek_schema.mirek_minimum
return color_util.color_temperature_mired_to_kelvin(
color_temp.mirek_schema.mirek_minimum
)
# return a fallback value to prevent issues with mired->kelvin conversions
return FALLBACK_MIN_MIREDS
return FALLBACK_MAX_KELVIN
@property
def max_mireds(self) -> int:
"""Return the warmest color_temp that this light supports."""
def min_color_temp_kelvin(self) -> int:
"""Return the warmest color_temp_kelvin that this light supports."""
if color_temp := self.resource.color_temperature:
return color_temp.mirek_schema.mirek_maximum
return color_util.color_temperature_mired_to_kelvin(
color_temp.mirek_schema.mirek_maximum
)
# return a fallback value to prevent issues with mired->kelvin conversions
return FALLBACK_MAX_MIREDS
return FALLBACK_MIN_KELVIN
@property
def extra_state_attributes(self) -> dict[str, str] | None:
@ -210,7 +215,7 @@ class HueLight(HueBaseEntity, LightEntity):
"""Turn the device on."""
transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
xy_color = kwargs.get(ATTR_XY_COLOR)
color_temp = normalize_hue_colortemp(kwargs.get(ATTR_COLOR_TEMP))
color_temp = normalize_hue_colortemp(kwargs.get(ATTR_COLOR_TEMP_KELVIN))
brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
if self._last_brightness and brightness is None:
# The Hue bridge sets the brightness to 1% when turning on a bulb