Automation - notify if away while external door(s) opened

I have an automation that warns if any of our external doors are opened while the whole family is away. This is my current automation:

- id: '1672842695017'
  alias: Warning - External door opened when Family is away
  description: ''
  triggers:
  - entity_id:
    - group.external_doors
    to: 'on'
    trigger: state
  conditions:
  - condition: and
    conditions:
    - condition: state
      entity_id: group.family
      state: not_home
    - condition: not
      conditions:
      - condition: state
        entity_id: input_select.houskeeping_status
        state: Active
  actions:
  - choose:
    - conditions:
      - condition: and
        conditions:
        - condition: state
          entity_id: group.family
          state: not_home
        - condition: not
          conditions:
          - condition: state
            entity_id: input_select.houskeeping_status
            state: Active
      sequence:
      - data:
          message: '{% set doors = expand(''group.external_doors'')  | selectattr(''state'',
            ''eq'', ''on'') | map(attribute=''name'') | list %} {% set qty = doors
            | count %} {% set p1 = ''has been'' if qty > 1 else ''have been'' %}  {%
            if qty == 0 %}   No doors are open. {% else %}  Warning: {{'' and ''.join((doors
            | join('', '')).rsplit('', '', 1))}} {{p1}} opened and only Queenie seems
            to be at home. {% endif %}'
          title: 'Warning: External door(s) opened!'
        action: notify.mobile_app_christer_s_s23_ultra
      - data:
          title: 'Warning: External door(s) opened!'
          data:
            sound: climb
            priority: 1
          message: '{% set doors = expand(''group.external_doors'')  | selectattr(''state'',
            ''eq'', ''on'') | map(attribute=''name'') | list %} {% set qty = doors
            | count %} {% set p1 = ''has been'' if qty > 1 else ''have been'' %}  {%
            if qty == 0 %}   No doors are open. {% else %}  Warning: {{'' and ''.join((doors
            | join('', '')).rsplit('', '', 1))}} {{p1}} opened and only Queenie seems
            to be at home. {% endif %}'
        action: notify.pushover
      - data:
          message: '{% set doors = expand(''group.external_doors'')  | selectattr(''state'',
            ''eq'', ''on'') | map(attribute=''name'') | list %} {% set qty = doors
            | count %} {% set p1 = ''has been'' if qty > 1 else ''have been'' %}  {%
            if qty == 0 %}   No doors are open. {% else %}  Warning: {{'' and ''.join((doors
            | join('', '')).rsplit('', '', 1))}} {{p1}} opened and only Queenie seems
            to be at home. {% endif %}'
        action: notify.whatsapp
  mode: single

This works great, except that some times my home/away sensor(s) only change to ‘home’ a few seconds after our front door has been opened, leading to false notifications. So I tried to rewrite the automation with a 2 minute delay between the door being opened and the actual notification. This is my attempt:

