mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-11 22:34:04 +02:00
* Ensure that interpolation is in [0, 1], fixes #624 * Bump to 1.17.1 * Add assert * Interpolate via HSV space * Add test
This commit is contained in:
parent
7650a1b3e6
commit
f9b6753e6d
3 changed files with 39 additions and 8 deletions
|
|
@ -8,5 +8,5 @@
|
|||
"iot_class": "calculated",
|
||||
"issue_tracker": "https://github.com/basnijholt/adaptive-lighting/issues",
|
||||
"requirements": ["ulid-transform"],
|
||||
"version": "1.17.0"
|
||||
"version": "1.17.1"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
import asyncio
|
||||
import base64
|
||||
import bisect
|
||||
import colorsys
|
||||
import datetime
|
||||
import functools
|
||||
import logging
|
||||
|
|
@ -1549,18 +1550,31 @@ class SimpleSwitch(SwitchEntity, RestoreEntity):
|
|||
self._state = False
|
||||
|
||||
|
||||
def lerp_color(
|
||||
def lerp_color_hsv(
|
||||
rgb1: tuple[int, int, int],
|
||||
rgb2: tuple[int, int, int],
|
||||
t: float,
|
||||
) -> tuple[int, int, int]:
|
||||
"""Linearly interpolate between two RGB colors."""
|
||||
return (
|
||||
int(rgb1[0] + t * (rgb2[0] - rgb1[0])),
|
||||
int(rgb1[1] + t * (rgb2[1] - rgb1[1])),
|
||||
int(rgb1[2] + t * (rgb2[2] - rgb1[2])),
|
||||
"""Linearly interpolate between two RGB colors in HSV color space."""
|
||||
t = abs(t)
|
||||
assert 0 <= t <= 1
|
||||
|
||||
# Convert RGB to HSV
|
||||
hsv1 = colorsys.rgb_to_hsv(*[x / 255.0 for x in rgb1])
|
||||
hsv2 = colorsys.rgb_to_hsv(*[x / 255.0 for x in rgb2])
|
||||
|
||||
# Linear interpolation in HSV space
|
||||
hsv = (
|
||||
hsv1[0] + t * (hsv2[0] - hsv1[0]),
|
||||
hsv1[1] + t * (hsv2[1] - hsv1[1]),
|
||||
hsv1[2] + t * (hsv2[2] - hsv1[2]),
|
||||
)
|
||||
|
||||
# Convert back to RGB
|
||||
rgb = tuple(int(round(x * 255)) for x in colorsys.hsv_to_rgb(*hsv))
|
||||
assert all(0 <= x <= 255 for x in rgb), f"Invalid RGB color: {rgb}"
|
||||
return rgb
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SunLightSettings:
|
||||
|
|
@ -1748,7 +1762,7 @@ class SunLightSettings:
|
|||
# This will result in a perceptible jump in color at sunset and sunrise
|
||||
# because the `color_temperature_to_rgb` function is not 100% accurate.
|
||||
min_color_rgb = color_temperature_to_rgb(self.min_color_temp)
|
||||
rgb_color = lerp_color(min_color_rgb, self.sleep_rgb_color, percent)
|
||||
rgb_color = lerp_color_hsv(min_color_rgb, self.sleep_rgb_color, percent)
|
||||
color_temp_kelvin = self.calc_color_temp_kelvin(percent)
|
||||
force_rgb_color = True
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ from custom_components.adaptive_lighting.switch import (
|
|||
create_context,
|
||||
is_our_context,
|
||||
is_our_context_id,
|
||||
lerp_color_hsv,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
|
@ -1701,3 +1702,19 @@ async def test_adapt_until_sleep_and_rgb_colors(hass):
|
|||
await switch._update_attrs_and_maybe_adapt_lights(context=context)
|
||||
assert switch._settings[ATTR_BRIGHTNESS_PCT] == DEFAULT_SLEEP_BRIGHTNESS
|
||||
assert switch._settings["rgb_color"] == DEFAULT_SLEEP_RGB_COLOR
|
||||
|
||||
|
||||
def test_lerp_color_hsv():
|
||||
assert lerp_color_hsv((255, 0, 0), (0, 255, 0), 0) == (255, 0, 0)
|
||||
assert lerp_color_hsv((255, 0, 0), (0, 255, 0), 1) == (0, 255, 0)
|
||||
assert lerp_color_hsv((255, 0, 0), (0, 255, 0), 0.5) == (255, 255, 0)
|
||||
assert lerp_color_hsv((0, 0, 255), (255, 255, 255), 0.5) == (128, 255, 128)
|
||||
|
||||
# Tests that the interpolation is consistent
|
||||
for t in [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]:
|
||||
color = lerp_color_hsv((255, 0, 0), (0, 255, 0), t)
|
||||
inverted_color = lerp_color_hsv((0, 255, 0), (255, 0, 0), 1 - t)
|
||||
assert color == inverted_color
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
lerp_color_hsv((255, 0, 0), (0, 255, 0), 1.1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue