From d8774dcd2507469c1185a170386c097b62901c01 Mon Sep 17 00:00:00 2001 From: fir3man Date: Wed, 30 Sep 2026 22:15:20 +0200 Subject: [PATCH] feat: make CT-from-RGB-blend opt-in via transition_until_sleep_ct_mode Add `transition_until_sleep_ct_mode` (`linear` | `match_rgb`, default `linear`) so existing installations keep the historical kelvin interpolation unless they opt in. `transition_until_sleep_ct_curve` only applies in `match_rgb` mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 3 +- .../adaptive_lighting/color_and_brightness.py | 3 +- custom_components/adaptive_lighting/const.py | 33 ++++++++++++--- .../adaptive_lighting/strings.json | 6 ++- custom_components/adaptive_lighting/switch.py | 2 + .../adaptive_lighting/translations/en.json | 6 ++- .../adaptive_lighting/translations/pl.json | 6 ++- docs/configuration.md | 3 +- tests/test_color_and_brightness.py | 40 +++++++++++++++++++ 9 files changed, 88 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c81a4d04..14214863 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,8 @@ The YAML and frontend configuration methods support all of the options listed be | `sleep_rgb_color` | RGB color in sleep mode (used when `sleep_rgb_or_color_temp` is "rgb_color"). 🌈 | `[255, 56, 0]` | RGB color | | `sleep_transition` | Duration of transition when "sleep mode" is toggled in seconds. 😴 | `1` | `float` 0-6553 | | `transition_until_sleep` | When enabled, Adaptive Lighting will treat sleep settings as the minimum, transitioning to these values after sunset. 🌙 | `False` | `bool` | -| `transition_until_sleep_ct_curve` | Only used with `transition_until_sleep` and `sleep_rgb_or_color_temp: rgb_color`. Shapes how fast color-temperature-only lights warm up towards `sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up earlier (use if your color-temp lights look colder than your RGB lights in the evening), `<1` later. 🌡️ | `1.0` | `float` | +| `transition_until_sleep_ct_mode` | How color-temperature-only lights transition after sunset when `transition_until_sleep` is enabled and `sleep_rgb_or_color_temp` is `rgb_color`. `linear`: interpolate `min_color_temp` → `sleep_color_temp` in Kelvin. `match_rgb`: use the color temperature of the RGB blend that RGB lights show at the same moment, so mixed setups look uniform. 🌡️ | `linear` | one of `['linear', 'match_rgb']` | +| `transition_until_sleep_ct_curve` | Only used with `transition_until_sleep_ct_mode: match_rgb`. Calibrates how fast color-temperature-only lights warm up towards `sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up earlier (use if your color-temp lights still look colder than your RGB lights), `<1` later. 🎛️ | `1.0` | `float` | | `sunrise_time` | Set a fixed time (HH:MM:SS) for sunrise. 🌅 | `None` | `str` | | `min_sunrise_time` | Set the earliest virtual sunrise time (HH:MM:SS), allowing for later sunrises. 🌅 | `None` | `str` | | `max_sunrise_time` | Set the latest virtual sunrise time (HH:MM:SS), allowing for earlier sunrises. 🌅 | `None` | `str` | diff --git a/custom_components/adaptive_lighting/color_and_brightness.py b/custom_components/adaptive_lighting/color_and_brightness.py index 63306483..5ee06eff 100644 --- a/custom_components/adaptive_lighting/color_and_brightness.py +++ b/custom_components/adaptive_lighting/color_and_brightness.py @@ -297,6 +297,7 @@ class SunLightSettings: brightness_mode_time_dark: datetime.timedelta brightness_mode_time_light: datetime.timedelta brightness_mode: Literal["default", "linear", "tanh"] = "default" + adapt_until_sleep_ct_mode: Literal["linear", "match_rgb"] = "linear" adapt_until_sleep_ct_curve: float = 1.0 sunrise_offset: datetime.timedelta = datetime.timedelta() sunset_offset: datetime.timedelta = datetime.timedelta() @@ -447,7 +448,7 @@ class SunLightSettings: r, g, b = color_temperature_to_rgb(color_temp_kelvin) rgb_color = (round(r), round(g), round(b)) xy_color: tuple[float, float] = color_RGB_to_xy(*rgb_color) - if force_rgb_color: + if force_rgb_color and self.adapt_until_sleep_ct_mode == "match_rgb": # Keep color-temp-only lights on the same perceived trajectory as # the RGB blend: derive the CCT from the blended color instead of # interpolating in kelvin space, which diverges perceptually from diff --git a/custom_components/adaptive_lighting/const.py b/custom_components/adaptive_lighting/const.py index 9b164ec4..6c908d04 100644 --- a/custom_components/adaptive_lighting/const.py +++ b/custom_components/adaptive_lighting/const.py @@ -233,16 +233,28 @@ DOCS[CONF_ADAPT_UNTIL_SLEEP] = ( "transitioning to these values after sunset. 🌙" ) +CONF_ADAPT_UNTIL_SLEEP_CT_MODE, DEFAULT_ADAPT_UNTIL_SLEEP_CT_MODE = ( + "transition_until_sleep_ct_mode", + "linear", +) +DOCS[CONF_ADAPT_UNTIL_SLEEP_CT_MODE] = ( + "How color-temperature-only lights transition after sunset when " + "`transition_until_sleep` is enabled and `sleep_rgb_or_color_temp` is " + "`rgb_color`. `linear`: interpolate `min_color_temp` → `sleep_color_temp` " + "in Kelvin. `match_rgb`: use the color temperature of the RGB blend that " + "RGB lights show at the same moment, so mixed setups look uniform. 🌡️" +) + CONF_ADAPT_UNTIL_SLEEP_CT_CURVE, DEFAULT_ADAPT_UNTIL_SLEEP_CT_CURVE = ( "transition_until_sleep_ct_curve", 1.0, ) DOCS[CONF_ADAPT_UNTIL_SLEEP_CT_CURVE] = ( - "Only used with `transition_until_sleep` and `sleep_rgb_or_color_temp: " - "rgb_color`. Shapes how fast color-temperature-only lights warm up towards " - "`sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the " - "CCT, `>1` warms up earlier (use if your color-temp lights look colder than " - "your RGB lights in the evening), `<1` later. 🌡️" + "Only used with `transition_until_sleep_ct_mode: match_rgb`. Calibrates how " + "fast color-temperature-only lights warm up towards `sleep_color_temp` " + "compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up " + "earlier (use if your color-temp lights still look colder than your RGB " + "lights), `<1` later. 🎛️" ) CONF_ADAPT_DELAY, DEFAULT_ADAPT_DELAY = "adapt_delay", 0 @@ -400,6 +412,17 @@ VALIDATION_TUPLES: list[tuple[str, Any, Any]] = [ ), (CONF_SLEEP_TRANSITION, DEFAULT_SLEEP_TRANSITION, VALID_TRANSITION), (CONF_ADAPT_UNTIL_SLEEP, DEFAULT_ADAPT_UNTIL_SLEEP, bool), + ( + CONF_ADAPT_UNTIL_SLEEP_CT_MODE, + DEFAULT_ADAPT_UNTIL_SLEEP_CT_MODE, + selector.SelectSelector( # type: ignore[arg-type] + selector.SelectSelectorConfig( + options=["linear", "match_rgb"], + multiple=False, + mode=selector.SelectSelectorMode.DROPDOWN, + ), + ), + ), ( CONF_ADAPT_UNTIL_SLEEP_CT_CURVE, DEFAULT_ADAPT_UNTIL_SLEEP_CT_CURVE, diff --git a/custom_components/adaptive_lighting/strings.json b/custom_components/adaptive_lighting/strings.json index d72befe1..32132b9d 100644 --- a/custom_components/adaptive_lighting/strings.json +++ b/custom_components/adaptive_lighting/strings.json @@ -53,6 +53,7 @@ "sleep_rgb_color": "sleep_rgb_color", "sleep_transition": "sleep_transition", "transition_until_sleep": "transition_until_sleep: When enabled, Adaptive Lighting will treat sleep settings as the minimum, transitioning to these values after sunset. 🌙", + "transition_until_sleep_ct_mode": "transition_until_sleep_ct_mode", "transition_until_sleep_ct_curve": "transition_until_sleep_ct_curve", "sunrise_time": "sunrise_time", "min_sunrise_time": "min_sunrise_time", @@ -87,7 +88,7 @@ "sleep_rgb_or_color_temp": "Use either `\"rgb_color\"` or `\"color_temp\"` in sleep mode. 🌙", "sleep_rgb_color": "RGB color in sleep mode (used when `sleep_rgb_or_color_temp` is \"rgb_color\"). 🌈", "sleep_transition": "Duration of transition when \"sleep mode\" is toggled in seconds. 😴", - "transition_until_sleep_ct_curve": "Only used with `transition_until_sleep` and `sleep_rgb_or_color_temp: rgb_color`. Shapes how fast color-temperature-only lights warm up towards `sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up earlier (use if your color-temp lights look colder than your RGB lights in the evening), `<1` later. 🌡️", + "transition_until_sleep_ct_curve": "Only used with `transition_until_sleep_ct_mode: match_rgb`. Calibrates how fast color-temperature-only lights warm up towards `sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up earlier (use if your color-temp lights still look colder than your RGB lights), `<1` later. 🎛️", "sunrise_time": "Set a fixed time (HH:MM:SS) for sunrise. 🌅", "min_sunrise_time": "Set the earliest virtual sunrise time (HH:MM:SS), allowing for later sunrises. 🌅", "max_sunrise_time": "Set the latest virtual sunrise time (HH:MM:SS), allowing for earlier sunrises. 🌅", @@ -102,7 +103,8 @@ "take_over_control_mode": "The adaptation pausing mode when other sources change brightness and/or color of lights. `pause_all` always pauses both brightness and color adaptation. `pause_changed` pauses the adaptation of only the changed attributes and continues adapting unchanged attributes, e.g., continues color adaptation when only brightness was changed.", "autoreset_control_seconds": "Automatically reset the manual control after a number of seconds. Set to 0 to disable. ⏲️", "send_split_delay": "Delay (ms) between `separate_turn_on_commands` for lights that don't support simultaneous brightness and color setting. ⏲️", - "adapt_delay": "Wait time (seconds) between light turn on and Adaptive Lighting applying changes. Might help to avoid flickering. ⏲️" + "adapt_delay": "Wait time (seconds) between light turn on and Adaptive Lighting applying changes. Might help to avoid flickering. ⏲️", + "transition_until_sleep_ct_mode": "How color-temperature-only lights transition after sunset when `transition_until_sleep` is enabled and `sleep_rgb_or_color_temp` is `rgb_color`. `linear`: interpolate `min_color_temp` → `sleep_color_temp` in Kelvin. `match_rgb`: use the color temperature of the RGB blend that RGB lights show at the same moment, so mixed setups look uniform. 🌡️" } } } diff --git a/custom_components/adaptive_lighting/switch.py b/custom_components/adaptive_lighting/switch.py index 4ae02b64..95abf438 100644 --- a/custom_components/adaptive_lighting/switch.py +++ b/custom_components/adaptive_lighting/switch.py @@ -97,6 +97,7 @@ from .const import ( CONF_ADAPT_ONLY_ON_BARE_TURN_ON, CONF_ADAPT_UNTIL_SLEEP, CONF_ADAPT_UNTIL_SLEEP_CT_CURVE, + CONF_ADAPT_UNTIL_SLEEP_CT_MODE, CONF_AUTORESET_CONTROL, CONF_BRIGHTNESS_MODE, CONF_BRIGHTNESS_MODE_TIME_DARK, @@ -1020,6 +1021,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity): astral_observer=observer, adapt_until_sleep=data[CONF_ADAPT_UNTIL_SLEEP], adapt_until_sleep_ct_curve=data[CONF_ADAPT_UNTIL_SLEEP_CT_CURVE], + adapt_until_sleep_ct_mode=data[CONF_ADAPT_UNTIL_SLEEP_CT_MODE], max_brightness=data[CONF_MAX_BRIGHTNESS], max_color_temp=data[CONF_MAX_COLOR_TEMP], min_brightness=data[CONF_MIN_BRIGHTNESS], diff --git a/custom_components/adaptive_lighting/translations/en.json b/custom_components/adaptive_lighting/translations/en.json index 3bf7a96b..75448696 100644 --- a/custom_components/adaptive_lighting/translations/en.json +++ b/custom_components/adaptive_lighting/translations/en.json @@ -54,6 +54,7 @@ "sleep_rgb_color": "sleep_rgb_color", "sleep_transition": "sleep_transition", "transition_until_sleep": "transition_until_sleep: When enabled, Adaptive Lighting will treat sleep settings as the minimum, transitioning to these values after sunset. 🌙", + "transition_until_sleep_ct_mode": "transition_until_sleep_ct_mode", "transition_until_sleep_ct_curve": "transition_until_sleep_ct_curve", "sunrise_time": "sunrise_time", "min_sunrise_time": "min_sunrise_time", @@ -88,7 +89,7 @@ "sleep_rgb_or_color_temp": "Use either `\"rgb_color\"` or `\"color_temp\"` in sleep mode. 🌙", "sleep_rgb_color": "RGB color in sleep mode (used when `sleep_rgb_or_color_temp` is \"rgb_color\"). 🌈", "sleep_transition": "Duration of transition when \"sleep mode\" is toggled in seconds. 😴", - "transition_until_sleep_ct_curve": "Only used with `transition_until_sleep` and `sleep_rgb_or_color_temp: rgb_color`. Shapes how fast color-temperature-only lights warm up towards `sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up earlier (use if your color-temp lights look colder than your RGB lights in the evening), `<1` later. 🌡️", + "transition_until_sleep_ct_curve": "Only used with `transition_until_sleep_ct_mode: match_rgb`. Calibrates how fast color-temperature-only lights warm up towards `sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up earlier (use if your color-temp lights still look colder than your RGB lights), `<1` later. 🎛️", "sunrise_time": "Set a fixed time (HH:MM:SS) for sunrise. 🌅", "min_sunrise_time": "Set the earliest virtual sunrise time (HH:MM:SS), allowing for later sunrises. 🌅", "max_sunrise_time": "Set the latest virtual sunrise time (HH:MM:SS), allowing for earlier sunrises. 🌅", @@ -103,7 +104,8 @@ "take_over_control_mode": "The adaptation pausing mode when other sources change brightness and/or color of lights. `pause_all` always pauses both brightness and color adaptation. `pause_changed` pauses the adaptation of only the changed attributes and continues adapting unchanged attributes, e.g., continues color adaptation when only brightness was changed.", "autoreset_control_seconds": "Automatically reset the manual control after a number of seconds. Set to 0 to disable. ⏲️", "send_split_delay": "Delay (ms) between `separate_turn_on_commands` for lights that don't support simultaneous brightness and color setting. ⏲️", - "adapt_delay": "Wait time (seconds) between light turn on and Adaptive Lighting applying changes. Might help to avoid flickering. ⏲️" + "adapt_delay": "Wait time (seconds) between light turn on and Adaptive Lighting applying changes. Might help to avoid flickering. ⏲️", + "transition_until_sleep_ct_mode": "How color-temperature-only lights transition after sunset when `transition_until_sleep` is enabled and `sleep_rgb_or_color_temp` is `rgb_color`. `linear`: interpolate `min_color_temp` → `sleep_color_temp` in Kelvin. `match_rgb`: use the color temperature of the RGB blend that RGB lights show at the same moment, so mixed setups look uniform. 🌡️" } } } diff --git a/custom_components/adaptive_lighting/translations/pl.json b/custom_components/adaptive_lighting/translations/pl.json index 0aeb9cfe..735c664e 100644 --- a/custom_components/adaptive_lighting/translations/pl.json +++ b/custom_components/adaptive_lighting/translations/pl.json @@ -43,6 +43,7 @@ "prefer_rgb_color": "prefer_rgb_color: Czy w miarę możliwości preferować regulację kolorów RGB zamiast regulacji temperatury barwowej światła. 🌈", "sleep_transition": "sleep_transition: When 'sleep_state' changes. (sekund)", "transition_until_sleep": "transition_until_sleep: Gdy włączone, Adaptacyjne oświetlenie będzie traktowało ustawienia spania jako minimalne i przejdzie do nich po zachodzie słońca. 🌙", + "transition_until_sleep_ct_mode": "transition_until_sleep_ct_mode", "transition_until_sleep_ct_curve": "transition_until_sleep_ct_curve", "sunrise_time": "sunrise_time: Manual override of the sunrise time, if 'None', it uses the actual sunrise time at your location (HH:MM:SS)", "sunrise_offset": "sunrise_offset: How long before(-) or after(+) to define the sunrise point of the cycle (+/- sekund)", @@ -63,7 +64,7 @@ "sleep_rgb_or_color_temp": "Użyj `\"rgb_color\"` albo `\"color_temp\"` w trybie spania. 🌙", "sleep_rgb_color": "Kolor RGB w trybie spania (używane, gdy `sleep_rgb_or_color_temp` jest `rgb_color`). 🌈", "sleep_transition": "Długość przejścia, gdy nastąpi włączenie/wyłączenie \"trybu spania\" (w sekundach). 😴", - "transition_until_sleep_ct_curve": "Używane tylko z `transition_until_sleep` i `sleep_rgb_or_color_temp: rgb_color`. Określa, jak szybko żarówki obsługujące tylko temperaturę barwową ocieplają się w stronę `sleep_color_temp` względem CCT mieszanki RGB: `1` podąża za CCT, `>1` ociepla wcześniej (użyj, gdy żarówki CT wyglądają wieczorem chłodniej niż RGB), `<1` później. 🌡️", + "transition_until_sleep_ct_curve": "Używane tylko z `transition_until_sleep_ct_mode: match_rgb`. Kalibruje, jak szybko żarówki CT ocieplają się w stronę `sleep_color_temp` względem CCT mieszanki RGB: `1` podąża za CCT, `>1` ociepla wcześniej (użyj, gdy żarówki CT nadal wyglądają chłodniej niż RGB), `<1` później. 🎛️", "sunrise_time": "Ustaw stały czas wschodu słońca (HH:MM:SS). 🌅", "min_sunrise_time": "Ustaw czas najwcześniejszego wirtualnego wschodu słońca (HH:MM:SS), pozwala na opóźnienie wschodu słońca. 🌅", "max_sunrise_time": "Ustaw czas najpóźniejszego wirtualnego wschodu słońca (HH:MM:SS), pozwala na przyspieszenie wschodu słońca. 🌅", @@ -77,7 +78,8 @@ "brightness_mode_time_light": "(Pomijany, gdy `brightness_mode='default'`). Czas w sekundach, kiedy jasność będzie zwiększana po wschodzie słońca/zmniejszana przed zachodem słońca. 📈📉", "autoreset_control_seconds": "Czas, po którym manualna kontrola zostanie wyłączona (w sekundach). Ustaw 0, aby wyłączyć. ⏲️", "send_split_delay": "Opóźnienie (w ms) pomiędzy `separate_turn_on_commands` dla świateł, które nie akceptują jednoczesnego ustawiania jasności i koloru. ⏲️", - "adapt_delay": "Czas (w sekundach) pomiędzy włączeniem światła, a rozpoczęciem adaptowania przez Adaptacyjne oświetlenie. Może pomóc zredukować migotanie. ⏲️" + "adapt_delay": "Czas (w sekundach) pomiędzy włączeniem światła, a rozpoczęciem adaptowania przez Adaptacyjne oświetlenie. Może pomóc zredukować migotanie. ⏲️", + "transition_until_sleep_ct_mode": "Jak żarówki obsługujące tylko temperaturę barwową zmieniają się po zachodzie słońca, gdy włączone jest `transition_until_sleep` a `sleep_rgb_or_color_temp` to `rgb_color`. `linear`: interpolacja `min_color_temp` → `sleep_color_temp` w kelwinach. `match_rgb`: temperatura barwowa mieszanki RGB, którą w tym momencie pokazują żarówki RGB — mieszane instalacje wyglądają jednolicie. 🌡️" } } } diff --git a/docs/configuration.md b/docs/configuration.md index 1bc6c49e..b07e62f0 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -49,7 +49,8 @@ All configuration options are listed below with their default values. These opti | `sleep_rgb_color` | RGB color in sleep mode (used when `sleep_rgb_or_color_temp` is "rgb_color"). 🌈 | `[255, 56, 0]` | RGB color | | `sleep_transition` | Duration of transition when "sleep mode" is toggled in seconds. 😴 | `1` | `float` 0-6553 | | `transition_until_sleep` | When enabled, Adaptive Lighting will treat sleep settings as the minimum, transitioning to these values after sunset. 🌙 | `False` | `bool` | -| `transition_until_sleep_ct_curve` | Only used with `transition_until_sleep` and `sleep_rgb_or_color_temp: rgb_color`. Shapes how fast color-temperature-only lights warm up towards `sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up earlier (use if your color-temp lights look colder than your RGB lights in the evening), `<1` later. 🌡️ | `1.0` | `float` | +| `transition_until_sleep_ct_mode` | How color-temperature-only lights transition after sunset when `transition_until_sleep` is enabled and `sleep_rgb_or_color_temp` is `rgb_color`. `linear`: interpolate `min_color_temp` → `sleep_color_temp` in Kelvin. `match_rgb`: use the color temperature of the RGB blend that RGB lights show at the same moment, so mixed setups look uniform. 🌡️ | `linear` | one of `['linear', 'match_rgb']` | +| `transition_until_sleep_ct_curve` | Only used with `transition_until_sleep_ct_mode: match_rgb`. Calibrates how fast color-temperature-only lights warm up towards `sleep_color_temp` compared to the CCT of the RGB blend: `1` follows the CCT, `>1` warms up earlier (use if your color-temp lights still look colder than your RGB lights), `<1` later. 🎛️ | `1.0` | `float` | | `sunrise_time` | Set a fixed time (HH:MM:SS) for sunrise. 🌅 | `None` | `str` | | `min_sunrise_time` | Set the earliest virtual sunrise time (HH:MM:SS), allowing for later sunrises. 🌅 | `None` | `str` | | `max_sunrise_time` | Set the latest virtual sunrise time (HH:MM:SS), allowing for earlier sunrises. 🌅 | `None` | `str` | diff --git a/tests/test_color_and_brightness.py b/tests/test_color_and_brightness.py index 65bfd630..0529ed74 100644 --- a/tests/test_color_and_brightness.py +++ b/tests/test_color_and_brightness.py @@ -592,6 +592,7 @@ def test_adapt_until_sleep_ct_follows_rgb_blend(): brightness_mode_time_dark=dt.timedelta(hours=1), brightness_mode_time_light=dt.timedelta(hours=1), timezone=dt.timezone.utc, + adapt_until_sleep_ct_mode="match_rgb", ) date = dt.datetime(2022, 6, 1, tzinfo=dt.timezone.utc) sunset = settings.sun.sunset(date.date()) @@ -654,6 +655,7 @@ def test_adapt_until_sleep_ct_curve(curve, expect_warmer): "brightness_mode_time_dark": dt.timedelta(hours=1), "brightness_mode_time_light": dt.timedelta(hours=1), "timezone": dt.timezone.utc, + "adapt_until_sleep_ct_mode": "match_rgb", } plain = SunLightSettings(**kwargs) shaped = SunLightSettings(**kwargs, adapt_until_sleep_ct_curve=curve) @@ -683,3 +685,41 @@ def test_adapt_until_sleep_ct_curve(curve, expect_warmer): # endpoints unchanged at_sunset = shaped.brightness_and_color(sunset, is_sleep=False) assert at_sunset["color_temp_kelvin"] == 3000 + + +def test_adapt_until_sleep_ct_mode_linear_is_default_and_unchanged(): + """The default `linear` mode keeps the historical kelvin interpolation.""" + settings = SunLightSettings( + name="test", + astral_observer=location.observer, + adapt_until_sleep=True, + max_brightness=100, + max_color_temp=5500, + min_brightness=30, + min_color_temp=3000, + sleep_brightness=1, + sleep_rgb_or_color_temp="rgb_color", + sleep_color_temp=1000, + sleep_rgb_color=(255, 56, 0), + sunrise_time=None, + min_sunrise_time=None, + max_sunrise_time=None, + sunset_time=None, + min_sunset_time=None, + max_sunset_time=None, + brightness_mode_time_dark=dt.timedelta(hours=1), + brightness_mode_time_light=dt.timedelta(hours=1), + timezone=dt.timezone.utc, + ) + assert settings.adapt_until_sleep_ct_mode == "linear" + date = dt.datetime(2022, 6, 1, tzinfo=dt.timezone.utc) + sunset = settings.sun.sunset(date.date()) + _, midnight = settings.sun.noon_and_midnight(date) + if midnight < sunset: + midnight += dt.timedelta(days=1) + moment = sunset + (midnight - sunset) * 0.5 + result = settings.brightness_and_color(moment, is_sleep=False) + assert result["force_rgb_color"] + assert result["color_temp_kelvin"] == settings.color_temp_kelvin( + result["sun_position"], + )