Light template, color temperature

I’m trying to create a light template as a virtual light that acts as a middle-man between Home Assistant and a real light. Later this will handle multiple real lights as well as modifying the inputs to provide some color calibration.

The problem I’m facing now is that the color temperature doesn’t seem to get stored (if that’s the right word) in the virtual light. After setting a color temperature on the virtual light, in Template editor:
state_attr('light.real_light', 'color_temp')
returns the color temperature I just set (in mirek), but
state_attr('light.virtual_light', 'color_temp')
returns None.

Is temperature_template now what I should be using? How do I store the color temperature in the virtual light?

My code looks like this:

- platform: template
  lights:
    virtual_light:
      friendly_name: "Test Light"
      value_template: "{{ is_state('light.real_light', 'on') }}"
      level_template: "{{ state_attr('light.real_light', 'brightness') }}"
      rgb_template: "{{ state_attr('light.real_light', 'rgb_color') }}"
      temperature_template: "{{ state_attr('light.real_light', 'color_temp') }}"
      turn_on:
        service: light.turn_on
        data_template:
          entity_id: light.real_light
      turn_off:
        service: light.turn_off
        data_template:
          entity_id: light.real_light
      set_level:
        service: light.turn_on
        data_template:
          entity_id: light.real_light
          brightness: "{{ brightness }}"
      set_temperature:
        service: light.turn_on
        data_template:
          entity_id: light.real_light
          color_temp:
            {{ color_temp }}
      set_rgb:
        service: light.turn_on
        data_template:
          entity_id: light.real_light
          rgb_color:
            ({{ r }} , {{ g }} , {{ b }})
1 Like

Your template for set_temperature: is missing its surrounding quotes, so the value being passed is nonsense. I think the one for set_rgb is also incorrect, but there are a few ways that are allowed…

      set_temperature:
        service: light.turn_on
        data_template:
          entity_id: light.real_light
          color_temp: "{{ color_temp }}"
      set_rgb:
        service: light.turn_on
        data_template:
          entity_id: light.real_light
          rgb_color: "{{ rgb }}"

Whoops, missed that one when changing things back to their simplest forms. Not that it matters, but it would’ve avoided this side track.

Surrounding quotes there don’t make any difference. The fact that the color temperature does get passed on to the real light kind of already proves it, but yeah, adding the quotes doesn’t change anything here. The problem is that the value can’t get returned back through the virtual light. Or in other words, the virtual light does accept color temperature values and it works, but the virtual light itself never has a color temperature.

Also I prefer having r, g, b separate, as that way I can modify them later after I’ve sorted out these issues first. And also there the quotes don’t matter, as rgb does in fact work perfectly. It gets passed on to the real light, and the values can get returned back through the virtual light.

What happens if you set a constant, here, e.g.
temperature_template: "{{ 2700 }}"

Is it reported back? If not, what is actually returned from state_attr('light.virtual_light', 'color_temp') ?

state_attr('light.virtual_light', 'color_temp') still returns None.
It doesn’t matter what I set here - getting the real_light temperature, or setting any value manually, it always returns None.

state_attr('light.real_light', 'color_temp') returns the temperature I set to virtual_light.

I also found this. These values are taken after I’ve set virtual_light to some color temperature, so note that I’m never controlling real_light directly, it all goes through virtual_light.

{% for attr, value in states.light.virtual_light.attributes.items() %}
{{ attr }}: {{ value }}{% endfor %}

{% for attr, value in states.light.real_light.attributes.items() %}
{{ attr }}: {{ value }}{% endfor %}

outputs

min_color_temp_kelvin: 2000
max_color_temp_kelvin: 6535
min_mireds: 153
max_mireds: 500
supported_color_modes: [<ColorMode.COLOR_TEMP: 'color_temp'>, <ColorMode.RGB: 'rgb'>]
color_mode: rgb
brightness: 255
color_temp_kelvin: None
color_temp: None
hs_color: (27.097, 48.627)
rgb_color: (255, 187, 131)
xy_color: (0.467, 0.377)
friendly_name: Test Light
supported_features: 0

