Skip to content

Automation Examples

Real-world automation examples showing how to integrate Adaptive Lighting with your Home Assistant setup.

Replace every entity ID below with the IDs from your Home Assistant instance. Fresh Adaptive Lighting profiles use child IDs such as switch.adaptive_lighting_living_room_sleep_mode; profiles created before the device-based entity change may retain older IDs.

Blocks that begin with - alias are entries for automations.yaml. Blocks with a top-level script: or adaptive_lighting: key are complete configuration.yaml examples. If your configuration uses script: !include scripts.yaml, omit that outer key and place its contents in scripts.yaml.

Five examples also have blueprints with selectors, so you can configure them without editing YAML:

Blueprint Purpose Import
Sleep mode Synchronize several profiles with one sleep-mode helper. Import blueprint
Minimum brightness Turn one light off when its target crosses down to the minimum. Import blueprint
Pause at minimum Pause brightness through manual control, using its existing reset behavior. Import blueprint
Schedule profile Apply brightness and color temperature from Schedule helper blocks. Import blueprint
Daylight limit Lower maximum brightness in strong daylight. Import blueprint

Click a blueprint's import badge, confirm the import in Home Assistant, then create an automation and select your entities. You can also copy its source link into Settings → Automations & scenes → Blueprints → Import Blueprint. Read the matching example below for setup and behavior. Each blueprint is tested through Home Assistant alongside its YAML example. The built-in manual-control timeout needs no automation; the scripts below remain useful as actions in your own automations.

change_switch_settings updates a profile while its main switch is off, but lights are adapted only while that switch is on. It preserves manual-control flags, so manually controlled lights remain paused.

Automatically reset manual control after one hour.

Use the built-in timeout so every new manual change renews a single timer for that light:

adaptive_lighting:
  - name: "Living Room"
    lights:
      - light.living_room
    autoreset_control_seconds: 3600

This is a top-level configuration.yaml example. The timer clears manual control and immediately readapts a light when both it and the Adaptive Lighting switch are on.

Toggle multiple Adaptive Lighting switches to "sleep mode" using an input_boolean.sleep_mode.

Also available as a blueprint. Select an input boolean and the sleep-mode switches it should control.

- alias: "Adaptive lighting: toggle 'sleep mode'"
  mode: restart
  trigger:
    - platform: state
      entity_id: input_boolean.sleep_mode
    - platform: homeassistant
      event: start  # apply the helper's restored state
  variables:
    sleep_mode: "{{ states('input_boolean.sleep_mode') }}"
  conditions:
    - condition: template
      value_template: "{{ sleep_mode in ['on', 'off'] }}"
  actions:
    - action: "switch.turn_{{ sleep_mode }}"
      target:
        entity_id:
          - switch.adaptive_lighting_living_room_sleep_mode
          - switch.adaptive_lighting_bedroom_sleep_mode
Turn a light off when its adaptive brightness target reaches the minimum.

Prefer a form over editing YAML? Import the blueprint in Home Assistant under Settings → Automations & scenes → Blueprints → Import Blueprint. Select your profile, its matching adapt brightness switch, one light managed by that profile, and its minimum brightness percentage. Create one automation per light. If you change the profile's minimum later, update the automation too. The blueprint and YAML example below have the same behavior.

The Adaptive Lighting switch already exposes its calculated brightness_pct target. Use its state changes to choose a power policy in an automation; no custom event is needed. This example assumes min_brightness: 1. Change minimum_pct to match your profile, and replace the switch and light entity IDs with your own.

The comparison uses the same rounded 0–255 brightness as an adaptation command. Comparing floating-point percentages for exact equality can miss the minimum between updates. This detects the calculated target reaching its minimum command, not the bulb finishing a transition or reaching its physical dimming limit.