- id: '1672842695017'
  alias: Warning - External door opened when Family is away
  description: ''
  triggers:
    - entity_id:
        - group.external_doors
      to: 'on'
      trigger: state
  conditions:
  - condition: and
    conditions:
    - condition: state
      entity_id: group.family
      state: not_home
    - condition: not
      conditions:
      - condition: state
        entity_id: input_select.houskeeping_status
        state: Active
  action:
    - service: variable.set_variable #line 3211
      data:
        variable: opened_doors_list
        value: >
          {% set doors = expand('group.external_doors') | selectattr('state', 'eq', 'on') %}
          {% set door_names = [] %}
          {% for door in doors %}
            {% set door_name = state_attr(door.entity_id, 'friendly_name') or door.entity_id | replace('binary_sensor.', '') | replace('_', ' ') | title %}
            {% set _ = door_names.append(door_name) %}
          {% endfor %}
          {{ door_names | to_json }}

    - delay:
        minutes: 2

    - choose: # line 3226
      - conditions:
        - condition: and
          conditions:
          - condition: state
            entity_id: group.family
            state: not_home
          - condition: not
            conditions:
            - condition: state
              entity_id: input_select.houskeeping_status
              state: Active
          sequence:
            - service: notify.mobile_app_christer_s_s23_ultra
              data:
                title: "Warning: External door(s) opened while away!"
                message: >
                  {% set opened_doors = states('variable.opened_doors_list') | from_json %}
                  {% if opened_doors | count > 1 %}
                    {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                  {% elif opened_doors | count == 1 %}
                    {{ opened_doors }} has been opened and only Queenie seems to be at home.
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}

            - service: notify.pushover
              data:
                title: 'Warning: External door(s) opened while away!'
                message: >
                  {% set opened_doors = states('variable.opened_doors_list') | from_json %}
                  {% if opened_doors | count > 1 %}
                    {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                  {% elif opened_doors | count == 1 %}
                    {{ opened_doors }} has been opened and only Queenie seems to be at home.
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
                data:
                  sound: climb
                  priority: 1
            - service: notify.whatsapp
              data:
                message: >
                  {% set opened_doors = states('variable.opened_doors_list') | from_json %}
                  {% if opened_doors | count > 1 %}
                    {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                  {% elif opened_doors | count == 1 %}
                    {{ opened_doors }} has been opened and only Queenie seems to be at home.
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
  mode: single

What is not working here is the " - service: variable.set_variable" part, and I cannot figure out what I’m doing wrong here. I’m attaching the error messages I see in the Lovelace UI, and I’ve made comments in the above automation st show the line number that is referenced in the attached screenshot.

Maybe someone more skilled in yaml/jinja2 than myself can see what I’m doing wrong here?

I ended up rewriting this to use the input_text.set_value service in stead, so it seems to be working now:

- id: '1672842695017'
  alias: Warning - External door opened when Family is away
  description: ''
  triggers:
    - entity_id:
        - group.external_doors
      to: 'on'
      trigger: state
  conditions:
    - condition: and
      conditions:
        - condition: state
          entity_id: group.family
          state: not_home
        - condition: not
          conditions:
            - condition: state
              entity_id: input_select.houskeeping_status
              state: Active
  action:
    - service: input_text.set_value
      data:
        entity_id: input_text.opened_doors_list
        value_template: >
          {% set doors = expand('group.external_doors') | selectattr('state', 'eq', 'on') %}
          {% set door_names = [] %}
          {% for door in doors %}
            {% set door_name = state_attr(door.entity_id, 'friendly_name') or door.entity_id | replace('binary_sensor.', '') | replace('_', ' ') | title %}
            {% set _ = door_names.append(door_name) %}
          {% endfor %}
          {{ door_names | join(',') }}

    - delay:
        minutes: 2

    - choose:
        - conditions:
            - condition: and
              conditions:
                - condition: state
                  entity_id: group.family
                  state: not_home
                - condition: not
                  conditions:
                    - condition: state
                      entity_id: input_select.houskeeping_status
                      state: Active
          sequence:
            - service: notify.mobile_app_christer_s_s23_ultra
              data:
                title: "Warning: External door(s) opened while away!"
                message: >
                  {% set opened_doors_string = states('input_text.opened_doors_list') %}
                  {% if opened_doors_string %}
                    {% set opened_doors = opened_doors_string.split(',') %}
                    {% if opened_doors | count > 1 %}
                      {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                    {% elif opened_doors | count == 1 %}
                      {{ opened_doors[0] }} has been opened and only Queenie seems to be at home.
                    {% endif %}
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}

            - service: notify.pushover
              data:
                title: 'Warning: External door(s) opened while away!'
                message: >
                  {% set opened_doors_string = states('input_text.opened_doors_list') %}
                  {% if opened_doors_string %}
                    {% set opened_doors = opened_doors_string.split(',') %}
                    {% if opened_doors | count > 1 %}
                      {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                    {% elif opened_doors | count == 1 %}
                      {{ opened_doors[0] }} has been opened and only Queenie seems to be at home.
                    {% endif %}
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
                sound: climb
                priority: 1

            - service: notify.whatsapp
              data:
                message: >
                  {% set opened_doors_string = states('input_text.opened_doors_list') %}
                  {% if opened_doors_string %}
                    {% set opened_doors = opened_doors_string.split(',') %}
                    {% if opened_doors | count > 1 %}
                      {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                    {% elif opened_doors | count == 1 %}
                      {{ opened_doors[0] }} has been opened and only Queenie seems to be at home.
                    {% endif %}
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
  mode: single

Forgot to mention that the previous version was using a custom component. now I’m just using the built-in input_text server with a helper “opened_doors_list” defined through the GUI.

I concluded before testing properly, it still does not work. The automation gives me the following error when it’s triggered:

Error: Error rendering data template: SecurityError: access to attribute ‘append’ of ‘list’ object is unsafe.

It seems to be relatet to my ninja2 statement:

data:
  entity_id: input_text.opened_doors_list
  value_template: >
    {% set doors = expand('group.external_doors') | selectattr('state', 'eq',
    'on') %} {% set door_names = [] %} {% for door in doors %}
      {% set door_name = state_attr(door.entity_id, 'friendly_name') or door.entity_id | replace('binary_sensor.', '') | replace('_', ' ') | title %}
      {% set _ = door_names.append(door_name) %}
    {% endfor %} {{ door_names | join(',') }}
action: input_text.set_value

Any ideas anyone?

Turned out Home Assistant does not allow append to be used in an automation the way I dod,. so I attempted to re-write my ninja2 code again, and ended up with this:

- id: '1672842695017'
  alias: Warning - External door opened when Family is away
  description: ''
  triggers:
    - entity_id:
        - group.external_doors
      to: 'on'
      trigger: state
  conditions:
    - condition: and
      conditions:
        - condition: state
          entity_id: group.family
          state: not_home
        - condition: not
          conditions:
            - condition: state
              entity_id: input_select.houskeeping_status
              state: Active
  action:
    - service: input_text.set_value
      data:
        entity_id: input_text.opened_doors_list
        value: >-
          {% set doors = expand('group.external_doors') | selectattr('state', 'eq', 'on') %}
          {% set door_names = [] %}
          {% for door in doors %}
            {% set door_name = state_attr(door.entity_id, 'friendly_name') or door.entity_id | replace('binary_sensor.', '') | replace('_', ' ') | title %}
            {% set door_names = door_names + [door_name] %}
          {% endfor %}
          {{ door_names | join(',') }}

    - delay:
        minutes: 2

    - choose:
        - conditions:
            - condition: and
              conditions:
                - condition: state
                  entity_id: group.family
                  state: not_home
                - condition: not
                  conditions:
                    - condition: state
                      entity_id: input_select.houskeeping_status
                      state: Active
          sequence:
            - service: notify.mobile_app_christer_s_s23_ultra
              data:
                title: "Warning: External door(s) opened while away!"
                message: >
                  {% set opened_doors_string = states('input_text.opened_doors_list') %}
                  {% if opened_doors_string %}
                    {% set opened_doors = opened_doors_string.split(',') %}
                    {% if opened_doors | count > 1 %}
                      {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                    {% elif opened_doors | count == 1 %}
                      {{ opened_doors[0] }} has been opened and only Queenie seems to be at home.
                    {% endif %}
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}

            - service: notify.pushover
              data:
                title: 'Warning: External door(s) opened while away!'
                message: >
                  {% set opened_doors_string = states('input_text.opened_doors_list') %}
                  {% if opened_doors_string %}
                    {% set opened_doors = opened_doors_string.split(',') %}
                    {% if opened_doors | count > 1 %}
                      {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                    {% elif opened_doors | count == 1 %}
                      {{ opened_doors[0] }} has been opened and only Queenie seems to be at home.
                    {% endif %}
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
                data:
                  sound: climb
                  priority: 1

            - service: notify.whatsapp
              data:
                message: >
                  {% set opened_doors_string = states('input_text.opened_doors_list') %}
                  {% if opened_doors_string %}
                    {% set opened_doors = opened_doors_string.split(',') %}
                    {% if opened_doors | count > 1 %}
                      {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                    {% elif opened_doors | count == 1 %}
                      {{ opened_doors[0] }} has been opened and only Queenie seems to be at home.
                    {% endif %}
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
  mode: single

But still no go, no error messages but whatever door is opened I just get the message “No doors were opened …”. So obviously something is wrong with my ninja2 logic, or how I manipulate the strings when composing my message, or most likely both! :slight_smile:

YAML and NINJA2 sure is a PITA, and it doesn’t help that my own programming experience is mostly with C/C++/assembly language.

So please help someone, I’m sure my error(s) will be obvious to some of you :slight_smile:

Due to Jinja variable scope, you cannot set variables inside a for loop and have them accessible on the “outside”. The only exception is to use a namespace.

https://jinja.palletsprojects.com/en/stable/templates/#jinja-globals.namespace

Don’t know where you got the variable.set_variable action from. Just use a variables: block? No need for a helper in this case.

Your whole automation logic seems quite overcomplicated though…

Finally got this working, so leaving the working version here in case it can help somebody else.

I still think yaml and jinja2 is a real PITA, but at least I learned something new today! :grinning:

- id: '1672842695017'
  alias: Warning - External door opened when Family is away
  description: ''
  triggers:
    - entity_id:
        - group.external_doors
      to: 'on'
      trigger: state
  conditions:
    - condition: and
      conditions:
        - condition: state
          entity_id: group.family
          state: not_home
        - condition: not
          conditions:
            - condition: state
              entity_id: input_select.houskeeping_status
              state: Active
  action:
    - service: input_text.set_value
      data:
        entity_id: input_text.opened_doors_list
        value: >-
          {% set open_doors = expand('group.external_doors') | selectattr('state', 'eq', 'on') | map(attribute='name') | list %}
          {{ open_doors | join(',') }}
          
    - delay:
        minutes: 2

    - choose:
        - conditions:
            - condition: and
              conditions:
                - condition: state
                  entity_id: group.family
                  state: not_home
                - condition: not
                  conditions:
                    - condition: state
                      entity_id: input_select.houskeeping_status
                      state: Active
          sequence:
            - service: notify.mobile_app_christer_s_s23_ultra
              data:
                title: "Warning: External door(s) opened while away!"
                message: >-
                  {% set opened_doors_string = states('input_text.opened_doors_list') %}  {# Get the string value #}
                  {% if opened_doors_string %}  {# Check if the string is not empty #}
                    {% set opened_doors = opened_doors_string.split(',') %}  {# Split the string into a list #}
                    {% if opened_doors | length > 1 %}
                      {{ opened_doors[:-1] | join(', ') }} and {{ opened_doors[-1] }} have been opened and only Queenie seems to be at home.
                    {% elif opened_doors | length == 1 %}
                      {{ opened_doors[0] }} has been opened and only Queenie seems to be at home.
                    {% endif %}
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
                 
            - service: notify.pushover
              data:
                title: 'Warning: External door(s) opened while away!'
                message: >
                  {% if states('input_text.opened_doors_list') | length > 0 %}
                    {% for door in states('input_text.opened_doors_list') %}
                      {{ door }}{% if not loop.last %}, {% endif %}  {# Add comma and space unless it's the last item #}
                    {% endfor %} opened and only Queenie seems to be at home.
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
                data:
                  sound: climb
                  priority: 1

            - service: notify.whatsapp
              data:
                message: >
                  {% if states('input_text.opened_doors_list') | length > 0 %}
                    {% for door in states('input_text.opened_doors_list') %}
                      {{ door }}{% if not loop.last %}, {% endif %}  {# Add comma and space unless it's the last item #}
                    {% endfor %} opened and only Queenie seems to be at home.
                  {% else %}
                    No doors were opened while you were away. Check sensors!
                  {% endif %}
  mode: single