mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-27 20:34:20 +02:00
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.
4.5 KiB
4.5 KiB
1. Constants and config schema
- 1.1 Add
CONF_LUX_SENSOR/DEFAULT_LUX_SENSOR("") andCONF_TARGET_LUX/DEFAULT_TARGET_LUX(0) toconst.pywithDOCSentries [R: options-flow selectors, D4] - 1.2 Add both fields to
VALIDATION_TUPLES—lux_sensorascv.entity_id,target_luxasint_between(0, 10000)[R: options-flow selectors, D4] - 1.3 Add
ambient_luxandlux_reductionentries toOUTPUT_SENSORSinconst.py[R: output-sensors entity table, D7]
2. Pure lux-reduction math
- 2.1 Implement
lux_reduce(curve_brightness, target_lux, current_lux, min_brightness) → float | Noneincolor_and_brightness.py[R: lux-feedback pure function, D2, D6] - 2.2 Unit tests for
lux_reduce: above target, below target, exactly at target, below min_brightness → None, zero/negative current_lux → pass-through [R: lux-feedback pure function scenarios]
3. Config flow — Ambient lux section
- 3.1 Add
_lux_sensor_selector()factory returningEntitySelector(domain="sensor", device_class="illuminance")inconfig_flow.py[R: options-flow selectors, D4] - 3.2 Add
_target_lux_selector()factory returningNumberSelector(min=1, max=10000, step=10, unit="lx", mode=BOX)[R: options-flow selectors, D4] - 3.3 Build the "Ambient lux" section in
_build_options_schema— collapsed,lux_sensoralways shown,target_luxconditional onlux_sensorbeing non-empty (same pattern assend_split_delay) [R: options-flow sections, options-flow conditionals, D4] - 3.4 Read the lux sensor's current state in
async_step_initand pass it toasync_show_formviadescription_placeholders={"current_lux": lux_reading}[R: options-flow live reading, D5] - 3.5 Add section, field labels, and description (with
{current_lux}placeholder) tostrings.json[R: options-flow live reading, D5]
4. Switch adapt path — lux gate integration
- 4.1 In
switch.py_prepare_adaptation_data(or its caller), readlux_sensorstate fromself.hass.states.get(), calllux_reduce, and replacebrightness_pctinself._settingsbefore service-data assembly [R: lux-feedback reduce-only gate, D1, D2, D6] - 4.2 Handle
lux_reducereturningNone: sendlight.turn_offwithtransition, set per-light_lux_turned_offflag [R: lux-feedback auto-off, D3, D9] - 4.3 Handle lux-off recovery: when
lux_reducereturns non-Noneand_lux_turned_offis set, sendlight.turn_onwith adjusted brightness andinitial_transition, clear flag [R: lux-feedback auto-off recovery, D9] - 4.4 Register
async_track_state_change_eventonlux_sensorwhen configured, with 5pp significance guard; teardown inasync_will_remove_from_hass[R: lux-feedback sensor subscription, D8]
5. Output sensors — lux values
- 5.1 Publish
ambient_luxandlux_reductionto theoutputscache dict alongside existing keys on each curve tick [R: output-sensors ambient lux, output-sensors lux reduction, D7] - 5.2 Conditionally create
_ambient_luxand_lux_reductionsensor entities only whenlux_sensoris configured; clean up entities on reconfigure when sensor is removed [R: output-sensors conditional creation] - 5.3 Ensure both new sensors subscribe to
SIGNAL_OUTPUTS_UPDATEDvia the existing dispatcher pattern [R: output-sensors dispatcher pattern]
6. Strings and manifest
- 6.1 Add
entity.sensor.ambient_luxandentity.sensor.lux_reductionname entries tostrings.json[R: output-sensors entity table] - 6.2 Bump minor version in
manifest.json[D: non-breaking additive change]
7. Integration tests
- 7.1 Test: profile without lux sensor — curve brightness unchanged, no lux output sensors created [R: lux-feedback graceful degradation, output-sensors conditional]
- 7.2 Test: profile with lux sensor above target — brightness reduced by correct factor [R: lux-feedback reduce-only gate]
- 7.3 Test: lux drives brightness below min_brightness — light turns off, turns back on when lux drops [R: lux-feedback auto-off and recovery, D9]
- 7.4 Test: lux sensor becomes unavailable — falls back to curve brightness, warning logged once [R: lux-feedback graceful degradation]
- 7.5 Test: lux sensor state change triggers re-adaptation (crossing target threshold) [R: lux-feedback sensor subscription, D8]
- 7.6 Test: config flow shows live lux reading in description placeholder [R: options-flow live reading, D5]
- 7.7 Test: conditional
target_luxfield visibility in options flow [R: options-flow conditionals]