min_color_temp_kelvin: 2000
max_color_temp_kelvin: 6535
min_mireds: 153
max_mireds: 500
effect_list: ['None', 'candle', 'fire', 'prism', 'sparkle', 'opal', 'glisten']
supported_color_modes: [<ColorMode.COLOR_TEMP: 'color_temp'>, <ColorMode.XY: 'xy'>]
effect: None
color_mode: color_temp
brightness: 255
color_temp_kelvin: 3333
color_temp: 300
hs_color: (27.355, 48.529)
rgb_color: (255, 187, 131)
xy_color: (0.467, 0.377)
mode: normal
dynamics: none
friendly_name: Real Light
supported_features: 44

Note first that even when setting a color temperature, the light will also calculate the corresponding RGB values and return those, even though it’s actually in color temperature mode.

Note also that real_light has color_mode: color_temp, but virtual_light has color_mode: rgb. This would explain why virtual_light doesn’t store any color_temp values and just returns None, because it just goes into RGB mode, even though real_light that it actually controls is properly set to color temperature mode.

How can I make virtual_light go into color temperature mode? It does even list color_temp as one of its supported_color_modes.

More findings. Removing rgb_template completely makes color temperature work correctly everywhere. So it appears that if the virtual light supports both RGB and color temp, then RGB mode will be prioritized.

I also have an alternative theory. Because the physical light will automatically update its RGB values to correspond with the color temperature set, maybe the virtual light’s rgb_template sees that as having to change itself into RGB mode, overwriting the color temp mode.

So the steps could be as follows:

  • User sets virtual_light’s color temperature.
  • virtual_light updates its color temperature, sets itself to color_temp mode, and updates real_light’s color temperature.
  • real_light updates its color temperature, sets itself to color_temp mode, and also updates its RGB values.
  • virtual_light notices that real_light updated its RGB values, so it updates its own RGB values and sets itself to RGB mode.

This happens even if real_light doesn’t need to update its RGB values, for example setting the same color temperature twice in a row, so I’m not really sure about what’s actually happening under the hood.


I am in the same situation as you. The color mode of the real light is ‘color_temp,’ and it needs to express the color temperature, but the virtual light retrieves the RGB color from the real light and returns it as color modes like ‘hs’ or ‘rgb.’ Therefore, the color mode of the virtual light is ‘rgb,’ which is why ‘color_temp’ and ‘color_temp_kelvin’ return null.

When configuring a template light, it is not possible to set the color mode of the virtual light to the value of the real light’s color mode.

The color temperature status of the virtual light is displayed as null, but fortunately, it can still be adjusted. This is quite inconvenient.

Thanks for posting this, I had the same issue. I found that the template would process the color_modes in the following precedence: rgb, hs, color_temp. If rgb_template had a value, it would always stay in rgb color_mode. If rgb_template had no value, but hs_template did, it would stay in hs color_mode and never change into color_temp.

I was able to work around the issue/bug, by wrapping the rgb_template and hs_template inside logic which would check the color_mode of the real light.

        rgb_template: > 
          {% if is_state_attr('light.real_light', 'color_mode', 'rgb') %}
            {{ state_attr('light.real_light', 'rgb_color') }}
          {% else %}
          {% endif %}
        hs_template: >
          {% if is_state_attr('light.real_light', 'color_mode', 'hs') %}
            {{ state_attr('light.real_light', 'hs_color') }}
          {% else %}
          {% endif %}
1 Like

Just wanted to say thank you for your solution! It works perfectly. I just stumbled upon this thread, because I was having the same issue.
Hopefully Home Assistant will provide a better solution in the future.

(backstory: I have an RGB+CCT light which I wanted to scale to the proper CCT range of the LED-strip with a template light. Zigbee LED-strip controllers always have a default CCT-range and this range unfortunately cannot be modified to the CCT-range of the LED-strip that is connected.)

1 Like

You’re welcome! I’m glad to help!