New Adaptive Lighting Integration

Update: I have now disabled the take_over_control in all rooms. So manual controls should not become active anymore unless I actively call the service in my automation which I don’t.

But for whatever reason the manual controls is getting activated again!!! WTF???

How can this be. I am honestly going crazy with this integration and I am about to delete it and go back to my manual automations.

image
This option means AL stops adapting the light if something turns on the light while the light is already on and AL is adapting it. This allows you to set the brightness/color and AL will no longer adapt it. The light has be turned off and back at which point AL will resume adapting it.

image
This means AL stops adapting the light if a source outside of HA turns on/adjusts the light i.e. a physical control or another platform which communicates directlt with the light. When the light reports a state change to HA, AL stops adapting it.

image
This allows you to automatically turn off manual control after xx seconds and AL will resume adapting it.

Are you using transition?? I gave up trying to use transition as it was always a nightmare for me.
Hypothesis: If the light has a built-in mechanism for transition delay (i.e. take 5 seconds to adjust to new brightness/color) and it reports intermediate settings (i.e. updates current brightness/color every second) then AL will see those intermediate states as a “something else is controlling the light” and will flip to manual mode.
My Zooz dimmer has settings for transition/fade and also only report the final state but even after considering all the factors, things were not working right for me.

If this were the case then AL would have somehow missed the “turned off” in which case the next AL update would turn the lights back on.

Thanks @dbrunt for the ideas and hints

Ok I have done some more investigation and testing:

When I turn on the light e.g. with my light switch which is most reliable for testing the following happens:

  1. automation fires lights.turn_on
  2. Lights in the room turn on (not adjusting)
  3. All lights show up under manual control
  4. I turn off the lights with the switch. lights.turn_off is fired
  5. Lights turn off
  6. Lights disappear under manual control

I also experimented with changing the adapt delay to compensate for any transition delay that the lights could have on their own (between 0 and 5). I also played with the transition in the AL settings between 0 and 2 to make sure that does not cause issues. Take over control is disabled.

But the result is always the same as outlined above.

So something must cause the the manual setting after the fact, but I have no clue what it could be besides AL itself.

Also the turn off of the manual control works when the lights are turned off, so there is no issue there.

Another update: I have gone thru the debug logs. One thing I found was this

[custom_components.adaptive_lighting.switch] Bathroom: Config mismatch: detect_non_ha_changes or adapt_only_on_bare_turn_on set to true requires take_over_control to be enabled. Adjusting config and continuing setup with take_over_control: true.

So that explains why the manual takeover still happened. I turned off also the “only bare turn on” setting to test and voila the lights no longer show as manual.

So one mystery solved. However I still don’t get what is causing the manual to take over in the first place.

I also found an interesting line in the logs

[custom_components.adaptive_lighting.switch] Detected an ‘off’ → ‘on’ event for ‘light.living_room_arc_lamp’ …, triggered by the adaptive_lighting integration itself, which should not happen. If you see this please submit an issue with your full logs at GitHub - basnijholt/adaptive-lighting: Adaptive Lighting custom component for Home Assistant

Actually I saw this post that I had overlooked before and gave it a try.

I modified my automations (motion and switches) to the adaptive lighting service instead of the lights turn on and with that it finally works!!

Also switched off the intercept.

Thanks so much!

Adaptive Lighting is working well on a number of lights I’m using, but for some WLED strips, I’m finding that the manual control kicks in unexpectedly and prevents further updates. The setup on these strips is a bit complex, but enacts the following flow:

  1. The lights configured in Adaptive Lighting are template lights.
  2. These template lights run a script for on/off/set level/set temperature commands.
  3. The script fires an event to send the necessary info to Node Red.
  4. Node Red takes the temperature, and derives two RGB values with a slight offset either side of the set temperature.
  5. Node Red formats the two RGB values into a JSON request direct to the WLED strip to apply the “Lake” effect with the primary and tertiary colours (the secondary colour is the background, so always remains black)

