Normalizing dimmer values across lights in a room

I’m looking for a good way to control 5 separately controlled lights as one—with a twist…I want to normalize dimmer levels across all lights.

The end state would be a light group (perhaps fronted by a template) where a dimmer level of 1 would set each light to the lowest level at which that light is visibly on (LLV) and a dimmer level of 99 would set each light at to the highest level where it’s visibly dimmed (HLD).

I have a theoretical approach in mind, but no good ideas on how to implement it. Through testing I have determined the LLV and HLD for each light, which I can use in the formula below to determine the level at which to set each ilght for any given template level.

My question…what is a a somewhat reusable and elegant (or even inelegant) way to apply this formula to set the dimmer level of each light based on that light’s LLV and HLD?

Dimmer level transformation formula
LA = LLV - 1 + ( LT * ((HLD-LLV)/(99-1)) )
where:
La = actual level to set
LLV = lowest level at which the light is visible
HLD = highest level at which the light is visibly dimmer
LT = template level value

For reference: Observed LLVs and HDDs for the 5 lights in question

Light LLV HLD
Shower Lights 1 95
Chandelier 30 92
Sink Sconces 16 90
Vanity Sconces 16 90
Tub Lights 1 95

Internally HA stores brightness levels as a byte (values 0-255) so you will need to adjust your formula appropriately. Note: There is also a percentage brightness attribute (brightness_pct) but I am not going to use it.

Assuming the group of lights you use are always dimmed together, a super quick solution would be to pick one light in the group as the “master” light.

The master should be the light with the greatest range (in your example the first or last one).

You can then attach a simple automation to the master light, something like this:

mode: single
triggers:
  - trigger: state
    entity_id:
      - light.my_master_light
    attribute: brightness
conditions: []
variables:
  master_brightness: "{{ trigger.to_state.attributes.brightness }}"
  scaled_brightness: "{{ ((master_brightness - 30) / 180)  }}"
  normalized_brightness: "{{ min(max(scaled_brightness, 0.0), 1.0) }}"
actions:
  - repeat:
      for_each:
        - entity: light.sink
          min_level: 30
          scale: 200
        - entity: light.shower
          min_level: 20
          scale: 192
      sequence:
        - action: light.turn_on
          metadata: {}
          data:
            brightness: >-
              {{ repeat.item.min_level + (normalized_brightness * repeat.item.scale) }}
          target:
            entity_id: "{{ repeat.item.entity }}"

Hence I am using the variable block to:

  • Read the brightness from the master light.
  • Scale it into the range 0.0 - 1.0
  • Clamping it to ensure it doesn’t get outside the range I want.

Next I use a for_each loop to run through all the follower lights.
Each light has a min_level and a scale where:

max_level = min_level + scale

Finally connect your dimmer to the master light when you change the brightness of that the other lights should follow.

PS - This “solution” has a “feature” that the master light can be dimmed below it’s minimum brightness, you could add an if to the script either to prevent that or turn all lights off, however if you want to know that you have reached the bottom you may want to leave it as is, as the single light going out indicates you have reached the bottom…

Thanks. I’ll give this a go.