- alias: "Adaptive lighting: turn off at minimum brightness"
  mode: single
  triggers:
    - trigger: state
      entity_id: switch.adaptive_lighting_living_room
      attribute: brightness_pct
  conditions:
    - condition: state
      entity_id:
        - switch.adaptive_lighting_living_room
        - switch.adaptive_lighting_living_room_adapt_brightness
      state: "on"
    - condition: template
      value_template: >-
        {% set minimum_pct = 1 %}
        {% set minimum = (minimum_pct * 255 / 100) | round(0) %}
        {% set before = trigger.from_state.attributes.get('brightness_pct')
                        if trigger.from_state else none %}
        {% set after = trigger.to_state.attributes.get('brightness_pct')
                       if trigger.to_state else none %}
        {{ is_number(before) and is_number(after)
           and (before | float * 255 / 100) | round(0) > minimum
           and (after | float * 255 / 100) | round(0) <= minimum }}
    - condition: state
      entity_id: light.living_room
      state: "on"
    - condition: template
      value_template: >-
        {{ 'light.living_room' not in
           (state_attr('switch.adaptive_lighting_living_room', 'manual_control') or []) }}
  actions:
    - action: light.turn_off
      target:
        entity_id: light.living_room

This runs once when a valid target crosses down into the minimum range. It skips lights currently marked as manually controlled, does not repeatedly turn them off while the target remains low, and does not turn them back on later. Startup or re-enabling the profile while already at the minimum is not a new crossing. Sleep mode can also cause a crossing if its brightness is at or below the chosen minimum. Changing sleep mode clears manual control by default; set reset_manual_control_on_sleep_mode_change: false if you want to preserve it. For a bedtime-only policy, trigger directly on the sleep-mode switch changing to on instead.

Pause brightness at the minimum using manual control.

Use the blueprint to mark an individual light's brightness as manually controlled when the calculated target reaches its minimum. The light stays on and the adaptation switches stay enabled. Set take_over_control_mode: pause_changed on the profile to keep adapting color; the default pause_all pauses both attributes.

Select the profile, its adapt-brightness switch, and a light managed by it. Match the minimum percentage to the profile's min_brightness. This YAML example assumes min_brightness: 1; change minimum_pct and the entity IDs to match your setup.

- alias: "Adaptive lighting: pause brightness at minimum"
  mode: single
  variables:
    minimum_pct: 1
    minimum: "{{ (minimum_pct * 255 / 100) | round(0) }}"
  triggers:
    - trigger: state
      entity_id: switch.adaptive_lighting_living_room
      attribute: brightness_pct
  conditions:
    - condition: state
      entity_id:
        - switch.adaptive_lighting_living_room
        - switch.adaptive_lighting_living_room_adapt_brightness
      state: "on"
    - condition: template
      value_template: >-
        {% set before = trigger.from_state.attributes.get('brightness_pct')
                        if trigger.from_state else none %}
        {% set after = trigger.to_state.attributes.get('brightness_pct')
                       if trigger.to_state else none %}
        {{ is_number(before) and is_number(after)
           and (before | float * 255 / 100) | round(0) > minimum
           and (after | float * 255 / 100) | round(0) <= minimum }}
    - condition: state
      entity_id: light.living_room
      state: "on"
    - condition: template
      value_template: >-
        {{ 'light.living_room' not in
           (state_attr('switch.adaptive_lighting_living_room', 'manual_control_brightness') or []) }}
  actions:
    - variables:
        light_session: "{{ states.light.living_room.last_changed.isoformat() }}"
        profile_session: "{{ states.switch.adaptive_lighting_living_room.last_changed.isoformat() }}"
        brightness_session: "{{ states.switch.adaptive_lighting_living_room_adapt_brightness.last_changed.isoformat() }}"
    - wait_template: >-
        {% set target = state_attr('switch.adaptive_lighting_living_room', 'brightness_pct') %}
        {{ not is_state('light.living_room', 'on')
           or not is_state('switch.adaptive_lighting_living_room', 'on')
           or not is_state('switch.adaptive_lighting_living_room_adapt_brightness', 'on')
           or states.light.living_room.last_changed.isoformat() != light_session
           or states.switch.adaptive_lighting_living_room.last_changed.isoformat() != profile_session
           or states.switch.adaptive_lighting_living_room_adapt_brightness.last_changed.isoformat() != brightness_session
           or not is_number(target) or (target | float * 255 / 100) | round(0) > minimum
           or 'light.living_room' in
               (state_attr('switch.adaptive_lighting_living_room', 'manual_control_brightness') or [])
           or (state_attr('light.living_room', 'brightness') | float(256)) <= minimum }}
      timeout: "00:05:00"
      continue_on_timeout: false
    - condition: template
      value_template: >-
        {% set target = state_attr('switch.adaptive_lighting_living_room', 'brightness_pct') %}
        {{ is_state('light.living_room', 'on')
           and is_state('switch.adaptive_lighting_living_room', 'on')
           and is_state('switch.adaptive_lighting_living_room_adapt_brightness', 'on')
           and states.light.living_room.last_changed.isoformat() == light_session
           and states.switch.adaptive_lighting_living_room.last_changed.isoformat() == profile_session
           and states.switch.adaptive_lighting_living_room_adapt_brightness.last_changed.isoformat() == brightness_session
           and is_number(target) and (target | float * 255 / 100) | round(0) <= minimum
           and (state_attr('light.living_room', 'brightness') | float(256)) <= minimum
           and 'light.living_room' not in
               (state_attr('switch.adaptive_lighting_living_room', 'manual_control_brightness') or []) }}
    - action: adaptive_lighting.set_manual_control
      data:
        entity_id: switch.adaptive_lighting_living_room
        lights: light.living_room
        manual_control: >-
          {{ true if 'light.living_room' in
             (state_attr('switch.adaptive_lighting_living_room', 'manual_control_color') or [])
             else 'brightness' }}

