Nested if statements in an automation's data_template

I have several Aeotec door and window sensors which return 22 if the contact is open, and 23 when it’s closed. Occasionally they return 254* when they’re asleep, so I’m using an input_boolean to filter out that state and feed a binary_sensor which I can set with device_class of door or window. I’m struggling with nested if statements in the data_template section of my automation. The goal is to set the right input_boolean “filter” sensor and notify me of any unknown states or sensors.

- id: '1591327292171'
  alias: Aeotec Door and Window Boolean Filter
  description: "Change the input boolean for known states of the door's access control\n\
    \    sensor while filtering out state 254"
  trigger:
  - entity_id: sensor.sliding_glass_door_access_control, sensor.front_door_access_control,
      sensor.garage_house_door_access_control, sensor.garage_side_door_access_control,
      sensor.kevin_bed_window_access_control
    platform: state
  condition:
  - condition: template
    value_template: '{{ trigger.to_state|int != 255 }}'
  - condition: state
    entity_id: binary_sensor.system_ready
    state: 'on'
  action:
  - service_template: >
      {% if trigger.entity_id == 'sensor.sliding_glass_door_access_control' or trigger.entity_id == 'sensor.front_door_access_control' or trigger.entity_id == 'sensor.garage_house_door_access_control' or trigger.entity_id == 'sensor.garage_side_door_access_control' or trigger.entity_id == 'sensor.kevin_bed_window_access_control' %}
        {% if trigger.to_state.state|int == 23 %}
          input_boolean.turn_off
        {% elif trigger.to_state.state|int == 22 %}
          input_boolean.turn_on
        {% else %}
          notify.kevin
        {% endif %}
      {% else %}
        notify.kevin
      {% endif %}
    data_template: >
      {% if trigger.to_state.state|int == 23 or trigger.to_state.state|int == 22 %}
        entity_id: 
          {% if trigger.entity_id == 'sensor.sliding_glass_door_access_control' %}
            input_boolean.sliding_glass_door_filter
          {% elif trigger.entity_id == 'sensor.front_door_access_control' %}
            input_boolean.front_door_filter
          {% elif trigger.entity_id == 'sensor.garage_house_door_access_control' %}
            input_boolean.garage_house_door_filter
          {% elif trigger.entity_id == 'sensor.garage_side_door_access_control' %}
            input_boolean.garage_side_door_filter
          {% elif trigger.entity_id == 'sensor.kevin_bed_window_access_control' %}
            input_boolean.kevin_bed_window_filter
          {% else %}
            - data:
              title: You have a problem with the  {{ trigger.entity_id }}
              message: The trigger.to_state is  {{ trigger.to_state.state|int }}
          {% endif %}
      {% else %}
        - data:
          title: "You have a problem with the  {{ trigger.entity_id }}"
          message: The trigger.to_state is  {{ trigger.to_state.state|int }}
      {% endif %}

My configuration check returns:

Configuration invalid
Invalid config for [automation]: expected a dictionary for dictionary value @ data['action'][0]['data_template']. Got None. (See ?, line ?). 

The configuration check passes if the data_template: section is changed to:

    data_template:
      entity_id: >
        {% if trigger.entity_id == 'sensor.sliding_glass_door_access_control' %}
          input_boolean.sliding_glass_door_filter
        {% elif trigger.entity_id == 'sensor.front_door_access_control' %}
          input_boolean.front_door_filter
        {% elif trigger.entity_id == 'sensor.garage_house_door_access_control' %}
          input_boolean.garage_house_door_filter
        {% elif trigger.entity_id == 'sensor.garage_side_door_access_control' %}
          input_boolean.garage_side_door_filter
        {% elif trigger.entity_id == 'sensor.kevin_bed_window_access_control' %}
          input_boolean.kevin_bed_window_filter
        {% else %}
          - data:
            title: You have a problem with the  {{ trigger.entity_id }}
            message: The trigger.to_state is  {{ trigger.to_state.state|int }}
        {% endif %}

I’d appreciate any help in understanding what I’m doing wrong, or pointers to documentation.

* The automation condition is set to 255 and not 254 intentionally so that I can test the notification when the device goes to sleep. I’ll correct it later once I know it’s working.

Think of an automation as being a form with fields that you fill out. Each field can have a template to compute its value. What you can’t do is what you did in your example. You created a template outside of a field.

This is valid. Templates are used to compute values for the fields.

name: "{{template to compute the name}}"
address: "{{template to compute the address}}"

This is not valid. A template is used to determine which fields, if any, should be employed.

{{ template to compute whether the name and address fields should be used }}

Also, this template is incorrect:

    value_template: '{{ trigger.to_state|int != 255 }}'

it should be:

    value_template: '{{ trigger.to_state.state|int != 255 }}'

One more thing: you can take advantage of the fact that you have used a consistent naming structure for your sensors and input_booleans. Instead of doing this:

          {% if trigger.entity_id == 'sensor.sliding_glass_door_access_control' %}
            input_boolean.sliding_glass_door_filter
          {% elif trigger.entity_id == 'sensor.front_door_access_control' %}
            input_boolean.front_door_filter
          {% elif trigger.entity_id == 'sensor.garage_house_door_access_control' %}
            input_boolean.garage_house_door_filter
          {% elif trigger.entity_id == 'sensor.garage_side_door_access_control' %}
            input_boolean.garage_side_door_filter
          {% elif trigger.entity_id == 'sensor.kevin_bed_window_access_control' %}
            input_boolean.kevin_bed_window_filter

you can just do this:

          input_boolean.{{trigger.object_id.replace('access_control', 'filter')}}
1 Like

So something like this?

    data_template: >
      {% if trigger.to_state.state|int == 23 or trigger.to_state.state|int == 22 %}
        {% if trigger.entity_id == 'sensor.sliding_glass_door_access_control' %}
          entity_id: input_boolean.sliding_glass_door_filter

Thanks for pointing out the missing .state

input_boolean.{{trigger.object_id.replace('access_control', 'filter')}}

Oh, brilliant! Thanks!!

No. That’s still a template that exists outside of the entity_id option.

The problem is that you painted yourself into a corner when you created a service_template that can call either of two services and each service has different options. In the data_template you’re trying to use the correct options depending on which of the two services is employed. You can’t do that because it requires the template to exists outside of the options and that’s not permitted.

A similar problem occurs when people make a service_template that will either turn a light on or off. If it’s turn_on they want options to set brightness, rgb_color, etc. However, the turn_off service accepts no brightness, rgb_color, etc options so you can’t supply the ones used for turn_on and hope they’ll simply be ignored. Attempts to use a template to include/exclude brightness, rgb_color, etc won’t work because of the same restriction (the template is only valid to compute an option’s value not to exist outside of it and determine which options should be included/excluded).

Long story short, you’re going to have to redesign that automation. Consider creating separate automations.

1 Like

AH! Thank you. I understand the problem and why that’s not working now.

1 Like