adaptive-lighting/CHANGELOG.md
Casey 1b21228b30 Implement add-output-sensors: 36/41 tasks complete
Three sensor entities per AL profile expose the curve's current outputs
plus actual sun elevation as graphable numerics with
SensorStateClass.MEASUREMENT, so HA's recorder + apexcharts-card chart
them natively:

- sensor.<profile>_output_brightness   (% — from self._settings)
- sensor.<profile>_output_color_temp   (K — from self._settings)
- sensor.<profile>_sun_elevation       (° — from sun.sun.attributes.elevation)

Architecture: master switch publishes computed outputs to
hass.data[DOMAIN][entry_id]["outputs"] after each curve tick, then fires
a per-entry dispatcher signal. Sensors subscribe and read from the cache.
Single computation path, push-based updates, no polling.

The existing master switch attributes (brightness_pct, color_temp_kelvin,
synthetic sun_position in [-1,+1]) are unchanged — sensors are purely
additive. Manifest bumped to 2.2.0-cdit.1 (minor; no breaking changes).

Artifact realignment along the way: Q2 answer assumed sun_position was
Sun2 elevation degrees, but reading color_and_brightness.py revealed
it's a synthetic float in [-1,+1] derived from the brightness curve.
Switched to pulling actual elevation from sun.sun (Decision 8 added),
renamed sensor from sun_position to sun_elevation. Friendly names use
asymmetric "Output" prefix to dodge collision with the adapt-brightness
switch and Min/Max color-temp numbers.

Remaining: group 6 (manual live-HA verification on
homeassistant.onca-blenny.ts.net) — requires HACS deploy.

15 new sensor tests pass; full suite green (123/123). openspec
validate --strict green. ruff clean on new files.
2026-05-21 10:11:52 +02:00

10 KiB
Raw Blame History

Changelog — CDiT Adaptive Lighting fork

All notable CDiT-fork changes are documented here. The upstream basnijholt/adaptive-lighting changelog is in upstream's release notes; this file covers only changes specific to this fork.

The format is loosely based on Keep a Changelog.


Standing on the shoulders of giants

This fork builds on basnijholt/adaptive-lighting — years of work by @basnijholt and 130+ contributors. The curve math, light intercept, HACS distribution, simulator webapp, and the long tail of edge cases the original handles correctly all come from that codebase. This fork is a narrow set of opinions layered on a deep, mature foundation; the credit for making this idea work at all belongs upstream.

If you're not specifically a CDiT-style single-household installation, please prefer the upstream integration — it's better-maintained, supports more use cases, and has the entire community behind it. Issues with core curve math or light handling belong on the upstream tracker, where they reach the maintainers who can actually fix them for everyone.


[2.2.0-cdit.1] — Unreleased

Added

  • Three read-only sensor entities per profileoutput_brightness (%), output_color_temp (K), sun_elevation (°). They expose the curve's current target outputs alongside HA's built-in sun.sun elevation as graphable numerics with state_class: measurement, so the History panel, apexcharts-card, and mini-graph-card chart them natively. The existing master-switch attributes (brightness_pct, color_temp_kelvin, the synthetic sun_position in [-1, +1]) are unchanged.
  • Push-based sensor updates via a per-entry dispatcher signal fired by the master switch after each curve tick. No polling, no duplicate curve math — sensors are pure readers of a runtime cache the master switch publishes to.
  • sun_elevation is sourced from sun.sun.attributes.elevation on every curve tick. If sun.sun is missing or the attribute is absent (rare; can happen during very early HA startup), the sensor renders as unknown for that tick — the other two sensors continue updating normally.

Changed

  • manifest.json version bumped to 2.2.0-cdit.1. Minor bump; no breaking config-entry changes — existing 2.1 entries upgrade in place and gain the three new sensor entities on next setup.

Migration

No user action required. Restart HA after upgrade and the three new sensors appear under each profile's device page. Add them to a Lovelace card or apexcharts-card to start graphing.


[2.1.0-cdit.1] — Unreleased

Added

  • Four live-tunable number entities per profilemin_brightness, max_brightness, min_color_temp, max_color_temp. Drop the four sliders onto any Lovelace card to tune the curve from the dashboard without opening the options dialog. Slider position persists across Home Assistant restarts via RestoreNumber.
  • Curve math reads the runtime values from the entities on every tick (with a fallback to entry.options when an entity is unavailable, e.g., during early-setup races). Slider changes take effect on the next curve evaluation — no integration reload, no restart.
  • Options-flow opens with current slider values, not stale options — if you tweaked the slider on the dashboard, the dialog shows the current value, not the value you typed in at setup. Saving the dialog resets the sliders to the just-saved values (explicit gesture wins).

Changed

  • Entity friendly names use HA's has_entity_name composition. For a profile named "Dining MVP" you now see "Dining MVP", "Dining MVP Brightness", "Dining MVP Color" on the dashboard instead of "Adaptive Lighting Adapt Brightness dining_mvp_lights" (which truncated to "Adaptive Lighting Adapt Br…"). Existing entity_ids are preserved by the entity registry — automations and scripts referencing them keep working.
  • manifest.json version bumped to 2.1.0-cdit.1. Minor bump; no breaking config-entry changes — existing 2.0 entries upgrade in place and gain the four new number entities on next setup.

Migration

No user action required for existing 2.0 installs — restart HA after the upgrade and the four new entities appear under each profile's device page, seeded with that profile's current options values.


[2.0.0-cdit.1] — Unreleased

The first major CDiT release. Breaking change: existing upstream config entries will not load — see "Upgrading" below.