The comparison uses the rounded 0–255 target, so it does not depend on sampling an exact floating-point minimum. It waits up to five minutes for the light to report that minimum before marking manual control, so the final dimming command can complete. Reported brightness does not prove physical fade completion. If the light, profile, or adapt-brightness switch is toggled, the target rises, brightness is marked manually controlled elsewhere, or brightness never reaches the minimum, the attempt is abandoned. Lights that cannot report the configured minimum will not be paused. Existing manual color flags are preserved, and lights whose brightness is already manually controlled are left alone. Manual-control state is shared for lights managed by multiple profiles, so their existing takeover policies still apply.

The usual resets apply: turning the light off, the configured autoreset_control_seconds timeout, clearing manual control through its service, and existing profile/sleep-switch reset behavior. After a reset, normal adaptation can increase brightness again. This runs once per downward crossing; resetting while the target remains at its minimum does not immediately mark the light again. Startup at the minimum is not a crossing either.

This pauses further dimming as well as brightening. To pause brightness immediately after a brightness change made through Home Assistant, use take_over_control_mode: pause_changed with take_over_control: true; that needs no additional automation.

Set sunrise and sunset from an alarm.

Call this script from your alarm automation. It sets one Adaptive Lighting profile's sunrise to the current time and its sunset to 12 hours later on the local clock.

script:
  set_adaptive_lighting_alarm_times:
    alias: "Adaptive lighting: set times from alarm"
    variables:
      alarm_time: '{{ now().strftime("%H:%M:%S") }}'
    sequence:
      - action: adaptive_lighting.change_switch_settings
        data:
          entity_id: switch.adaptive_lighting_alarm_lights
          sunrise_time: "{{ alarm_time }}"
          sunset_time: >
            {{ (strptime(alarm_time, "%H:%M:%S") + timedelta(hours=12))
               .strftime("%H:%M:%S") }}
Use a Schedule helper as a step-based custom lighting profile.

Also available as a blueprint. Select the main profile switch and your Schedule helper.

Create a Schedule helper named Adaptive Lighting Profile. Add time blocks with Additional data like this:

brightness_pct: 20
color_temp_kelvin: 2500

