Light.turn_on with template data

Hello everyone, I’m trying to create a generic script that allows me to manage my outdoor lights which can be activated or not with a parameter (Automate Gazebo #1 and/or #2 for example). This generic procedure will receive optional information concerning the desired state of the light (Brightness, Color Temp, Color Name…). A problem occurs when I want to build the data block that will be sent to light.turn_on. I’ve tried different ways of sending the information, but I still can’t do it.

Maybe it’s not possible? What do you think?

Template

{% set var_tmp_light_data = [] %}
{% set var_brightness_pct = 60 %}
{% set var_color_temp = 0 %}
{% set var_color_name = "red" %}
  {% if var_brightness_pct %}
    {# {% set var_tmp_light_data = var_tmp_light_data + [ "brightness_pct = " + var_brightness_pct|string ] %}   #}
    {% set var_tmp_light_data = var_tmp_light_data + [ dict(brightness_pct = var_brightness_pct) ] %}  
  {% endif -%}
  {% if var_color_temp %}
    {# {% set var_tmp_light_data = var_tmp_light_data + [ "color_temp = " + var_color_temp|string ] %}   #}
    {% set var_tmp_light_data = var_tmp_light_data + [ dict(color_temp = var_color_temp) ] %}  
  {% elif var_color_name %}
    {# {% set var_tmp_light_data = var_tmp_light_data + [ "color_name = " + var_color_name|string ] %}   #}
    {% set var_tmp_light_data = var_tmp_light_data + [ dict(color_name = var_color_name) ] %}
  {% endif -%}
  {{ var_tmp_light_data }}

Output
[{'brightness_pct': 60}, {'color_name': 'red'}]

Action

action: light.turn_on
target:
  entity_id: light.gazebo_1
data: |
  {% set var_brightness_pct = 60 %}
  {% set var_color_temp = 0 %}
  {% set var_color_name = "red" %}
  
  {% set var_tmp_light_data = [] %}  
  {% if var_brightness_pct %}
    {# {% set var_tmp_light_data = var_tmp_light_data + [ "brightness_pct = " + var_brightness_pct|string ] %}   #}
    {% set var_tmp_light_data = var_tmp_light_data + [ dict(brightness_pct = var_brightness_pct) ] %}  
  {% endif -%}
  {% if var_color_temp %}
    {# {% set var_tmp_light_data = var_tmp_light_data + [ "color_temp = " + var_color_temp|string ] %}   #}
    {% set var_tmp_light_data = var_tmp_light_data + [ dict(color_temp = var_color_temp) ] %}  
  {% elif var_color_name %}
    {# {% set var_tmp_light_data = var_tmp_light_data + [ "color_name = " + var_color_name|string ] %}   #}
    {% set var_tmp_light_data = var_tmp_light_data + [ dict(color_name = var_color_name) ] %}
  {% endif -%}
  {{ var_tmp_light_data }}

Error
Failed to perform the action light.turn_on. Error rendering data template: Result is not a Dictionary

I think the dictionary is incorrect, I believe it should be more like this:

{'brightness_pct': 60, 'color_name': 'red'}

What you are passing would be treated like a list in the data, which works for some things (like sending multiple entity ID’s for example) but I don’t think it would work for a single entity command.

I got this to work. Not sure if it’s the most elegant solution, but it’s what I was able to come up with:

action: light.turn_on
target:
  entity_id: light.kitchen_lights
data: >
  {% set var_brightness_pct = 60 %}
  {% set var_color_temp = 0 %}
  {% set var_color_name = "blue" %}
  {% set ns = namespace(var_tmp_light_data = {}) %}
  {% if var_brightness_pct %}  
    {% set ns.var_tmp_light_data = dict(ns.var_tmp_light_data, **{'brightness_pct' : var_brightness_pct}) %}  
  {% endif -%}
  {% if var_color_temp %}
    {% set ns.var_tmp_light_data = dict(ns.var_tmp_light_data, **{'color_temp' : var_color_temp}) %}  
  {% endif -%}
  {% if var_color_name %}
    {% set ns.var_tmp_light_data = dict(ns.var_tmp_light_data, **{'color_name' : var_color_name}) %}  
  {% endif -%}
  {{ ns.var_tmp_light_data }}
1 Like

Even if your code isn’t what someone else would do, the fact that it works is the only thing that matters.

You could also assemble the JSON/DICT like this if you wanted:

{{
  {
    'brightness_pct': var_brightness_pct,
    'color_temp': var_color_temp
  }
}}

Thanks for your help. If there’s a cleaner solution, I’m interested. Often, a solution grows with the need and we no longer see the easiest one.

What you have is clean enough, any cleaning would frankly be fairly inconsequential. So long as YOU can read it then you’re probably fine.

Although, looking at your code, you are defining the brightness and color code, so testing if they are set isn’t doing anything at all since there is never a time they are not set. That’s minor and doesn’t cause problems really, just an observation.

The piece of code is minimal and only for testing the solution. The problem is that we can’t set var_color_temp at the same time as var_color_name, even if one of the two is null.

At first, I thought I’d just set the value to null, but the light.turn_on action doesn’t like it.

action: light.turn_on
target:
  entity_id: light.gazebo_1
data:
  color_temp:
  color_name: 'red'

Error
Failed to perform the action light.turn_on. two or more values in the same group of exclusion ‘Color descriptors’ @ data[]. Got None

That will be my solution, thanks for your help.

You can use a template with a default value if one isn’t provided.

action: light.turn_on
target:
  entity_id: light.gazebo_1
data:
  brightness_pct: "{{ var_brightness_pct | default(100) }}"
  color_name: "{{ var_color_name | default('blue') }}"
  color_temp_kelvin: "{{ var_color_temp | default(3000) }}"

The assumption is that var_color_temp (and the other two) are the names of script variables you are passing to the script.

FWIW, the color_temp option has been deprecated in favor of color_temp_kelvin.

1 Like

Hi Karco,

There’s a lot of jinja and that tends to get hard to read if you have to use this more than once. Consider putting this template in a custom_template / macro so you can call it. (Assuming you are going to use it more than one place).

The difference to remember is the return will be a string, and you may need to cast it to whatever if a string is not what you need returned.

1 Like

I didn’t know about this feature. Thanks for the information.

Can you explain why you have chosen to create a template that tests if each individual Jinja2 variable exists when all three variables do in fact exist and are hard-coded into the template itself?

image

Are the three Jinja2 variables actually script variables passed to the “generic” script that manages your outdoor lights?

Absolutely, that’s the case.

Then what’s the advantage of your long template versus simply using default as shown above?

Simply because I don’t want a default value. If the procedure is asked to adjust color, I don’t want to touch Brightness and vice versa. On the other hand, if I want to do both, it’s always possible.
I agree that it’s more complicated than it needs to be… But when I have an idea in mind, I go through with it.

Got it.

Although it’s possible for the default brightness value to be the light’s existing brightness value, that’s only possible if the light is already on so it’s not a good fit for your application.