Entity._name_internal returns _attr_name before it ever consults
translation_key (homeassistant/helpers/entity.py:689). sensor.py and number.py
set both, so every entity.sensor.* and entity.number.* string added to
strings.json has been unreachable — the five sliders and five sensors rendered
English regardless of the user's language, bolted onto an integration that is
otherwise translated into 36. Dropping the three _attr_name assignments makes
the keys live; display_name was then a dead constructor parameter and goes too.
Two keys existed in strings.json but not translations/en.json (ambient_lux,
lux_reduction) and ramp_half_width was in neither, so a bare deletion would
have left three entities unnamed. Added them to both files.
ambient_lux carries unit lx and is textbook SensorDeviceClass.ILLUMINANCE; it
was inheriting the class-level _attr_device_class = None along with the four
curve outputs that genuinely have no equivalent. Without it the sensor loses
standard icon, unit handling and long-term-statistics grouping. Now a per-key
lookup, so the outputs keep their honest None.
The five number entities are behaviour knobs, not state — EntityCategory.CONFIG
moves them off the primary device page.
Both validate.yml and hassfest.yaml carried `schedule: cron "0 0 * * *"`, and
GitHub auto-disables any workflow with a schedule after 60 days of repository
inactivity. Both were taken out on 2026-09-08, 60 days after the last push. A
disabled workflow also stops answering push and pull_request, so this repo now
has no HACS or hassfest validation at all. Removing the cron is the durable
fix; re-enabling in the UI just restarts the same clock.
README claimed the tanh ramp has "a fixed 30-minute half-width" 60 lines above
documenting the live 5-120 min slider that replaced it.
164 tests pass, ruff clean.
* openspec: propose migrate-ci-to-phcc (proposal + design)
Design-first per repo convention. Migrates pytest + Docker CI off the dead HA core-checkout harness to the PHCC-based local test suite that already passes locally (164). Implementation (tasks + code) held pending review of the design's open questions.
* ci: migrate pytest + Docker off HA core-checkout to PHCC
Implements openspec change migrate-ci-to-phcc.
- pytest.yaml: run the local PHCC suite (latest + dev matrix; dev is
continue-on-error). Fixes the trigger (was push:[master] -> never ran on
main; now main). Drops coverage (was computed but never uploaded). Recipe
verified in a clean env locally: 164 passed, Python 3.13, latest PHCC.
- Delete dead core-checkout scaffolding: install_dependencies action,
setup-dependencies, setup-symlinks, update-test-matrix.{py,yaml},
test_dependencies.py, Dockerfile, docker-build.yml.
- setup-devcontainer: PHCC flow (uv sync --group test).
- tests/README.md: rewritten for 'uv run pytest'.
- CLAUDE.md: drop the 'Refresh test matrix' row.
- hacs.json 2024.12.0 -> 2026.1.0; README min-version line corrected (it
wrongly claimed '2025.1.0 pinned in manifest.json' - manifest pins none).
* openspec: mark migrate-ci-to-phcc 4.3 done (CI verified green)
- end-of-file-fixer: trim the double trailing newline on two openspec spec files so pre-commit passes (verified: pre-commit run --all-files is green).
- toc.yaml: add permissions.contents=write so the TOC generator's push to main stops 403-ing as github-actions[bot].
Does not touch the pytest/Docker core-checkout harness (PHCC migration) — that is a separate, design-level change.
The README What's-new callout and the CHANGELOG 2.1.0 entry still said four number entities, while the README table/intro and the runtime-range-controls spec say five (the four range bounds plus ramp_half_width). Update the callout to list all five and add a CHANGELOG entry for the fifth entity; leave the historical 2.1.0 'four' entry intact. Docs only -- code and spec already reflect five. Filed as openspec change fix-number-entity-count-docs.
- manifest.json: remove the 'homeassistant' key (not a valid manifest key;
the min HA version lives in hacs.json). Verified hassfest-clean locally.
- validate.yml / hassfest.yaml: trigger on push to main (default branch) too,
not only master, so CI actually runs.
This is the CDiT fork and is not in the HACS default list. Replace the
condensed install section with the canonical custom-repository steps,
add the not-in-default / use-upstream note, the same-domain warning, and
a dedicated manual-install subsection.
Fifth runtime number per profile (5-120 min, default 30 = the old
RAMP_HALF_WIDTH_SECONDS constant). No options-flow field — the entity is
the only knob, meant to be driven seasonally from Node-RED. Two-tier
restore (restored -> default; no options tier, which would reset the
width on every unrelated options save). The curve and the sun-event
day-anchoring read the width once per tick and share the same value, so
widened evening ramps complete past the next_* sensor flip.
8 new tests; 164 passing. Bump to 2.5.0-cdit.1.
sensor.sun_next_rising flips to tomorrow at sunrise; the old anchor only
pulled it back when >12h away. With short June nights tomorrow's sunrise
is within 12h by mid-afternoon, so from ~17:30 local until sunset the
pair described tomorrow and the curve returned minimum.
Replace the clock-distance heuristic with ordering-based anchoring in a
new pure helper anchor_sun_events() (color_and_brightness.py):
- daytime (sunrise > sunset): pull sunrise back one day, unconditionally
- stale "today's sunset" still on yesterday: push sunset forward one day
- post-sunset ramp tail (both flipped, still within half_width): pull
both back so the down-ramp completes instead of snapping to min
8 regression tests incl. the June-afternoon repro and a winter check.
Config:
- .ruff.toml target-version py310 -> py312, matching pyproject's
requires-python (>=3.12) and the 3.12 'type' aliases switch.py
already ships. Unblocks two false invalid-syntax errors.
- Ignore D102 in tests (test-class methods), consistent with the
existing D100/D103 test ignores.
Code (no behavior changes):
- COM812 trailing commas + UP017 dt.UTC via ruff --fix, black re-wrap
- RUF002: unicode minus/en-dash -> ASCII hyphen in docstrings
- SIM105: contextlib.suppress for the lux-reading parse in config_flow
- TRY300: move return out of try in _read_lux_sensor
- PLC0415: hoist inline asyncio/logging imports to module top
- E741: rename ambiguous 'l' comprehension variable to light_id
- PT006/PT018: parametrize tuple + split compound assertion
- D102: docstring for OptionsFlow.async_step_init
- ARG001/ARG002: noqa with justification on HA-required signatures
- PLR0912/PLR0915: noqa on prepare_adaptation_data and
_update_attrs_and_maybe_adapt_lights (upstream-inherited complexity;
splitting would hurt readability more than it helps)
./scripts/lint passes clean; 148 tests pass.
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.
Thread 2 (bug): runtime range number entities seeded from native_min on a
fresh profile (only a name stored at setup), so new groups ran at
max_brightness=1% and a 1000-1000K color-temp range until the options
dialog was saved once. Each RANGE_ENTITIES row now carries a sensible
DEFAULT_* and _options_value() falls back to it. Adds a regression test.
Thread 3: collapse 'Sun schedule' and 'Light control' by default
(now 2 open / 5 closed): Targets + Daytime curve expanded, the rest
collapsed.
Existing profiles unaffected (their options are already saved); only
newly-created groups get the corrected seed. Bump 2.3.0 -> 2.3.1-cdit.1.
The 'Lux reduction' sensor published the retained brightness factor, so it
read 100% when nothing was being reduced (0% actual reduction) — the label
and value were inverses. Now it publishes the actual reduction:
100 - round(factor*100), so 0% = no dimming, higher = more cut, None when
the gate is inactive.
Updates the output-sensors spec scenarios to match (71 -> 29, 100 -> 0,
adds the gate-inactive None case) and adds a publish-level value test
(none existed — the prior scenarios were never enforced in code).
Two config-flow bugs in the Ambient lux / Advanced sections:
- Conditional fields (target_lux, send_split_delay) only appeared on a
fresh re-open of the dialog, never in the same session — violating the
options-flow spec ('SHALL re-render ... in the same session'). Now, when
a driver is enabled but its dependent field was hidden from the rendered
schema, the form re-renders (carrying the user's edits) instead of saving.
- The options form could not be saved at all without selecting a lux
sensor: vol.Optional(CONF_LUX_SENSOR, default='') fed '' into the
illuminance EntitySelector, which rejects empty strings. Omit the
default (vol.UNDEFINED) when no sensor is configured.
Extracted _has_pending_reveal() and _overlay_range_values() helpers to
keep async_step_init under the branch limit. Added 3 flow-level tests
exercising the real re-render path (prior tests only hit the schema
builder, which is how these slipped through). 141 tests pass.
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.
Sensors are live on Tailscale HA, the change is complete end-to-end.
Moves the change to openspec/changes/archive/2026-05-21-add-output-sensors/
and promotes the delta spec to openspec/specs/output-sensors/spec.md
as a new capability (5 requirements, 13 scenarios).
The CDiT fork is single-household and was carrying an entire upstream
docs/ mkdocs site documenting features the fork has removed (sleep mode,
take-over-control, brightness_mode selector, YAML config). The README
mostly auto-generated from those pages via markdown-code-runner.
What's gone:
- docs/ — all 11 pages + assets + run_markdown_code_runner.py
- .github/workflows/docs.yml — zensical+shinylive GitHub Pages build
- .github/workflows/markdown-code-runner.yml — auto-edit of README from docs/
- .github/update-services.py / update-strings.py — would clobber the
hand-edited services.yaml / strings.json
- scripts/update-generated-content — orchestrator for the above
- custom_components/adaptive_lighting/_docs_helpers.py + docs_gen.py —
only used by the deleted markdown-code-runner
- zensical.toml — docs-site config
- "docs" dependency group in pyproject.toml (markdown-code-runner,
shinylive, zensical, etc.) + lock regenerated
What's new:
- README.md rewritten to describe the fork's actual surface — 3 switches,
4 number entities, 3 sensor entities per profile, 2 services (apply +
change_switch_settings), entry-only setup, UI tuning, sun source.
Preserves the existing "What's new in 2.1" / "2.2" block quotes.
- webapp/README.md annotated to flag the Shiny simulator models the
upstream curve (with brightness_mode, sleep mode, etc.) and does not
reflect the fork.
- CLAUDE.md command table no longer references update-generated-content.
Sensor.py + test_sensor_platform.py: incidental black reformat from the
lint pass (multi-arg function calls split per line).
Tests still pass (123/123). Lint clean. Sensors implementation
unchanged.
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.
Promotes the master switch's current_brightness, current_color_temp, and
sun_position attributes to first-class sensor entities with
SensorStateClass.MEASUREMENT so HA's recorder graphs them as numerics.
This is the explicit complement to the killed add-lovelace-card: stock
apexcharts-card / History panel becomes the charting story once values
live on graphable entities.
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 to the signal and read
from the cache. Single computation path; pure-reader sensors.
Naming: "Output brightness" / "Output color temp" disambiguate from
adapt-brightness switch and min/max number entities. "Sun position"
needs no prefix. sun_position is solar elevation in degrees (unit °)
sourced from the user's configured Sun2 / sensor.sun_* entity.
4 artifacts: proposal, design (8 decisions), spec (5 requirements, 13
scenarios), tasks (7 groups, 33 checkboxes). Strict-validate green.
Both fail the "will the maintainer actually use this?" test for a
single-household fork:
- house-mode-modes: state-driven switch flips are what Node-RED already
does in the CDiT stack. Pushing them into the integration competes
with Node-RED's purpose and adds HA-core-churn maintenance forever.
- add-lovelace-card: maintainer wouldn't use a custom Lit + TypeScript +
Vite + HACS plugin card. Stock tile + apexcharts cards in Lovelace
YAML cover the same need without a frontend ecosystem in a Python repo.
Integration scope stays: sun curve + runtime entities + options flow.
47/47 tasks complete, including live verification on production HA:
- 4 number entities × 6 profiles registered (42 AL entities total)
- Slider drag does not reload integration (entry.modified_at stable)
- Curve picks up new slider value on next recompute
- Options flow seeds from entity state, not entry.options
- Save snaps sliders to typed values via reload
- RestoreNumber persists slider position across HA restart
- Friendly names now read as "<profile> Brightness" / "Color" / etc.
Delta synced into canonical specs:
- options-flow MR4 (curve bound values come from entities)
- runtime-range-controls capability added (7 requirements)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
Task 9.4: GitHub repo description and topics set via `gh repo edit`.
Description: "CDiT-opinionated fork of basnijholt/adaptive-lighting —
sectioned config, entity-driven sun timing (Sun2-friendly), synthetic
tanh curve. Not a drop-in replacement; star upstream too." Topics:
home-assistant, hacs, adaptive-lighting, circadian-lighting, cdit,
opinionated-fork, custom-component, home-automation.
Archive: change moved to openspec/changes/archive/2026-05-16-cdit-
config-redesign/. The 9 ADDED Requirements from the delta were synced
into openspec/specs/options-flow/spec.md as the canonical capability
spec — this is the first long-lived spec in the repo.
Result: cdit-config-redesign is 53/53 complete, archived, validated,
synced. The three remaining active changes (add-lovelace-card,
add-runtime-range-controls, house-mode-modes) sit in the roadmap.
Marked 4.3 (manual UI test of OptionsFlowWithReload reload-on-save +
entity-ID preservation) as complete after end-to-end verification on
the real HA install at homeassistant.onca-blenny.ts.net:
- Created a fresh test profile via the new config flow
- Confirmed 3 switches (master + adapt_color + adapt_brightness, no
sleep) registered
- Opened the options flow — 6 sections render in the order specified
in spec R1
- Toggled include_config_in_attributes off → on, saved
- Entry stayed in `loaded` state, no restart prompt, all 3 entity
IDs preserved across the reload
- Field change landed on the master switch's attributes
Bonus: during the production run, also migrated all 6 existing AL
profiles from the upstream-shape entries (stuck in MIGRATION_ERROR
after our v1→v2 break) onto the new sectioned schema. 4/6 fully
migrated with their snapshotted config; 2/6 (dining_mvp,
ko_circadian_lights) saved with the lights that ARE currently
registered — `light.liv_lt_lights` and `light.hll_lt_main` are not
present in HA right now (offline or renamed).
The only task left in this change is 9.4 (gh repo description /
topics), which is a one-liner outside the code base.
Production HA caught this on the first save attempt: HA rejects
`config_entry.add_update_listener()` when the integration also uses
`OptionsFlowWithReload`, raising:
ValueError: Config entry update listeners should not be used with
OptionsFlowWithReload
The listener was a vestigial bit of the pre-redesign reload plumbing
that should have been deleted alongside the manual reload path (design
decision D6). Removed:
- `config_entry.add_update_listener(async_update_options)` registration
in `async_setup_entry`
- `async_update_options` helper (only existed to call `async_reload`)
- `UNDO_UPDATE_LISTENER` tracking in `async_unload_entry`
- The `UNDO_UPDATE_LISTENER` import (still defined in const.py for any
external code that imports it; pruning that is a separate cleanup)
Updated `tests/test_init.py::test_successful_setup_on_current_version`
to assert `entry.entry_id in hass.data[DOMAIN]` instead of the listener
key. All 94 tests still pass locally.
This is the first real-HA-only bug we've shipped — props to the
production deploy for catching it before merge.
Test infrastructure:
- Add `pytest-homeassistant-custom-component` (PHACC) as a `test`
dependency group. PHACC ships `hass`, `enable_custom_integrations`,
`MockConfigEntry`, and friends without needing to clone HA core as a
sibling directory. Modernizes the test setup from upstream's
`setup-symlinks` pattern.
- conftest.py: add `auto_enable_custom_integrations` autouse fixture
so HA discovers the integration under `custom_components/` during
tests. Keep the upstream template-deprecation no-op.
- Import paths: all tests now import from `custom_components.adaptive_lighting`
(not `homeassistant.components.adaptive_lighting`) and from
`pytest_homeassistant_custom_component.common` (not `tests.common`).
New tests (groups 7.2-7.16):
- tests/test_color_and_brightness.py (16 tests): TestBrightnessCurve
asserts min-before-sunrise, midpoint-at-event, max-during-day, sunset
ramp symmetry. TestColorTempCurve verifies the same shape applies to
K. TestSunPosition checks the synthetic +1/-1/0 derivation.
TestTanhDayCurveDirect exercises the helper directly.
- tests/test_config_flow.py (12 tests): six sections in order, each
section contains only its specified fields, conditional visibility
of send_split_delay, default sun entities, strict-typed entity
selectors, NumberSelector slider/box configs, BooleanSelector for
every flag, full user→create-entry flow, YAML-managed entry aborts
with `yaml_managed` reason, options flow renders the sectioned schema.
- tests/test_init.py (6 tests): successful setup on current version,
stale version raises ConfigEntryError via async_migrate_entry,
unload is clean, tombstone removes orphan sleep entity + logs INFO,
tombstone is idempotent, tombstone respects config_entry ownership.
Source modernizations driven by the tests:
- __init__.py: add `async_migrate_entry` that surfaces the
"incompatible — delete and recreate" message and sets the entry to
MIGRATION_ERROR. Removed direct `ConfigEntryError` from
`async_setup_entry` (HA routes version mismatches through the
migration handler now).
- switch.py: removed upstream's YAML-managed-entry auto-remove hack.
YAML profiles now load normally and the options flow handles the
"you must edit configuration.yaml" message (spec R7).
Existing tests updated to PHACC paths: test_adaptation_utils.py
(38 tests), test_hass_utils.py (22 tests). Both pass without
modification beyond the import fix.
Deleted: tests/test_switch.py (2,999 LOC of upstream tests, most
covering sleep mode / take-over-control / manual-control state
machines that no longer exist; CDiT-specific switch tests deferred
to a follow-up change).
Result: `uv run --group test pytest tests/` → 94 passed in 0.57s.
Deferred from this change:
- 4.3: manual UI test that toggling a field and saving reloads cleanly
(requires a real HA instance, can't be done from CLI).
- 9.4: GitHub repo description / topics update (do via `gh repo edit`
outside the change scope).
openspec status: 4/4 artifacts complete; strict-validate green.
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.
const.py:
- Drop 21 retired CONF_*/DEFAULT_* (sleep cluster, manual sun timing,
brightness curve variants, take-over-control cluster).
- Add CONF_SUNRISE_ENTITY / CONF_SUNSET_ENTITY (default
sensor.sun_next_rising / _setting).
- Add RAMP_HALF_WIDTH_SECONDS = 1800.
- Add CONFIG_ENTRY_VERSION = 2 (gate for strict version-break).
- Re-default DEFAULT_MIN_BRIGHTNESS 1→5, DEFAULT_MIN_COLOR_TEMP 2000→2200.
- Update ICON_MAIN / _BRIGHTNESS / _COLOR_TEMP to the CDiT picks.
manifest.json: bump to 2.0.0-cdit.1, pin homeassistant: 2025.1.0,
re-point codeowners/documentation/issue_tracker to the CaseyRo fork.
switch.py:
- Drop sleep_mode_switch creation in async_setup_entry; integration
now creates 3 switches per profile (master, adapt_color, adapt_brightness).
- Strip sleep-mode state machine from AdaptiveSwitch (sleep_mode_switch
attribute, sleep_transition, adapt_until_sleep, the state-change
listener, the _sleep_mode_switch_state_event_action method).
- Bridge-stub _take_over_control / _detect_non_ha_changes /
_adapt_only_on_bare_turn_on / _only_once / _auto_reset_manual_control_time
as class-level False/0 so Manager-side branches become dead code without
needing a full rewrite of AdaptiveLightingManager.
- Remove handle_set_manual_control service + its registration.
- Replace astral-driven curve init with the new SunLightSettings call
shape; add AdaptiveSwitch._today_sun_events() helper that reads the
configured sunrise/sunset entities.
- Set _attr_icon on AdaptiveSwitch.
color_and_brightness.py:
- Rewrite SunLightSettings as a pure curve-math wrapper (5 fields:
name + bounds + ramp half-width); methods take t_sunrise/t_sunset
as args, never reads HA state.
- Implement piecewise tanh ramp curve per spec R4 / design D11 in
_tanh_day_curve(). Both brightness and color-temp use the same shape.
- Drop SunEvents, sleep-mode branches, brightness_mode-switch, astral
dependency, force_rgb_color, lerp_color_hsv sleep-tinted color blending.
config_flow.py:
- Rewrite as sectioned schema (Targets / Daytime curve / Sun schedule /
Light control / Advanced / Diagnostics) via HA's section() helper.
- Native HA selectors throughout (NumberSelector, EntitySelector,
BooleanSelector). Strict typing on sun-event entity pickers.
- Conditional visibility for send_split_delay (driver:
separate_turn_on_commands).
- Extend OptionsFlowWithReload (with ImportError fallback for HA < 2025.1
dev environment); async_abort(reason="yaml_managed") for SOURCE_IMPORT.
- VERSION = CONFIG_ENTRY_VERSION.
__init__.py:
- Reject older config entries with ConfigEntryError ("recreate the entry")
per spec R8 / design D4.
- Add _remove_orphan_sleep_entities tombstone helper that scans the
entity registry for sleep-mode entities owned by this entry and
removes them on first setup. Idempotent and config_entry-scoped.
_docs_helpers.py: stub the removed DOCS_MANUAL_CONTROL / SET_MANUAL_CONTROL_SCHEMA
so the docs-generator script keeps importing.
Validation:
- ALL modules import cleanly under HA 2024.12.5 (dev env).
- openspec validate cdit-config-redesign --strict: green.
- ruff check --select=F: clean.
Remaining: groups 7 (16 tests), 8 (strings + plain-language pass), 9 (docs).
Three new checkboxes captured from the design-review thread:
- 1.6 better defaults (min_brightness 1→5, min_color_temp 2000→2200)
- 2.5 distinct mdi icons on each switch class
- 8.6 plain-language pass on every label, description, and error
Adds a 'polish' annotation tag for quality tasks that do not map
to a numbered requirement or design decision.
Forward-looking change that adds a single-profile Lovelace card
visualizing AL state — current brightness, color temperature,
24-hour curve, the three switches, the four range sliders, and an
optional house-mode badge. Card is additive: it consumes existing
entities and never replaces them.
Stack: Lit + TypeScript + Vite, bundled alongside the integration
via HACS. Visual direction: editorial-instrument — calm typography,
restrained color, the card warms after sunset.
Specs and tasks deferred until prerequisites land (cdit-config-
redesign for the 3-switch model and sun-entity sensors,
add-runtime-range-controls for the four number entities the
sliders bind to).
- openspec/ — three changes scoped:
• cdit-config-redesign: full artifact set (proposal + design + specs +
tasks), strict-validate green. Prunes 21 fields from the upstream
options flow, switches sun timing to entity-driven sources, hardcodes
a tanh curve, and breaks compat with upstream config entries.
• add-runtime-range-controls: proposal stub for promoting the 4
brightness/color-temp ranges to live number entities.
• house-mode-modes: proposal stub for per-AL house-mode behavior matrix
driving the runtime switches.
- .claude/ — opsx slash commands and openspec skill bundles for driving
the artifact-driven workflow.
- CLAUDE.md — fork orientation, remote topology, dev commands, and the
active change pointer.
* fix: reduce log verbosity for self-triggered off-to-on warning (#1433)
Move full event object dump from warning to debug level in
_off_to_on_state_event_is_from_turn_on() (switch.py:2717).
For lights with large effect_list attributes (e.g. Govee lights
with 130+ effects), the warning dumped the entire Event object
including both old_state and new_state, creating log entries
thousands of characters long.
The warning now logs only entity_id and context.id, while the
full event remains available at debug level for troubleshooting.
Fixes#1433
* fix: correct indentation for _LOGGER.debug block
* fix: correct indentation for _LOGGER.warning and _LOGGER.debug
* fix: remove unintended encoding corruption, keep only log level change
Reset switch.py to main and re-apply only the intended change:
move the full event object from warning to debug level in
_off_to_on_state_event_is_from_turn_on().
Addresses reviewer feedback about unintended Unicode corruption
(→ and ≈ characters were corrupted to mojibake).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Florian Horner <florianhorner@Mac.fritz.box>
Co-authored-by: Bas Nijholt <basnijholt@users.noreply.github.com>
Two issues prevented the script from running on macOS without manual intervention:
1. `sed -i` requires a backup suffix on macOS BSD sed. Replace with a
portable `grep -v | mv` idiom that works on both macOS and Linux.
2. `python` is not in PATH on macOS by default. Replace with `python3`.
Co-authored-by: Florian Horner <florianhorner@macbook-pro-von-florian.tail6f28f8.ts.net>
Co-authored-by: Bas Nijholt <basnijholt@users.noreply.github.com>