Use different values for each block. The automation below applies the active block whenever the schedule state or its attributes change. Setting both brightness limits and both color temperature limits to the same value keeps each block at its setpoint. Outside a block, the configured Adaptive Lighting settings are restored.

- alias: "Adaptive lighting: apply scheduled profile"
  triggers:
    - trigger: state
      entity_id: schedule.adaptive_lighting_profile
    - trigger: homeassistant
      event: start
  actions:
    - choose:
        - conditions:
            - condition: state
              entity_id: schedule.adaptive_lighting_profile
              state: "on"
          sequence:
            - action: adaptive_lighting.change_switch_settings
              data:
                entity_id: switch.adaptive_lighting_living_room
                min_brightness: >
                  {{ state_attr('schedule.adaptive_lighting_profile', 'brightness_pct') | int(1) }}
                max_brightness: >
                  {{ state_attr('schedule.adaptive_lighting_profile', 'brightness_pct') | int(1) }}
                min_color_temp: >
                  {{ state_attr('schedule.adaptive_lighting_profile', 'color_temp_kelvin') | int(2000) }}
                max_color_temp: >
                  {{ state_attr('schedule.adaptive_lighting_profile', 'color_temp_kelvin') | int(2000) }}
      default:
        - action: adaptive_lighting.change_switch_settings
          data:
            entity_id: switch.adaptive_lighting_living_room
            use_defaults: configuration
  mode: restart

This creates step changes at block boundaries. It does not interpolate between schedule points. Runtime settings also reset when Home Assistant restarts, so the startup trigger reapplies the active block. The default branch restores every configured setting; restore only the four fields explicitly if other automations also change runtime settings.

Reduce daytime brightness when an illuminance sensor detects strong daylight.

Also available as a blueprint. Select the profile and sensor, then set the lux thresholds and brightness limits. The high lux threshold must exceed the low threshold; the blueprint does nothing if they are reversed or equal.

Keep a low configured min_brightness for late night and let an automation lower max_brightness while the room has ample daylight. Use a sensor that is not significantly affected by the controlled lights to avoid a feedback loop.

- alias: "Adaptive lighting: limit brightness in daylight"
  triggers:
    - trigger: numeric_state
      entity_id: sensor.living_room_illuminance
      above: 300
    - trigger: numeric_state
      entity_id: sensor.living_room_illuminance
      below: 200
    - trigger: homeassistant
      event: start
      id: startup
  actions:
    - if:
        - condition: trigger
          id: startup
      then:
        - wait_template: >
            {{ is_number(states('sensor.living_room_illuminance')) }}
          timeout: "00:05:00"
          continue_on_timeout: false
    - choose:
        - conditions:
            - condition: numeric_state
              entity_id: sensor.living_room_illuminance
              above: 300
          sequence:
            - action: adaptive_lighting.change_switch_settings
              data:
                entity_id: switch.adaptive_lighting_living_room
                max_brightness: 30
        - conditions:
            - condition: numeric_state
              entity_id: sensor.living_room_illuminance
              below: 200
          sequence:
            - action: adaptive_lighting.change_switch_settings
              data:
                entity_id: switch.adaptive_lighting_living_room
                max_brightness: 100
  mode: restart

The separate 200 and 300 lux thresholds add hysteresis. After a restart, the automation waits for a numeric sensor state before evaluating it. If the initial value is between the thresholds, Adaptive Lighting keeps its configured maximum. Replace 30 and 100 with your desired daytime limit and normal maximum.

min_brightness and max_brightness are the solar-midnight and daytime endpoints of the brightness curve. Setting min_brightness higher than max_brightness is supported and creates an inverted curve that is brighter at night and dimmer during the day. If you only want a daytime limit, keep the reduced maximum at or above the configured minimum.

Turn on Hue-controlled lights with the current Adaptive Lighting values.

For a Hue button exposed to Home Assistant, call this script from the button automation. It turns on the listed lights directly with the current Adaptive Lighting brightness and color.

