mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-28 12:54:22 +02:00
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.
227 lines
10 KiB
Markdown
227 lines
10 KiB
Markdown
# 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](https://keepachangelog.com/).
|
||
|
||
---
|
||
|
||
## Standing on the shoulders of giants
|
||
|
||
This fork builds on **[basnijholt/adaptive-lighting](https://github.com/basnijholt/adaptive-lighting)** —
|
||
years of work by [@basnijholt](https://github.com/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 profile** — `output_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 profile** — `min_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 throughout** — `NumberSelector` (slider for
|
||
brightness 1–100 %, box for color temp 1000–10000 K), `EntitySelector`
|
||
(typed to `domain=sensor, device_class=timestamp` for sun events,
|
||
`domain=light, multiple=True` for the light list), `BooleanSelector`.
|
||
- **Conditional field visibility** — `send_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 guard** — `async_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`**: `1` → `5`. 1 % reads as off on most bulbs;
|
||
5 % is the dim-but-visible floor.
|
||
- **`DEFAULT_MIN_COLOR_TEMP`**: `2000 K` → `2200 K`. Less sodium-vapor
|
||
orange; warmer-lamp tone.
|
||
- **Master switch icon**: `mdi:theme-light-dark` → `mdi:weather-sunny-alert`.
|
||
- **`adapt_color` switch icon**: `mdi:sun-thermometer` → `mdi:invert-colors`.
|
||
- **`adapt_brightness` switch icon**: `mdi:brightness-4` →
|
||
`mdi:brightness-percent`.
|
||
- **Minimum Home Assistant version**: pinned to `2025.1.0` in
|
||
`manifest.json`.
|
||
- **Manifest metadata** — `codeowners`, `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](https://github.com/pnbruckner/ha-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.
|