Reusable push-to-dim and multi-step dimming for multiple lights

It took me weeks of searching these forums to come up with a simple way to use a remote to turn on/off and dim a single light or multiple lights together. I hope others will benefit from my scripts here.

These scripts can be used without modification for as many lights/remotes as you want (e.g., you don’t need to make copies, rename them, or add more state), but if multiple remotes are operated simultaneously they will confuse each other.

There are two versions:

Version A. Provides push-and-hold-to-dim dimming for remotes that send out “button held down” and “button released” events.

It does the following:

  1. When the “button held down” event is received it records the time, sets all lights to brightness 0%, and starts a 6 second transition to 100%.

  2. When the “button released” event is received it calculates what percentage of the 6 seconds elapsed from the recorded “button held down” event time and sets the light brightness to that level.

This results in a smooth dimming up for any number of lights and stops at the point when the button was released.

This is implemented in two short scripts and uses input_number.dimming_time_start to store the start time. You call script.dimming_start on the “button held down” event and script.dimming_stop on the “button released” event. It allows you to control multiple lights at the same time via the parameter lights_to_control. You can use it for as many remotes/lights as you want without modification. It does not support dimming down, but starts at 0 each time.

Version B. Provides toggle and dimming control with remotes that send out a single “press” event.

It does the following:

  1. When the button is pressed it looks if the button was last pressed more than 2 seconds ago. If so, it just toggles the light.

  2. If the button was pressed less than 2 seconds ago, it sets the brightness to 33% on the first press.

  3. Subsequent presses within 2 seconds increase brightness by 33% each time.

This results in a simple “press it again quickly to adjust dimming” behavior with a default behavior of toggling on the initial press.

Version B’s implementation is a bit more complex because it needs more state. To use it you just call script.toggle_dim on the button press event with the list of lights in the lights_to_control parameter. The basic idea is that it stores the last time the button was pressed in input_number.dimming_time_start, as with Version A, but it also tracks the number of short presses in input_number.dimming_value, and behaves accordingly. It uses three helper scripts to allow a service_template to provide dynamic behavior, but you don’t need to do anything other than call the script on the button events.

Note that both of these scripts use a single global input_number to store the time. This means that if multiple switches use the scripts at the same time they will confuse each other. This is partially addressed in Version B by using input_text.dimming_last_entity to keep track of the last list of lights that was controlled. If it is different from the current one, the script will reset the timing. What this does it allows you to quickly toggle multiple lights without having it switch into dimming mode. (E.g., if you have two bedside lamps controlled by two remotes, you can press ‘off’ on each one right after each other and they will both turn off on the first press.)

Note that after you add the input_numbers and input_text to configuration.yaml you have to restart HA for them to show up.

Version A: Press-and-hold to dim, release to set brightness.

Add to configuration.yaml

input_number:
 dimming_time_start:
  name: Time dimming started
  initial: 0
  min: 0
  max: 2575824076
  step: 0.001

Add to scripts.yaml:


# This script saves the time when the dimming starts, turns the light off,
# and starts dimming it up over 6 seconds.
dimming_start:
 sequence:
  - service: input_number.set_value
    data_template:
     entity_id: input_number.dimming_time_start
     value: "{{now().timestamp()}}"
  - service: light.turn_off
    data_template:
     entity_id: "{{lights_to_control}}"
     transition: 0
  - service: light.turn_on
    data_template:
     entity_id: "{{lights_to_control}}"
     brightness: 255
     transition: 6
# When the dimming stops, this calculates the difference in time from when 
# the dimming started to when it stopped, and sets the brightness based on 
# the percentage change.
dimming_stop:
 sequence:
  - service: light.turn_on
    data_template:
     entity_id: "{{lights_to_control}}"
     brightness: "{{ [(now().timestamp()|float - states('input_number.dimming_time_start')|float)/6.0*255,255]|min|int}}"
     transition: 0

To use, call script.dimming_start on the button held down event and script.dimming_stop on the button released event. For example:


