Device page sorts entities alphabetically by name, so 'Min/Max …' always
listed max above min ('a' < 'i'). Rename the four range numbers to
'Brightness lower/upper' and 'Color temp lower/upper' so each quantity's
lower bound sorts first. Pin suggested_object_id to the field key so new
profiles keep slugging number.<profile>_min_brightness etc., identical to
profiles created before the rename; existing entity_ids are registry-
preserved via unchanged unique_ids.
New-profile defaults: brightness 5-100% -> 10-90% (5% proved too dim on
gloomy days; 90% leaves manual-boost headroom), min color temp 2200K ->
2000K (deeper warm tone won in practice). Existing profiles unaffected —
saved options and restored slider values take precedence.
Specs synced: runtime-range-controls naming table + scenarios,
output-sensors collision references. Two new tests cover the slug pin
and the lower/upper friendly-name composition.
Optional per-profile lux sensor binding that dims lights when daylight
alone exceeds a user-set target (factor = target/current). Lights turn
off entirely below min_brightness. Two config fields, live lux reading
in the options flow, two conditional output sensors, sensor state
subscription with 5pp significance guard. 26/26 tasks, 138 tests green.
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.
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>
strings.json + translations/en.json:
- Rewritten from scratch with plain-language labels and one-sentence
framers per section (Targets / Daytime curve / Sun schedule / Light
control / Advanced / Diagnostics).
- Per-field `data_description` for every visible option in the options
flow.
- New translations for `yaml_managed` abort and the version-incompatible
error.
- Removed every key for the 21 dropped fields and the sleep switch.
- Services section updated for the trimmed surface: dropped
`set_manual_control` entirely, removed all sleep / take-over /
sunrise-sunset-time keys from `change_switch_settings`.
services.yaml: rewritten by hand (was auto-generated upstream). Now
matches the fork's actual service surface: `apply` and
`change_switch_settings` only, with native HA selectors and units.
README: added a CDiT preamble at the top covering the five core
differences from upstream, the strict-version-break warning, the
recommended Sun2 companion, and the minimum HA version pin. Crucially,
also added a "🙏 Huge thanks to the upstream team" block that names
@basnijholt and the 130+ upstream contributors, points users at the
upstream repo for the canonical install, and routes core-curve / light-
handling bugs to upstream's tracker. Open-source credit done right.
CHANGELOG.md: new file. Header credits upstream up front; v2.0.0-cdit.1
section lists every Added / Changed / Removed item by name, the
migration / upgrade steps in numbered form, internal refactors, and
known limitations (Manager bridge stubs, locale drift, astral as
transitive dep).
tasks.md: 8.1-8.6 and 9.1-9.3 marked complete; 9.4 (GitHub repo
description) deferred to a separate `gh repo edit` step.
openspec validate cdit-config-redesign --strict: green.
JSON + YAML syntax: validated.
Module import: clean.
## Summary
- fix hassfest validation by replacing raw options-description URLs with Home Assistant translation placeholders
- extend the pytest CI matrix to cover the latest patch release for each Home Assistant month, plus dev
- align CI/dev container Python versions and tests with newer Home Assistant behavior
## Validation
- GitHub Actions pytest matrix passed for 2024.12.5 through 2026.4.3 plus dev
- Docker passed for linux/amd64 and linux/arm64
- hassfest, HACS validation, pre-commit, pre-commit.ci, markdown-code-runner, docs build, and Release Drafter passed
## Summary
- Fixes regression in v1.30.0 where lights turned on by automations were incorrectly marked as "manually controlled"
- Makes `adapt_only_on_bare_turn_on` respect individual attribute tracking from #1356
## Root Cause
PR #1356 added a call to `update_manually_controlled_from_event()` in the `turn_on_off_event_listener.on()` handler for ALL `light.turn_on` events, including when turning a light on from OFF state.
When an automation turns on a light with brightness/color attributes, this incorrectly marked the light as "manually controlled", preventing Adaptive Lighting from adapting it.
## Fix
1. Only call `update_manually_controlled_from_event()` when the light was **already ON** before the turn_on event. Turning on from OFF is handled by `_respond_to_off_to_on_event()`.
2. Make `adapt_only_on_bare_turn_on` respect `take_over_control_mode`:
- With `PAUSE_CHANGED`: Only pause adaptation of specified attributes, continue adapting unspecified ones
- With `PAUSE_ALL`: Pause all adaptation (existing behavior)
## Expected Behavior After Fix
| Scenario | `adapt_only_on_bare_turn_on` | `take_over_control_mode` | Result |
|----------|------------------------------|--------------------------|--------|
| Turn on from OFF with brightness | `false` | Either | NOT manually controlled |
| Turn on from OFF with brightness | `true` | `PAUSE_ALL` | All adaptation paused |
| Turn on from OFF with brightness | `true` | `PAUSE_CHANGED` | Only brightness paused, color adapts |
| Turn on from OFF without attributes | Either | Either | NOT manually controlled |
| Change brightness while ON | Either | Either | Brightness manually controlled |
## Test plan
- [x] Turn on light via automation with brightness/color (`adapt_only_on_bare_turn_on=false`) - should adapt
- [x] Turn on light via scene (`adapt_only_on_bare_turn_on=true`, `PAUSE_ALL`) - should pause all adaptation
- [x] Turn on light with brightness only (`adapt_only_on_bare_turn_on=true`, `PAUSE_CHANGED`) - should adapt color
- [x] Both intercept=True and intercept=False paths tested for consistency
- [x] CI tests pass
Fixes#1378
Co-authored-by: Mario Guggenberger <mg@protyposis.net>
* refactor: introduce light control parameter enum
* refactor: replace manual control flag with parameter enum
* test: update deprecated color temp attribute
* build: set execution bits on task scripts
* feat: individual manual control of brightness and color
* test: add tests for individual manual control evaluation
* fix: sequential manual changes not always detected
If multiple attributes of a light were changed within an interval, only the last change was detected because the check in the interval only used the latest event. For example, if there was a brightness change and a following color change, only the color attribute was detected as manually controlled. To fix this, the manual control attribute flags are now set directly from the event handler so that all events are processed.
* fix: invalid service description
* docs: fix missing space in config description
* refactor: pluralize multivalued bitmask enum name
* feat: add option to duplicate existing lighting instance
A menu step in the config flow was added that allows a user to create a
new instance or duplicate the options of an existing one.
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* Add type annotation, tests, and translations for duplicate feature
- Add type annotation for source_options class attribute
- Add menu step translations to en.json
- Add tests for menu display, new instance creation, and duplication
* Simplify source_options access with class-level default
---------
Co-authored-by: Bas Nijholt <bas@nijho.lt>
* Fix trailing spaces in const.py: restore correct one, remove incorrect one
* Also remove trailing space from translations/en.json
* Also remove trailing space from strings.json
* Change the order of options in config flow
* Update README.md, strings.json, and services.yaml
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* Implement call intercept for multiple lights
* remove comment
* skip if no eids
* add comment
* fix type
* Fix skipped
* indentation
* Add logging and fix error
* Fix for HA ≤2023.04
* simplify
* remove unused ignores
* Debug mode
* Add test
* Make test failing
* rename switch
* rename lights
* Fix tests
* Rename lights in tests
* Remove unused dependencies
* Improve tests
* More tests
* Remove the DEBUG_MODE
* Add doc-string
* Extra test
* assert
* extra test
* Comments
* fix
* fix
* expand light groups
* more logging
* sort
* Revert is_proactively_adapting checks
This reverts commit 39fd8f2be0.
* simplify the mapping
* Revert "Revert is_proactively_adapting checks"
This reverts commit 18803e8e50.
* test
* no light groups
* do not expand
* Do not expand_light_groups in intercept
* more logging
* Fix
* add comment
* Add multi_light_intercept config option
* Update README.md, strings.json, and services.yaml
* add light group
* fix platform
* add simple test
* turn off again
* Test without take over control
* improve test and fix it in one way
* Fixes
* add cleanup fixture
* format
* Update test_switch.py
* add __str__
* remove unneeded call
* simplify service_data construction
* Generalize is_our_context
* Fix multi_light_intercept: false
* add comments
* add docs
* Update README.md, strings.json, and services.yaml
* Add feature line
* move function
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* Fixes in maybe_cancel_adjusting to possibly fix accidental turn on
* simplify logic in maybe_cancel_adjusting
* Add logging statements
* only control if turn_on called
* more logs
* add TODO
* Add _state_event_is_from_our_turn_on
* Ignore off->on state switches that are not accociated with light.turn_on
* improve logging
* rename
* Update docs
* Update README.md, strings.json, and services.yaml
* Add caution message to README
* Change order of emojis
* Update README.md, strings.json, and services.yaml
* Check that platform is not None
* log the call
* fix args
* Do not re-add already added configs
* Do not re-add already added configs
* Use async_remove
* remove unused code
* [pre-commit.ci] pre-commit autoupdate (#627)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.0.279 → v0.0.280](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.279...v0.0.280)
- [github.com/psf/black: 23.3.0 → 23.7.0](https://github.com/psf/black/compare/23.3.0...23.7.0)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Bas Nijholt <basnijholt@gmail.com>
* Extra logging statement
* Add to README
* log context_id
* return right indent
* move comment
* Skip on self.manager.is_proactively_adapting
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
* Cleanup after add_to_platform_abort is called, fixes#658
* Add note
* try-catch because of priv
* Catch all exceptions
* Bump to 1.17.3 in manifest.json
* assert that hass is not None
* Rename _light_event_action -> _light_state_event_action
* update .github/update-strings.py
* Update README.md, strings.json, and services.yaml
* update name
* Fixes
* Update README.md, strings.json, and services.yaml
* Add name
* Do not add name
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* Update switch.py
Continue to adapt color temperature down to the sleep temperature after sunset. Results in a gradually warming light during the night time rather than a fixed color temperature throughout the night time.
* Run pre-commit
* Merge branch 'master' into pr/87
* add config option bool `adapt_until_sleep` defaulting to `false`
---------
Co-authored-by: Bas Nijholt <bas@nijho.lt>
Co-authored-by: Bas Nijholt <basnijholt@gmail.com>
Co-authored-by: Benjamin Auquite <halomastar@gmail.com>
* Switch attributes now show the config settings.
`sunset_time`, `sunrise_time`, `max_sunrise_time`, and `min_sunset_time` show 'null' when not overridden - TODO
* fixed basnijholt's requested issues
* Run pre-commit
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* 'configuration' attr holds list of config options
returned the `=` from basnijholt's review.
* Small style changes
* Add include_config_in_attributes to en.json
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Bas Nijholt <bas@nijho.lt>