Added

  • Sectioned options dialog rendered via HA's section() helper. Six groups (Targets, Daytime curve, Sun schedule, Light control, Advanced, Diagnostics) replace the upstream 40-field flat form.
  • Native HA selectors throughoutNumberSelector (slider for brightness 1100 %, box for color temp 100010000 K), EntitySelector (typed to domain=sensor, device_class=timestamp for sun events, domain=light, multiple=True for the light list), BooleanSelector.
  • Conditional field visibilitysend_split_delay only appears when its driver separate_turn_on_commands is enabled.
  • Entity-driven sun timing — two new options sunrise_entity and sunset_entity accept any sensor with device_class: timestamp. Defaults to the built-in sensor.sun_next_rising / sensor.sun_next_setting. Plug in Sun2 (sensor.sun2_dawn, sensor.sun2_astro_dawn, etc.) without any code changes.
  • Synthetic tanh brightness/color-temp curve with a hardcoded 30-minute ramp half-width around each sun event. Tunable in const.py via RAMP_HALF_WIDTH_SECONDS (currently 1800).
  • OptionsFlowWithReload — saving options reloads the integration cleanly without a manual reload.
  • Strict version-break guardasync_setup_entry raises ConfigEntryError with a clear message when a config entry's version is older than the current major.
  • Sleep-switch tombstone cleanup — on first load after upgrade, orphan switch.adaptive_lighting_sleep_mode_* entities owned by this integration are removed from the entity registry and logged at INFO.
  • Plain-language strings — every label, description, and abort message rewritten to read like a sentence a human wrote, not engineer shorthand. Sections get a one-sentence framer at the top.

Changed

  • DEFAULT_MIN_BRIGHTNESS: 15. 1 % reads as off on most bulbs; 5 % is the dim-but-visible floor.
  • DEFAULT_MIN_COLOR_TEMP: 2000 K2200 K. Less sodium-vapor orange; warmer-lamp tone.
  • Master switch icon: mdi:theme-light-darkmdi:weather-sunny-alert.
  • adapt_color switch icon: mdi:sun-thermometermdi:invert-colors.
  • adapt_brightness switch icon: mdi:brightness-4mdi:brightness-percent.
  • Minimum Home Assistant version: pinned to 2025.1.0 in manifest.json.
  • Manifest metadatacodeowners, documentation, and issue_tracker now point to CaseyRo/adaptive-lighting.

Removed

21 configuration fields, 1 entity, 1 service, all part of upstream features that the CDiT fork does not use.

  • Sleep mode cluster (6 fields + 1 entity): sleep_brightness, sleep_rgb_or_color_temp, sleep_color_temp, sleep_rgb_color, sleep_transition, transition_until_sleep. The switch.adaptive_lighting_sleep_mode_<name> entity is no longer created. Each profile now provides three switches (master, adapt_color, adapt_brightness) instead of four.
  • Manual sun timing (8 fields): sunrise_time, min_sunrise_time, max_sunrise_time, sunrise_offset, sunset_time, min_sunset_time, max_sunset_time, sunset_offset. Replaced by the two *_entity options above.
  • Brightness curve shape (3 fields): brightness_mode, brightness_mode_time_dark, brightness_mode_time_light. The curve is now always a tanh ramp.
  • Take-over-control cluster (4 fields): take_over_control, take_over_control_mode, detect_non_ha_changes, autoreset_control_seconds. Manual overrides are expected to live at the scene/automation layer.
  • Anti-AL flags (2 fields): only_once, adapt_only_on_bare_turn_on. If you don't want continuous adaptation on a light, don't run AL on that light.
  • Service: adaptive_lighting.set_manual_control no longer exists. The dependent state machine in switch.py and AdaptiveLightingManager remains as dead code in this release; follow-up cleanup will delete it.

Migration / upgrading from upstream

  1. Update via HACS (or copy custom_components/adaptive_lighting/ over your existing install).
  2. Restart Home Assistant.
  3. The existing config entry shows as "failed to load" with the message "Adaptive Lighting v2 (CDiT fork) is incompatible with the existing config entry."
  4. Delete the failed entry: Settings → Devices & Services → Adaptive Lighting → ⋮ → Delete.
  5. Add a fresh entry: Settings → Devices & Services → Add Integration → Adaptive Lighting.
  6. Open the new entry's Configure dialog and walk through the six sections.
  7. (Optional) Install Sun2 via HACS and point sunrise_entity / sunset_entity at one of its sensors.

Internal

  • color_and_brightness.py: rewritten. SunLightSettings is now a pure curve-math dataclass with 5 fields. Sun event timestamps are passed in as arguments by the caller (which reads them from HA entities) rather than computed via astral.
  • config_flow.py: rewritten. ~250 LOC instead of 175 LOC, but each section, selector factory, and conditional is now isolated and testable.
  • __init__.py: adds version-check + tombstone-cleanup guards at the top of async_setup_entry.
  • Total integration code shrank by ~400 LOC despite the new schema builder.

Known limitations

  • AdaptiveLightingManager (in switch.py) still contains the manual-control bookkeeping infrastructure. The branches that would populate it are now dead code (the relevant AdaptiveSwitch attributes are bridge stubs hardcoded to False), but the bookkeeping dicts and helper methods remain. Cleanup is deferred to a follow-up change.
  • Locale files other than en.json are out of sync with the new schema and may render English strings until they are re-translated. Out of scope for this release.
  • astral is still a transitive dependency. The curve-evaluation path no longer imports it, so pruning is just a pyproject.toml edit when the package as a whole stops using it.