# Call script.dimming_start on the "button held down" event and pass in the lights to control
- alias: Wall switch dim start
  trigger:
   platform: event
   event_type: zwave.scene_activated
   event_data:
    entity_id: zwave.bedroom_wall_switch
    scene_id: 22
  action:
    - service: script.dimming_start
      data_template: 
        lights_to_control: light.bedroom_dresser_light, light.bedroom_reading_light_1, light.bedroom_reading_light_2

# Call script.dimming_stop on the "button released" event and pass in the lights to control
- alias: Wall switch dim stop
  trigger:
   platform: event
   event_type: zwave.scene_activated
   event_data:
    entity_id: zwave.bedroom_wall_switch
    scene_id: 23
  action:
    - service: script.dimming_stop
      data_template: 
        lights_to_control: light.bedroom_dresser_light, light.bedroom_reading_light_1, light.bedroom_reading_light_2

The above script will have the three lights (bedroom_dresser_light, light.bedroom_reading_light_1, and light.bedroom_reading_light_2) all dim together when the button is held down and stop dimming when it is released.

Version B: Press to toggle/dim.

Add to configuration.yaml:


input_number:
 dimming_value:
  name: Current Dimming Value
  initial: 0
  min: 0
  max: 255
  step: 1
 dimming_time_start:
  name: Time dimming started
  initial: 0
  min: -1000
  max: 2575824076
  step: 0.001
input_text:
  dimming_last_entity:
    name: "Name of the last entity used with the dimming script"
    initial: "None"

Add to scripts.yaml: (note that most of the code here is debug output that is commented out.)


toggle_dim_set_to_low_dim:
  sequence:
  - service: light.turn_on
    data_template:
      entity_id: "{{lights_to_control}}"
      brightness_pct: 34
      transition: 0

toggle_dim_increase_dim:
  sequence:
  - service: light.turn_on
    data_template:
      entity_id: "{{lights_to_control}}"
      brightness_step_pct: 34
      transition: 0

toggle_dim_do_nothing:
  sequence:
  - service: system_log.write
    data_template: 
      message: "toggle_dim_do_nothing: {{lights_to_control}}"
      level: info

