Template-based action in an automation

Hi,

for my heating automation(s) I am trying to execute an action based on a template.
Specifically, depending of the state of a sensor, I want to execute one action or another.
Example:

actions:
[...]
  - action: '{% if is_state("binary_sensor.fibaro_fgk_bedroom_open", "off") %} input_number.set_value
      {% else %} climate.turn_off {% endif %}

      '
    data: '{% if is_state("binary_sensor.fibaro_fgk_bedroom_open", "off") %} value:
      {{ states("input_number.heating_bedroom_day") }} {% else %} {} {% endif %}

      '
    target:
      entity_id: '{% if is_state("binary_sensor.fibaro_fgk_bedroom_open", "off") %}
        input_number.heating_bedroom {% else %} climate.spirit_bedroom  {% endif %}

        '
[...]

So, depending on the sensor state, this should either result in something like

- action: input_number.set_value
  data:
    value: <some_number>
  target:
      entity_id: input_number.heating_bedroom

or

- action: climate.turn_off
  data: {}
  target:
    entity_id: climate.spirit_bedroom

The code itself does not give any errors, but unfortunately the execution of the actions: list stops at this point and none of the succeeding actions are triggered.

Does anyone have an idea what’s wrong here?

Data needs to return a dictionary, not yaml. Also, if this just a single if statement and you aren’t going to have multiple options, you’re likely better off using if,then,else action.

Thanks for your reply! I read it multiple times and still can’t follow what you mean :wink:
Could you please elaborate a little bit more, maybe give an example?

What’s the reason for using jinja/templates here?

I am running a sequence of actions to update the temperature settings for each thermostat.
Depending on the a binary sensor state (= window sensor reporting an open window), for a single one of those thermostats, I don’t want to update the temperature (which would trigger the TRV switching into heat mode), but instead I want to run a climate.turn_off action.

The automation itself is triggered by a number of different events, so its most likely not sufficient to place a condition clause before the input_number.set_value action for this particular TRV.
(I would need to check again, but there was a reason why I tried it the way it looks now).

If you know an alternative way to “phrase” it, please let me know.

Direct reply to your question (without going into whether it is necessary or not): you have to return dictionary in both cases, not just in the “else” case.

data: >
  {% if is_state("binary_sensor.fibaro_fgk_bedroom_open", "off") %}
    {{ { "value": states("input_number.heating_bedroom_day") } }}
  {% else %}
    {}
  {% endif %}

you can also use dict() function to make the dictionary: dict(value=states("input_number.heating_bedroom_day")). Either way, the whole thing must be enclosed in {{ }} for functions (states/dict) to work. Same applies to the target field.

1 Like

Ah, thanks for the explanation!

But wouldn’t a (simplified) statement like this:

data: >
  {% if (something) %}
  value: {{ states("some_other_thing") }}
  {% endif %}

result in a valid dictionary, i.e. like

data:
  value: 42

You might have a problem with the syntax. Templates need to be quoted for single line:

  - action: "{{ 'switch.turn_on' }}"

or unquoted for multi-line:

  - action: >
      {{ 'switch.turn_on' }}

In your original post, you appear to have newline characters within a quoted template, which will fail.

This:

produces a string. You can help yourself by testing such code snippets in the template editor in Developer Tools and observing the type of result.

2 Likes

I blame the visual editor :wink:

It looks like it’s working now, looking like this:

  - action: >
      {% if is_state("binary_sensor.fibaro_fgk_bedroom_open", "off") %}
      input_number.set_value
      {% else %}
      climate.turn_off
      {% endif %}
    data: >
      {% if is_state("binary_sensor.fibaro_fgk_bedroom_open", "off") %}
      {{ dict(value=states("input_number.heating_bedroom_day")) }}
      {% else %}
      {}
      {% endif %}
    target:
      entity_id: >
        {% if is_state("binary_sensor.fibaro_fgk_bedroom_open", "off") %}
        input_number.heating_bedroom
        {% else %}
        climate.spirit_bedroom
        {% endif %}

I will watch the behavior closely, but a first test ran successful.
Thanks everyone!

well, from my standpoint, it doesn’t seem like you need templates at all. Templates are just making it harder to read.

- if:
  - condition: state
    entity_id: binary_sensor.fibaro_fgk_bedroom_open
    state: "off"
  then:
  - action: input_number.set_value
    target:
      entity_id: input_number.heating_bedroom
    data:
      value: '{{ states("input_number.heating_bedroom_day") }}'
  else:
  - action: climate.turn_off
    target:
      entity_id: climate.spirit_bedroom

But if you really want to use templates all you need to change is

    data: '{% if is_state("binary_sensor.fibaro_fgk_bedroom_open", "off") %}
      {"value":{{ states("input_number.heating_bedroom_day") }} } {% else %} {} {% endif %}

      '

If you were doing more than a single if statement, then I’d use templates… but you aren’t.

2 Likes

Thanks a lot, @petro!
I must admit, I wasn’t aware of that syntax and you’re right, it’s a lot easier to read.

I will start refactoring my code :smiley:

I am, of course, aware of the template editor (been using it for years).
However, until now I was not consciously aware that it shows the data type of the output.
Thanks for pointing that out!

…with some caveats about its behaviour:

1 Like