I know this is very convoluted, but it was the only way I found that could support adaptive lighting in conjunction with multiple colours being sent to a WLED effect - just using the native integration only allows a single colour/temperature, or a preset palette (which won’t work unless you create hundreds of palettes for each temp adaptive lighting might send).

The Home Assistant side of things is set up with the following YAML:

light:
  - platform: template
    lights:
      toms_bedhead_blob:
        value_template: >
          {% set state = states('light.toms_bedhead') == 'on' %}
          {% set effect = state_attr('light.toms_bedhead','effect') == 'Lake' %}
          {% if state and effect %}
            on
          {% else %}
            off
          {% endif %}
        level_template: "{{ state_attr('light.toms_bedhead','brightness') }}"
        temperature_template: "{{ states('input_number.toms_bedhead_temperature') }}"
        turn_on:
          service: script.wled_blob
          data:
            command: "turn_on"
            color_temp: "{{ color_temp | default( states('input_number.toms_bedhead_temperature') ) }}"
            brightness: "{{ brightness | default( state_attr('light.toms_bedhead','brightness') ) }}"
            ip_address: "192.168.0.86"
        turn_off:
          service: script.wled_blob
          data:
            command: "turn_off"
            ip_address: "192.168.0.86"
        set_level:
          service: script.wled_blob
          data:
            command: "set_level"
            brightness: "{{ brightness }}"
            ip_address: "192.168.0.86"
        set_temperature:
          - service: script.wled_blob
            data:
              command: "set_temperature"
              color_temp: "{{ color_temp }}"
              brightness: "{{ brightness }}"
              ip_address: "192.168.0.86"
          - service: input_number.set_value
            target:
              entity_id: input_number.toms_bedhead_temperature
            data:
              value: "{{ color_temp }}"
input_number:
  toms_bedhead_temperature:
    name: Toms Bedhead Temperature
    min: 153
    max: 500

script:
  wled_blob:
    alias: WLED Blob
    mode: parallel
    sequence:
    - event: node_red.wled_blob
      event_data:
        command: "{{ command }}"
        color_temp: "{{ color_temp | default( states('input_number.toms_bedhead_temperature') ) }}"
        brightness: "{{ brightness | default( state_attr('light.toms_bedhead','brightness') ) }}"
        ip_address: "{{ ip_address }}"

adaptive_lighting:
- name: Toms Bedhead Blob
  lights:
    - light.toms_bedhead_blob
  prefer_rgb_color: false
  separate_turn_on_commands: false
  interval: 5
  transition: 1
  sunrise_time: '08:00:00'
  sunset_time: '19:00:00'
  min_brightness: 25
  max_brightness: 100

The Node Red flow is as follows:

