Notify which windows are left open when you leave the house

Hi,

I want to send a notification when I leave the house about windows still being open. I don’t know how to extract the friendly_name of the specific switch that is still ‘on’. See my code here:

groups.yml

windows:
  name: Windows
  view: no
  entities:
    - switch.window_bedroom
    - switch.window_study
    - switch.window.bathroom

automation.yml

- alias: Left window open
  trigger:
    platform: state
    entity_id: input_boolean.someone_home
    to: 'off'
  condition:
    - condition: state
      entity_id: group.windows
      state: 'on'
  action:
    - service: notify.pushover
      data_template:
        message: "{{ states.group.windows.[entity_id].attributes.friendly_name }} are still open" <-- this part
        title: "Window still open"
        data:
          priority: 1

This is what i use for my notification - the output is not perfectly formatted, but I’m hoping to do that when I have a little more time, for the moment it does the job:

  action:  
    - service: notify.mypushbullet
      data_template:
        title: "Open are:"
        message: >-
          {%- set entities = [states.binary_sensor.back_deadbolt, states.binary_sensor.back_door, states.binary_sensor.balcony_deadbolt, states.binary_sensor.balcony_door, states.binary_sensor.balcony_window, states.binary_sensor.downstairs_deadbolt, states.binary_sensor.downstairs_door ] -%}
          {%- for entity in entities -%}
            {%- if entity.state == 'on' %}
              {{ entity.name }}
            {%- endif %}
          {%- endfor -%}

I have more binary_sensors in there but I guess you get where I’m coming from.

2 Likes

Thanks @chairstacker for the help, fixed it now:

- service: notify.pushover
  data_template:
    message: >-
      {%- for entity in states.group.windows.attributes.entity_id -%}
        {%- if states[entity.split('.')[0]][entity.split('.')[1]].state == 'on' %}
          {{ states[entity.split('.')[0]][entity.split('.')[1]].attributes.friendly_name }}
        {%- endif %}
      {%- endfor -%}
    title: "Window still open: "
    data:
      priority: 1
5 Likes

You can simplify that:

- service: notify.pushover
  data_template:
    message: >
     {{ states | selectattr('entity_id','in', state_attr('group.windows','entity_id')) | selectattr('state','eq','on') | map(attribute='name') | join(', ') }}
    title: "Window still open: "
    data:
      priority: 1
10 Likes

Hey, looking at doing something similar but rather than a text notification, wanting to have a Text To Speech notification about which windows I’ve left open when I try to enable the alarm.

Do you know how I could add an ‘and’ before the last name if there is more than one listed? As its going to be a voice notification, would sound more natural than just listing them with ands in between each one.

I know there are options for changing the string slightly like this:

    {%- for state in states.switch -%}
      {%- if state.state == 'on' -%}
        {%- if loop.first %}The {% elif loop.last %} and the {% else %}, the {% endif -%}
          {{ state.name }} status is {{ state.state }} 
      {%- endif -%}
    {%- else -%}

Maybe that helps!

Thanks, I went with this in the end:

{% set open_windows = states | selectattr('entity_id','in', state_attr('group.windows','entity_id')) | selectattr('state','eq','on') | map(attribute='name') | list %}
{% if open_windows | length == 0 %}
     All windows are closed.
{% elif open_windows | length == 1 %}
     There is a window open in the {{ open_windows | join('') }}.
{% else %}
     There are windows open in the {{ open_windows[:-1] | join(', ') }}{{',' if open_windows | length > 2 else ''}} and {{ open_windows[-1]}}.
{% endif %}
2 Likes

That’s what I would have done.

I was using this:

            * Open Windows *
            {%- for state in states.binary_sensor -%}
            {% set type = state.name.split(' ') | last -%}
              {% if type == 'Window' and state.state_with_unit == 'on' %}
                {{ state.name }}
              {%- endif -%}  
            {%- endfor %}

but yours gives a more elegant output. However can you offer a solution that removes the first four chars of the entity_id? all my PIR sensors are in the form pir_hall. I’ve tried [4:] everywhere I can think of (:slight_smile: I’m still a Python novice but this seemed like it would fit somewhere!) as well anything else I thought might do it. But no joy…

        {%- set movement = states | selectattr('entity_id','in', state_attr('group.all_pir_sensors','entity_id')) | selectattr('state','eq','on') | map(attribute='name') | list %}
        {% if movement | length == 0 %}
        *No* movement detected in the house.
        {%- elif movement | length == 1 %}
        There is *movement* in the {{ movement | join('') }}.
        {%- else %}
        There is *movement* in the {{ movement [:-1] | join(', ') }}{{',' if movement | length > 2 else ''}} and {{ movement [-1]}}.
        {%- endif %}

