Adds four live-tunable `number` entities per AL profile (min/max brightness, min/max color temp) that own the runtime curve values. Slider changes take effect on the next curve tick — no integration reload. State persists across HA restart via `RestoreNumber`. Curve math now reads `min_brightness`, `max_brightness`, `min_color_temp`, `max_color_temp` from the four runtime entities via the entity registry, falling back to `entry.options` when an entity is unavailable. The options flow seeds its four range fields from the current entity state so the dialog matches reality. Also fixes entity friendly names via HA's `has_entity_name` composition: profile "Dining MVP" now reads as "Dining MVP", "Dining MVP Brightness", "Dining MVP Color" — short enough for HA's tightest cards. `unique_id`s are unchanged so existing entity_ids stay stable. Manifest bumped to 2.1.0-cdit.1 (minor, no breaking changes). 14 new tests in `tests/test_number_platform.py`; 108 passing overall. OpenSpec change archived once 9.x live-HA verification completes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2.9 KiB
MODIFIED Requirements
Requirement: Brightness and color temperature follow a synthetic tanh curve
For each config entry, the integration SHALL synthesize the daytime brightness and color-temperature values using a hyperbolic-tangent curve anchored at the timestamps from sunrise_entity and sunset_entity, with a hardcoded half-width of 30 minutes (RAMP_HALF_WIDTH_SECONDS = 1800) at each event. The brightness value at time t SHALL follow:
t ≤ t_sunrise − 1800s: value = configured minimumt_sunrise − 1800s < t < t_sunrise + 1800s: value = tanh-interpolated minimum → maximumt_sunrise + 1800s ≤ t ≤ t_sunset − 1800s: value = configured maximumt_sunset − 1800s < t < t_sunset + 1800s: value = tanh-interpolated maximum → minimumt ≥ t_sunset + 1800s: value = configured minimum
The same curve shape SHALL be applied to color temperature using min_color_temp and max_color_temp as the curve bounds.
The four bound values (min_brightness, max_brightness, min_color_temp, max_color_temp) SHALL be read at evaluation time from the four runtime range entities defined in the runtime-range-controls capability, with fallback to entry.options[CONF_*] when an entity is unavailable. The curve evaluation SHALL NOT read these four values directly from entry.options during normal operation.
Scenario: Brightness is at minimum well before sunrise
- WHEN the current time is more than 30 minutes before the
sunrise_entitytimestamp - THEN the computed brightness SHALL equal the current value of
number.adaptive_lighting_<name>_min_brightness
Scenario: Brightness is exactly at the midpoint at the sunrise event
- WHEN the current time equals the
sunrise_entitytimestamp - THEN the computed brightness SHALL equal
(current_min_brightness + current_max_brightness) / 2 - WHERE
current_min_brightnessandcurrent_max_brightnessare the current states of the corresponding number entities
Scenario: Brightness is at maximum during the day
- WHEN the current time is between
sunrise_entity + 30minandsunset_entity − 30min - THEN the computed brightness SHALL equal the current value of
number.adaptive_lighting_<name>_max_brightness
Scenario: Color temperature follows the same curve shape
- WHEN the current time is at any point on the curve
- THEN the computed color temperature SHALL follow the same tanh interpolation between the current values of
number.adaptive_lighting_<name>_min_color_tempand_max_color_tempas the brightness curve does between the two brightness entities
Scenario: Bound values are taken from runtime entities, not from entry.options
- GIVEN
entry.options[CONF_MIN_BRIGHTNESS]is 5 - AND
number.adaptive_lighting_<name>_min_brightnessis at 30 - WHEN the curve is evaluated at a time before
sunrise_entity − 1800s - THEN the computed brightness SHALL equal 30 (the entity state), not 5 (
entry.options)