# Dim control on multiple button press
# On first press after a long time toggle light
# On subsequent presses within 2 seconds, cycle through 33%, 66%, 100%
toggle_dim:
  sequence:
  # - service: system_log.write
  #   data_template: 
  #     message: "## toggle_dim time delta: {{now().timestamp()|int-states('input_number.dimming_time_start')|int}} dimming_value: {{states('input_number.dimming_value')|int}} lights: {{lights_to_control}} previous: {{states('input_text.dimming_last_entity')}}"
  #     level: warning
  # If this is for a different light to control, then set the previous time to 100 seconds ago to force a toggle
  - service: input_number.set_value
    data_template:
      entity_id: input_number.dimming_time_start
      value: >
        {% if states('input_text.dimming_last_entity')==lights_to_control %} 
          {{states('input_number.dimming_time_start')|int}}
        {% else %}
          {{states('input_number.dimming_time_start')|int-100}}
        {% endif %}
  # - service: system_log.write
  #   data_template: 
  #     message: >
  #       {% if states('input_text.dimming_last_entity')==lights_to_control %} 
  #         Same light to control as last time, so use the time since last press.
  #       {% else %}
  #         Different light to control, so reset the timing.
  #       {% endif %}
  #     level: warning
  # Remeber the lights to control so we know if they are the same next time
  - service: input_text.set_value
    data_template:
      entity_id: input_text.dimming_last_entity
      value: "{{lights_to_control}}"
  # Toggle the lights if the last button press was over 2 seconds ago
  - service_template: >
      {% if now().timestamp()|int-states('input_number.dimming_time_start')|int>2 %}
        light.toggle
      {% else %}
        script.toggle_dim_do_nothing
      {% endif %}
    data_template:
      entity_id: "{{lights_to_control}}"
  # - service: system_log.write
  #   data_template: 
  #     message: >
  #       {% if now().timestamp()|int-states('input_number.dimming_time_start')|int>2 %}
  #         More than 2 seconds since last call: just toggle.
  #       {% else %}
  #         Less than 2 seconds since last call: adjust.
  #       {% endif %}
  #     level: warning
  # Keep track of how many short presses we've had
  - service: input_number.set_value
    data_template:
      entity_id: input_number.dimming_value
      value: >
        {% if now().timestamp()|int-states('input_number.dimming_time_start')|int<=2 and states('input_number.dimming_value')|int==0%}
          1
        {% else %}
          {{states('input_number.dimming_value')|int}}
        {% endif %}
  # - service: system_log.write
  #   data_template: 
  #     message: "## Updated dimming_value, now: {{states('input_number.dimming_value')|int}}"
  #     level: warning
  # If we are on the first short press, then set the dimming to low
  - service_template: >
      {% if now().timestamp()|int-states('input_number.dimming_time_start')|int<=2 and states('input_number.dimming_value')|int==1 %}
        script.toggle_dim_set_to_low_dim
      {% else %}
        script.toggle_dim_do_nothing
      {% endif %}
    data_template:
      lights_to_control: "{{lights_to_control}}"
  # If we are on subsequent short presses, then increase the dimming
  - service_template: >
      {% if now().timestamp()|int-states('input_number.dimming_time_start')|int<=2 and states('input_number.dimming_value')|int>1 %}
        script.toggle_dim_increase_dim
      {% else %}
        script.toggle_dim_do_nothing
      {% endif %}
    data_template:
      lights_to_control: "{{lights_to_control}}"
  # Increment the dimming value if this was a short press to count them
  - service: input_number.set_value
    data_template:
      entity_id: input_number.dimming_value
      value: >
        {% if now().timestamp()|int-states('input_number.dimming_time_start')|int<=2 %}
          {{states('input_number.dimming_value')|int+1}}
        {% else %}
          0
        {% endif %}
  # - service: system_log.write
  #   data_template: 
  #     message: "## Updated dimming_value, now: {{states('input_number.dimming_value')|int}}"
  #     level: warning
  # Record the current button press time
  - service: input_number.set_value
    data_template:
      entity_id: input_number.dimming_time_start
      value: "{{now().timestamp()|int}}"  
  # - service: system_log.write
  #   data_template: 
  #     message: "## Updated time delta: {{now().timestamp()|int-states('input_number.dimming_time_start')|int}} and dimming_value: {{states('input_number.dimming_value')|int}}"
  #     level: warning

Note that most of the code above is commented out debugging code. I left it in so it makes it easier to modify.

To use it, just call script.toggle_dim on the event in automations.yaml and pass in the lights to control:

- alias: Bedside Reading Lamp 1 Remote
  trigger:
   platform: event
   event_type: deconz_event
   event_data:
    id: 'bedroom_remote_1'
    event: 1002 
  action:
    service: script.toggle_dim
    data_template: 
      lights_to_control: light.bedroom_reading_light_1

Enjoy!

-David

11 Likes

When using version A it works on a single light. But as soon as i add two or more lights it jumps from zero to full brightness in under one second (hue ambience light bulps)

What kind of group do you use? A light group oe a normal group? If it is a light group, did you do the grouping in HA or in the Hue app?

The lights I’ve been using are IKEA connected via deCONZ. Are your lights connected through the Hue bridge or directly to HA?

One thing to test is if you can try a simple automation that uses light.turn_on with a transition on the list of lights. If that works then this script should work. If that does not work, then I’m not sure what is going on.

Do you know that there is a service call available in deconz that allows smooth dimming?

Its at HA light group.
But i also tried with by entering two single bulps directly in the service call

Yes. But this is not through deconz

This was a reply to @dbs :slight_smile:

@Burningstone – I did not know that deconz supported smooth dimming itself. My goal was to keep everything in HA so it would work with whatever type of lights I have. (I have a mixture of zigbee and z-wave devices.) I assumed transitions are supported in everything in HA, so this should work with anything. However, it seems like transitions may not be supported by Hue lights, so that may be a bad assumption. I don’t know where to find documentation on that, unfortunately. Thanks for the tip.

Transition works fine for my Hue bulbs with Deconz. However you are right that not all lights support transition.