His template outputs the friendly name. The entity_id is used to grab the state. What are you trying to do?

If you are trying to mimic your loop, and all your PIR sensors are set up as device_class: window, then this template should work:

        {%- set windows = states.binary_sensor| selectattr('attributes.device_class','eq','window') | selectattr('state','eq','on') | map(attribute='name') | list %}
        {% if windows | length == 0 %}
        *No* windows are open in the house.
        {%- elif windows | length == 1 %}
        {{ windows[0] }} is open.
        {%- else %}
        {{ windows[:-1] | join(', ') }}{{',' if windows | length > 2 else ''}} and {{ windows[-1]}} are open.
        {%- endif %}

I probably should have included the output to illustrate what I get now and what I would like to see.

Currently I get output like this
There is *movement* in the PIR Dining Room and PIR Hall.

I’d like to lose the first four characters from the friendly name of the sensors to give this
There is *movement* in the Dining Room and Hall.

The above is obtained using this

{%- set movement = states | selectattr('entity_id','in', state_attr('group.all_pir_sensors','entity_id')) | selectattr('state','eq','on') | map(attribute='name') | list %}
{% if movement | length == 0 %}
*No* movement detected in the house.
{%- elif movement | length == 1 %}
There is *movement* in the {{ movement | join('') }}.
{%- else %}
There is *movement* in the {{ movement [:-1] | join(', ') }}{{',' if movement | length > 2 else ''}} and {{ movement [-1]}}.
{%- endif %}

PS. All my PIR sensors are in a group but your method selectattr('attributes.device_class','eq','motion') is possibly more correct and might allow me to dispense with the group.

How would this be if I wanted an automation notifying me of which windows or doors are open when I activate an input boolean? And if none is open send that information?

Its the template im struggeling with.

I have set up two groups like this:

  all_doors:
    name: Dører
    icon: mdi:door
    entities:
      - binary_sensor.inngangsdor
      - binary_sensor.terrassedor
      - binary_sensor.loftstuedor
      - binary_sensor.garasjedor
      - binary_sensor.dorinnigarasjen
      - binary_sensor.kjoleskapssensor

  all_windows:
    name: Vinduer
    icon: mdi:window-open-variant
    entities:
      - binary_sensor.vindu_vart_soverom
      - binary_sensor.malinavindu
      - binary_sensor.vindu_bad_oppe
      - binary_sensor.kjokkenvindu_hogre
      - binary_sensor.kjokkenvindu_skulen

Not sure if this is the way to go, please correct me.

Hello can You please help me to simplify this?

            {%- set _map = {'binary_sensor.door_window_sensor_158d0001c0a321':' u Mikołaja', 'binary_sensor.door_window_sensor_158d0001ef349c':' w sypialni', 'binary_sensor.door_window_sensor_158d0002048827':' w kuchni', 'binary_sensor.door_window_sensor_158d000232c85a':' w garażu', 'binary_sensor.door_window_sensor_158d0003ef0912':' w górnej łazience', 'binary_sensor.door_window_sensor_158d0002049acc':' w salonie drugie', 'binary_sensor.door_window_sensor_158d0002049ae9':' w salonie pierwsze', 'binary_sensor.door_window_sensor_158d00025370e5':' u Adasia'} %}
            {%- set windows = states.binary_sensor| selectattr('attributes.device_class','eq','window') | selectattr('state','eq','on') | map(attribute='entity_id') | list %}
            {% if windows | length == 0 %}
            Wszystkie okna są zamknięte
            {%- elif windows | length == 1 %}
            Okno{{ _map[windows[0] ]}} jest otwarte
            {%- else %}
            Okna{%- for window in windows -%}
                {%- if not loop.first %}{%- if loop.last %} i{%else%},{%- endif %}{%- endif %}{{ _map[window]}}  
            {%- endfor %} są otwarte
            {%- endif %}     

Is it possible to filter windows so that it takes value from _map without this for loop?

As far as I know there’s no Jinja2 filter that can perform a dictionary lookup. If it existed it would look something like this:

            {%- set windows = states.binary_sensor
              | selectattr('attributes.device_class','eq','window')
              | selectattr('state','eq','on')
              | map(attribute='entity_id')
              | map(lookup(_map)) | list %}

Even if this lookup filter existed, you would probably still need to use a for-loop. That’s because of your requirement to insert an i, instead of a comma, before the last name. If you are willing to eliminate the i before the last name, you can use the join(',') filter which can convert a list like this:

[' u Mikołaja', ' w garażu', ' u Adasia']

to this:

u Mikołaja,  w garażu, u Adasia

