Alexa notify automation for more than one entity

I have the following automation:

- alias: 'Garage: Notify Open'
  id: b4dddc0a-1212-42ac-aba5-75236ed4c498
  trigger:
    - platform: state
      entity_id: cover.small_garage_door_homekit
      to: open
      for: "00:00:10"
  action:
    - repeat:
        until: "{{ is_state('cover.small_garage_door_homekit', 'closed') }}"
        sequence:
          - service: notify.alexa_media
            data:
              data: { type: announce }
              message: 'Small garage door is open'
              target: media_player.everywhere
          - delay: "00:00:30"

The goal is to announce on all echos in the house when my garage door has been open for a certain period of time. That announcement should be repeated (with a delay) for as long as that door remains open.

The above YAML works fine for a single garage door, but I have two doors. I could simply copy & paste this for the 2nd entity, but I’m worried about two announcements happening at the same time, assuming both doors are opened simultaneously.

Is there a clever way to combine both entities into this logic? I’d be OK with 1 interval/timer to handle 2+ doors, and the message just changes depending on the combination:

  • Both doors open: “Big and small garage doors are open”
  • Only small garage door open: “Small garage door is open”
  • Only big garage door open: “Big garage door is open”

This is just a thought; I am open to whatever is easiest / most reasonable.

This should work:

- alias: 'Garage: Notify Open'
  id: b4dddc0a-1212-42ac-aba5-75236ed4c498
  trigger:
    - platform: state
      entity_id: 
        - cover.small_garage_door_homekit
        - cover.big_garage_door_entity
      to: open
      for: "00:00:10"
  action:
    - repeat:
        until: "{{ is_state('cover.small_garage_door_homekit', 'closed') and is_state('cover.other_garage_door_entity', 'closed') }}"
        sequence:
          - service: notify.alexa_media
            data:
              data: { type: announce }
              message: >
                {% set covers = ['cover.small_garage_door_homekit', 'cover.other_garage_door_entity'] %}
                {% set open =  expand(covers) | selectattr('state', 'eq', 'open') | map(attribute='attributes.friendly_name') | join(',') %}
                {% if expand(covers) | selectattr('state', 'eq', 'open') | list | count == 1 %}
                  The {{ open }} is open.
                {% elif expand(covers) | selectattr('state', 'eq', 'open') | list | count > 1 %}
                  The {{ open |replace(',' , " & ") }} are open.
                {% else %} 
                   no covers are open
                {% endif %}  
              target: media_player.everywhere
          - delay: "00:00:30"
1 Like

This is great. Thank you. Is there a way to build the list of covers from the list of entities in the trigger section to avoid duplicated lists?

Do you have any advice for how to test these expressions and learn what data they hold?

I’m not entirely sure what you mean but you can put the template in the dev tools->template section and see the return values.

as far as auto generating the covers I’m not sure. I’ll have to mess with it a bit.

I think I’ve finally worked it out. It worked in my tests.

{% set covers_open =  (states.cover
                            | selectattr('state', 'eq', 'open')
                            | map(attribute='name')
                            | list)
  %}
{% set count =  covers_open | count %}
{% if count == 1 %}
  The {{ covers_open | join(',') }} is open.
{% elif count == 2 %}
  The {{ covers_open | join(',') | replace(',' , " and ") }} are open.
{% elif count > 2 %}
  The {%- for item in covers_open -%}
        {{item}}{% if not loop.last %}, {% endif %}{% if loop.revindex == 2 %} and {% endif %}
      {%- endfor %} are open.
{% else %} 
  no doors are open
{% endif %}
1 Like

One issue with this compared to the first is that the notification will give the names of @voidpointer 's non-garage covers that are open as well.

I know it’s closer to what OP asked for, but I fail to see the point… it’s just as many lines and I’m pretty sure it would actually increase the amount of processing needed to render the template.

I thought that this might be a case where you could use the trigger_variables key, but that doesn’t seem to work either.

That is true but I don’t have any other covers and made the assumption that they might not have any either.

If so then a different solution will need to be used or just revert to the original.

I guess you could use the device class attribute as another filter to only select garage doors.

{% set open =  (states.cover
            | selectattr('attributes.device_class', 'defined')
            | selectattr('attributes.device_class', 'eq', 'garage_door')
            | selectattr('state', 'eq', 'open')
            | map(attribute='name')
            | list)
          %}
{% set count =  open | count %}
{% if count == 1 %}
  The {{ open | join(',') }} is open.
{% elif count == 2 %}
  The {{ open | join(',') | replace(',' , " and ") }} are open.
{% elif count > 2 %}
  The {%- for item in open -%}
        {{item}}{% if not loop.last %}, {% endif %}{% if loop.revindex == 2 %} and {% endif %}
      {%- endfor %} are open.
{% else %} 
  no doors are open
{% endif %}

Assuming the garage_door device class is set.

1 Like

I did some more tinkering and eventually got this to work nicely in a clean way. @finity was an absolute huge help in pushing me in the right direction. I’ve learned a lot. I ended up using a Group to define the list of garage doors I care about and have the automation operate on that. The group is a great way to make this automation scalable. If I want to add more covers, all I need to do is update the group. I don’t need to touch the automation.

configuration.yaml:

group: !include groups.yaml

groups.yaml:

garage_doors:
  name: Garage Doors
  entities:
    - cover.small_garage_door_homekit
    - cover.big_garage_door_homekit

In the automation itself, in addition to cleaning this up with a group, I also cleaned up the if/elseif conditions to use a more generic way of joining the entity names for more than 1 entity. It works for both 2 and >2 scenarios.

Automation:

- alias: "Garage: Notify Open"
  id: b4dddc0a-1212-42ac-aba5-75236ed4c498
  trigger:
    - platform: state
      entity_id: group.garage_doors
      to: open
      for: "00:30:00"
  action:
    - repeat:
        until:
          - condition: state
            entity_id: group.garage_doors
            state: closed
        sequence:
          - service: notify.alexa_media
            data:
              data: { type: announce }
              target: media_player.everywhere
              message: >
                {% set open = (expand('group.garage_doors')
                  | selectattr('state', 'eq', 'open')
                  | map(attribute='name')
                  | list)
                %}
                {% set count =  open | count %}
                {% if count == 1 %}
                  The {{ open[0] }} is open.
                {% elif count > 1 %}
                  The {{ open[:-1] | join(', ') }} and {{ open[-1] }} are open.
                {% else %}
                  No doors are open.
                {% endif %}
          - delay: "00:05:00"

I hope this gives back a little bit for all the help. Thanks to you all.

1 Like