[{"id":"f7241b344eb53bfe","type":"inject","z":"45e2bb67.67d724","name":"Warmest","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"event_type\":\"node_red.wled_blob\",\"event\":{\"command\":\"set_temperature\",\"color_temp\":500,\"brightness\":\"\",\"ip_address\":\"192.168.0.86\"},\"origin\":\"LOCAL\",\"time_fired\":\"2024-02-19T12:00:53.392888+00:00\",\"context\":{\"id\":\"01HQ0KV3KZF0VWQJ003AXKCN8Y\",\"parent_id\":null,\"user_id\":\"52e86cd98fc0420ebbd8301a6df6a7cb\"}}","payloadType":"json","x":220,"y":800,"wires":[["d8bb1a6807c0aac4"]]},{"id":"d8bb1a6807c0aac4","type":"change","z":"45e2bb67.67d724","name":"","rules":[],"action":"","property":"","from":"","to":"","reg":false,"x":355,"y":820,"wires":[["0e9fa73d268c4e10"]],"l":false},{"id":"719afc65e19e1183","type":"server-events","z":"45e2bb67.67d724","name":"","server":"fbad561e431e2711","version":3,"exposeAsEntityConfig":"","eventType":"node_red.wled_blob","eventData":"","waitForRunning":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"$outputData(\"eventData\").event_type","valueType":"jsonata"}],"x":160,"y":760,"wires":[["d8bb1a6807c0aac4"]]},{"id":"7e9f7e1f58848014","type":"inject","z":"45e2bb67.67d724","name":"Coolest","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"event_type\":\"node_red.wled_blob\",\"event\":{\"command\":\"set_temperature\",\"color_temp\":153,\"brightness\":\"\",\"ip_address\":\"192.168.0.86\"},\"origin\":\"LOCAL\",\"time_fired\":\"2024-02-19T12:02:00.763243+00:00\",\"context\":{\"id\":\"01HQ0KX5DA7PNMG5YV4F5BZ9BF\",\"parent_id\":null,\"user_id\":\"52e86cd98fc0420ebbd8301a6df6a7cb\"}}","payloadType":"json","x":230,"y":880,"wires":[["d8bb1a6807c0aac4"]]},{"id":"5b35354b6183af36","type":"inject","z":"45e2bb67.67d724","name":"Medium","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"event_type\":\"node_red.wled_blob\",\"event\":{\"command\":\"set_temperature\",\"color_temp\":232,\"brightness\":\"\",\"ip_address\":\"192.168.0.86\"},\"origin\":\"LOCAL\",\"time_fired\":\"2024-02-19T12:02:33.707331+00:00\",\"context\":{\"id\":\"01HQ0KY5JR77FJN9QV3PPBMV68\",\"parent_id\":null,\"user_id\":\"52e86cd98fc0420ebbd8301a6df6a7cb\"}}","payloadType":"json","x":220,"y":840,"wires":[["d8bb1a6807c0aac4"]]},{"id":"8e46774499e80e01","type":"change","z":"45e2bb67.67d724","name":"Preserve Event","rules":[{"t":"move","p":"payload.event","pt":"msg","to":"bloblight","tot":"msg"},{"t":"move","p":"bloblight.color_temp","pt":"msg","to":"bloblight.mireds","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"bloblight.mireds","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":840,"wires":[["ca27dc1f9a7f0e2f"]]},{"id":"0e9fa73d268c4e10","type":"change","z":"45e2bb67.67d724","name":"Split Temperatures","rules":[{"t":"set","p":"payload.event.differential","pt":"msg","to":"75","tot":"num"},{"t":"set","p":"payload.event.color_temp","pt":"msg","to":"[payload.event.color_temp - payload.event.differential, payload.event.color_temp, payload.event.color_temp + payload.event.differential]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":800,"wires":[["8e46774499e80e01"]]},{"id":"ca27dc1f9a7f0e2f","type":"split","z":"45e2bb67.67d724","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":710,"y":760,"wires":[["372589c0c67a4356"]]},{"id":"372589c0c67a4356","type":"change","z":"45e2bb67.67d724","name":"Convert M to K","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t \"temperature\": $round(1000000 / payload, 0)\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":740,"y":800,"wires":[["4105e48b25664024"]]},{"id":"4105e48b25664024","type":"node-red-contrib-colorspace","z":"45e2bb67.67d724","name":"","target":"payload","x":740,"y":840,"wires":[["9a41d8a72dc3263b","e1fdaf93de86a60f"]]},{"id":"9a41d8a72dc3263b","type":"change","z":"45e2bb67.67d724","name":"Preserve RGB","rules":[{"t":"set","p":"payload","pt":"msg","to":"[payload.rgb.red,payload.rgb.green,payload.rgb.blue]","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":740,"y":880,"wires":[["3cfacb24b9edfce2"]]},{"id":"3cfacb24b9edfce2","type":"join","z":"45e2bb67.67d724","name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":950,"y":780,"wires":[["d193803e0b4f6ade"]]},{"id":"7ba15f8a6e6949e8","type":"http request","z":"45e2bb67.67d724","name":"POST JSON","method":"POST","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":970,"y":860,"wires":[["c5de333fdb5cca11"]]},{"id":"d193803e0b4f6ade","type":"change","z":"45e2bb67.67d724","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"bloblight.ip_address & \"/json/state\"","tot":"jsonata"},{"t":"move","p":"payload","pt":"msg","to":"bloblight.rgb_array","tot":"msg"},{"t":"set","p":"bloblight.rgb_array[1]","pt":"msg","to":"[0,0,0]","tot":"json"},{"t":"set","p":"payload","pt":"msg","to":"{\t       \"on\": bloblight.command != \"turn_off\",\t       \"bri\": bloblight.brightness,\t       \"transition\": 7,\t       \"seg\": [\t           {\t               \"on\": true,\t               \"bri\": 255,\t               \"col\": bloblight.rgb_array,\t               \"fx\": 75,\t               \"fxdef\":true,\t               \"pal\": 5,\t               \"sx\": 45,\t               \"mi\": false,\t               \"rev\": false\t           }        \t       ]    \t   }\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":980,"y":820,"wires":[["7ba15f8a6e6949e8"]]},{"id":"fbad561e431e2711","type":"server","name":"New Home Assistant","version":5,"addon":false,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

A sample of the adaptive lighting and wled logs follow, but I couldn’t find the correct logging to get the template lights to also appear, which I think might be most useful to understand what’s making the change that triggers manual control:

2024-05-17 20:37:26.843 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Toms Bedhead Blob: '_update_attrs_and_maybe_adapt_lights' called with context.id='01HY321JDV:al:KRXW:ntrv:7E' lights: 'None', transition: '1.0', force: 'False'
2024-05-17 20:37:26.844 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Toms Bedhead Blob: filtered_lights: '[]'
2024-05-17 20:37:29.272 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] (0) _service_interceptor_turn_on_handler: call.context.id='01HY321MSPNQW6VE2DPYQW4TMG', is_skipped_hash='False'
2024-05-17 20:37:29.272 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] (1) _service_interceptor_turn_on_handler: call='<ServiceCall light.turn_on (c:01HY321MSPNQW6VE2DPYQW4TMG): entity_id=['light.toms_bedhead_blob'], params=>', service_data='{'entity_id': ['light.toms_bedhead_blob'], 'params': {}}'
2024-05-17 20:37:29.274 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] (2) _service_interceptor_turn_on_handler: switch_to_eids='{'Adaptive Lighting: Toms Bedhead Blob': ['light.toms_bedhead_blob']}', skipped='[]'
2024-05-17 20:37:29.275 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] (3) _service_interceptor_turn_on_handler: intercepting entity_ids='['light.toms_bedhead_blob']'
2024-05-17 20:37:29.276 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Intercepted TURN_ON call with data {'params': {}, 'entity_id': ['light.toms_bedhead_blob']} (01HY321MSPNQW6VE2DPYQW4TMG)
2024-05-17 20:37:29.281 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Toms Bedhead Blob: Setting color_temp of light light.toms_bedhead_blob
2024-05-17 20:37:29.282 DEBUG (MainThread) [custom_components.adaptive_lighting.adaptation_utils] Preparing adaptation data for light.toms_bedhead_blob with service data {'entity_id': 'light.toms_bedhead_blob', 'brightness': 171, 'color_temp_kelvin': 2000}
2024-05-17 20:37:29.282 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Detected an 'light.turn_on('['light.toms_bedhead_blob']')' event with context.id='01HY321MSPNQW6VE2DPYQW4TMG'
2024-05-17 20:37:29.283 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Toms Bedhead Blob: execute_cancellable_adaptation_calls with data: AdaptationData(entity_id=light.toms_bedhead_blob, context_id=01HY321MT1:al:KRXW:dpt_:7F, sleep_time=0.0, force=False, max_length=1, which=both, initial_sleep=True)
2024-05-17 20:37:29.283 INFO (MainThread) [homeassistant.helpers.script.toms_bedhead_blob] toms_bedhead_blob: Running template script
2024-05-17 20:37:29.284 INFO (MainThread) [homeassistant.helpers.script.toms_bedhead_blob] toms_bedhead_blob: Executing step call service
2024-05-17 20:37:29.292 INFO (MainThread) [homeassistant.components.script.wled_blob] WLED Blob: Running script sequence
2024-05-17 20:37:29.292 INFO (MainThread) [homeassistant.components.script.wled_blob] WLED Blob: Executing step node_red.wled_blob
2024-05-17 20:37:29.312 INFO (MainThread) [homeassistant.helpers.script.toms_bedhead_blob] toms_bedhead_blob: Executing step call service
2024-05-17 20:37:29.365 DEBUG (MainThread) [homeassistant.components.wled] Manually updated wled data
2024-05-17 20:37:29.389 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Detected a 'light.toms_bedhead_blob' 'state_changed' event: '{'min_color_temp_kelvin': 2000, 'max_color_temp_kelvin': 6535, 'min_mireds': 153, 'max_mireds': 500, 'supported_color_modes': [<ColorMode.COLOR_TEMP: 'color_temp'>], 'color_mode': <ColorMode.COLOR_TEMP: 'color_temp'>, 'brightness': 171, 'color_temp_kelvin': 2000, 'color_temp': 500, 'hs_color': (30.601, 94.547), 'rgb_color': (255, 136, 13), 'xy_color': (0.599, 0.382), 'friendly_name': 'toms_bedhead_blob', 'supported_features': <LightEntityFeature: 0>}' with context.id='01HY321MWR3VXD8G8BEX0R0GAK'
2024-05-17 20:37:29.390 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Detected an 'off' → 'on' event for 'light.toms_bedhead_blob' with context.id='01HY321MWR3VXD8G8BEX0R0GAK'
2024-05-17 20:37:29.390 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] is_proactively_adapting_context='False', context_id='01HY321MWR3VXD8G8BEX0R0GAK'
2024-05-17 20:37:29.390 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] just_turned_off: delta_time='36.866754' > delay='5'
2024-05-17 20:37:29.390 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] is_proactively_adapting_context='False', context_id='01HY321MWR3VXD8G8BEX0R0GAK'
2024-05-17 20:37:29.390 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Toms Bedhead Blob: Ignoring 'off' → 'on' event for 'light.toms_bedhead_blob' with context.id='01HY321MWR3VXD8G8BEX0R0GAK' because 'light.turn_on' was not called by HA and 'detect_non_ha_changes' is False
2024-05-17 20:37:29.390 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Marking 'light.toms_bedhead_blob' as manually controlled.
2024-05-17 20:37:32.344 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Toms Bedhead Blob: '_update_attrs_and_maybe_adapt_lights' called with context.id='01HY321QSR:al:KRXW:ntrv:7G' lights: 'None', transition: '1.0', force: 'False'
2024-05-17 20:37:32.348 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Toms Bedhead Blob: filtered_lights: '['light.toms_bedhead_blob']'
2024-05-17 20:37:32.349 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] Toms Bedhead Blob: 'light.toms_bedhead_blob' is being manually controlled, stop adapting, context.id=01HY321QSR:al:KRXW:ntrv:7G.
2024-05-17 20:37:34.147 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] asfsdf: '_update_attrs_and_maybe_adapt_lights' called with context.id='01HY321SJ3:al:MFZW:ntrv:0G' lights: 'None', transition: '45', force: 'False'
2024-05-17 20:37:34.155 DEBUG (MainThread) [custom_components.adaptive_lighting.switch] asfsdf: filtered_lights: '[]'

I’d really appreciate any assistance in preventing the manual control from triggering unexpectedly.

EDIT: Tried listening to call_service events, but could only see single turn_on calls on the blob light at an interval matching that configured in adaptive lighting, so everything seems to be okay there.
Also tried configuring adaptive lighting using the light entity from the WLED integration rather than my template entity. It worked as expected without manual mode kicking in for seemingly no reason.
Finaly, tried putting my another light (LIFX) that’s currently working fine on adaptive light behind a template. Even through the template, the manual control works properly.