script:
  living_room_adaptive_lighting:
    alias: "Living room: adaptive lighting"
    sequence:
      - action: adaptive_lighting.apply
        data:
          entity_id: switch.adaptive_lighting_living_room
          lights:
            - light.living_room_ceiling
            - light.living_room_table
          turn_on_lights: true
          transition: 0

This requires Home Assistant to receive the button event. The one-shot apply call works while the main Adaptive Lighting switch is off, turns on the listed lights, and applies values even if a light is marked as manually controlled. It leaves the profile switch and manual-control state unchanged.

Adaptive Lighting does not update scenes stored on the Hue Bridge, so scenes activated only inside Hue cannot use this script and retain Hue's operation when Home Assistant is unavailable.

Use a fixed RGB stage before sleep mode.

This script starts sleep mode with a fixed dim red color, waits 30 minutes, and then restores the configured Adaptive Lighting settings. The main profile switch and the light must already be on.

script:
  adaptive_lighting_bedtime:
    alias: "Adaptive lighting: bedtime"
    mode: restart
    sequence:
      - action: adaptive_lighting.change_switch_settings
        data:
          entity_id: switch.adaptive_lighting_bedroom
          sleep_rgb_or_color_temp: rgb_color
          sleep_rgb_color: [255, 56, 0]
          sleep_brightness: 20
      - action: switch.turn_on
        target:
          entity_id: switch.adaptive_lighting_bedroom_sleep_mode
      - delay: "00:30:00"
      - action: adaptive_lighting.change_switch_settings
        data:
          entity_id: switch.adaptive_lighting_bedroom
          use_defaults: configuration

The light must support RGB color. The first stage uses a fixed brightness rather than following the normal brightness curve. When sleep mode changes from off to on, the default reset_manual_control_on_sleep_mode_change: true returns manually controlled lights to Adaptive Lighting control so they receive the stage. If you disable that option, manually controlled lights remain paused. Restoring configuration defaults resets every runtime setting on this Adaptive Lighting switch, so restore only the sleep fields explicitly if other automations also change runtime settings.

Stopping this script or reloading scripts during the delay prevents the final action, leaving the runtime overrides active. To recover, call adaptive_lighting.change_switch_settings for the profile with use_defaults: configuration. A Home Assistant restart reloads the configured settings.

Run a fixed virtual day across midnight.

Fixed virtual sunrise and sunset times can cross midnight. This configuration ramps an indoor garden from its minimum at 16:00 to its maximum at 22:00, then back to its minimum at 04:00.

adaptive_lighting:
  - name: "Indoor Garden"
    lights:
      - light.indoor_garden
    sunrise_time: "16:00:00"
    sunset_time: "04:00:00"
    min_brightness: 10
    max_brightness: 100
    brightness_mode: linear
    brightness_mode_time_dark: 0
    brightness_mode_time_light: 21600  # 6 hours

Adaptive Lighting changes brightness and color while a light is on; it does not manage the light's power schedule. This separate automation turns the example light on and off:

- alias: "Indoor garden: power schedule"
  triggers:
    - trigger: time
      at: "16:00:00"
      id: turn_on
    - trigger: time
      at: "04:00:00"
      id: turn_off
    - trigger: homeassistant
      event: start
      id: startup
  actions:
    - choose:
        - conditions:
            - condition: trigger
              id: turn_on
          sequence:
            - action: light.turn_on
              target:
                entity_id: light.indoor_garden
        - conditions:
            - condition: trigger
              id: startup
            - condition: time
              after: "16:00:00"
              before: "04:00:00"
          sequence:
            - action: light.turn_on
              target:
                entity_id: light.indoor_garden
      default:
        - action: light.turn_off
          target:
            entity_id: light.indoor_garden

Use min_sunrise_time, max_sunrise_time, min_sunset_time, or max_sunset_time instead when you want to constrain astronomical sunrise or sunset to an earliest or latest time rather than replace it.

Tip

Have a useful automation? Share your automation examples by opening an issue or submitting a pull request to the README.