However, a new challenge is created because you are now required to create that list of names which requires a for-loop! So no matter which way we approach this problem, it’s difficult to resolve without a for-loop.

Purely as an academic exercise, here’s a different way to produce the ‘open windows’ message. It’s no better than the one you have and only serves to demonstrate an alternate approach.

{%- set _map = {'binary_sensor.door_window_sensor_158d0001c0a321':' u Mikołaja', 'binary_sensor.door_window_sensor_158d0001ef349c':' w sypialni', 'binary_sensor.door_window_sensor_158d0002048827':' w kuchni', 'binary_sensor.door_window_sensor_158d000232c85a':' w garażu', 'binary_sensor.door_window_sensor_158d0003ef0912':' w górnej łazience', 'binary_sensor.door_window_sensor_158d0002049acc':' w salonie drugie', 'binary_sensor.door_window_sensor_158d0002049ae9':' w salonie pierwsze', 'binary_sensor.door_window_sensor_158d00025370e5':' u Adasia'} %}
{%- set windows = states.binary_sensor | selectattr('attributes.device_class','eq','window')
    | selectattr('state','eq','on') | map(attribute='entity_id') | list %}

{% set ns = namespace(names = []) %}
{% for w in windows if w in _map.keys() %}
  {% set ns.names = ns.names + [_map[w]] %}
{% endfor %}
{% set open = ns.names | length %}

{% if open == 0 %}
  Wszystkie okna są zamknięte
{%- else %}
  Okn{{'a' if open > 1 else 'o'}}{{ ns.names | join(',') }} {{'są' if open > 1 else 'jest'}} otwarte
{%- endif %}

NOTE

This would be much easier to achieve if the binary_sensor’s friendly_name contained the information to display in the ‘open windows’ message. The challenge here is that the names are contained in a dictionary and, if the goal is to avoid using a for-loop, would require a filter to perform a lookup (i.e. mapping).

Hi everyone,

I have been trying to get something like this to work for over a day and it seems like i am running out ideas.
All codes above are not working for me and only makes a lot of errors :frowning:
Hopefully one of you guys can give a push in the right direction.

Thanks in advanced

#automation
- id: '1598544875271'
  alias: er zijn nog deuren open
  description: ''
  trigger:
  - event: leave
    platform: geo_location
    source: device_tracker.sm_g973f
    zone: zone.home
  condition:
  - condition: state
    entity_id: group.deuren
    state: ''
  action:
  - data:
      message: '{{ states.group.deuren.[entity_id].attributes.friendly_name }} zijn nog steeds open'
    service: notify.mobile_app_danny
  mode: single

#group
deuren:
  name: Deuren
  entities:
    -  binary_sensor.voordeur
    -  binary_sensor.keukendeur
    -  binary_sensor.garagedeur

What are you trying to do with this condition? To permit the action to occur, this condition wants the state of group.duren to be equal to no state at all. That’s never going to happen.

  - condition: state
    entity_id: group.deuren
    state: ''

In addition, what is this supposed to do?

{{ states.group.deuren.[entity_id].attributes.friendly_name }}

Are you trying to get group.duren’s entities attribute or its friendly_name attribute? Or are you trying to get the friendly_name of something else? Note: if you use a template then instead of data: you must indicate data_template: otherwise it won’t work.


EDIT

I’ll take a guess and this may be what you want:

#automation
- id: '1598544875271'
  alias: er zijn nog deuren open
  description: ''
  trigger:
  - event: leave
    platform: geo_location
    source: device_tracker.sm_g973f
    zone: zone.home
  condition:
  - condition: state
    entity_id: group.deuren
    state: 'on'
  action:
  - data_template:
      message: >
        Deze deuren staan ​​nog open {{ expand('group.deuren') | selectattr('state', 'eq', 'on') | map(attribute='name') | list | join(', ') }}
    service: notify.mobile_app_danny
  mode: single
1 Like

Hi 123,

Thanks for the quick response.

I am not sure how and where i ended with this code can’t even see my own keyboard anymore.

what i’m trying to achieve is that my wife or i (last one leaving the house) will get notifyed only when a window or a door is still open. this notification should only show wich doors / windows are still open.

your code above seems to work :relaxed:, only it’s sending a notification even when all doors are closed.

I really need to go and studio more hassio programming :sweat::

OK, then try the automation I posted above.

How are you testing the automation? Are you triggering it manually? If you are, then it skips the trigger and the condition and will always send a notification, even when all doors are closed.

I was rewriting my last reply, i’m a slow writer and It takes some time for me to write in english.

As i mentioned in my last (edited) post it partially works, but it sends notifications even when de doors are closed