Loop through brithday sensors and send notification

I use a python date script (https://github.com/mf-social/ps-date-countdown) to create birthday sensors. No I have 30+ birthday sensors. I would like to get a notification when a birthday is comming up. But I don’t want to setup a separte notification for every sensor. Can I make some sort of script that loops through all birthday_* sensor and checks the date and sends a notification when its eg 7 days due.

You can attached all the sensors to a single trigger. No need to loop. It’ll be 1 automation.

can use a sensor.birthday_* or do I need to specifiy the sensors ?

You have to specify the sensors

When replying make sure you reply properly, otherwise people don’t get notifications

Try this:

alias: Birthday notifications
trigger:
  - platform: time
    at: '08:00:00'
action:
  - variables:
      bdays: "{{ states.sensor | selectattr('attributes.years', 'defined') | selectattr('state', 'eq', '7') | list }}"
      qty: "{{ bdays | count }}"
      p1: "{{'is' if qty == 1 else 'are'}}"
      p2: "{{'s'  if qty > 1  else ''}}"
  - condition: template
    value_template: "{{ qty > 0 }}"
  - service: persistent_notification.create
    data:
      title: "Birthday Reminder"
      message: "In one week, there {{p1}} {{qty}} birthday{{p2}}. {{bdays | map(attribute='name') | join(', ')}}"

It’s an automation that executes every day at 08:00. It looks for any sensors that have the attribute years and checks if their state is 7. If it finds any, it will report them.

NOTE

This assumes the countdown sensors you have are only for birthdays. If you have countdown sensors for anniversaries or other categories, this automation will include them as well. If you don’t want that, and want reminders for birthdays only, the template will have to be enhanced.

Thank you for the code. In the notification option I get 220 ‘birthday’ but no names, and I don’t have 220 birthdays active. When I try the first line in the developer tools and set eq to a amount thats should return 1 birthday I get 1 respone. But I cannot try the rest of the code in the developer tools.

Is there more documentation on this or how can I try code to see if I get the right results ? The result in the developer tools is:
bdays: “[<template TemplateState(<state sensor.birthday_sjakie=43; icon=mdi:cake, unit_of_measurement=days, friendly_name= Sjakie (03/05/1978 / 43 jaar) , nextoccur=3/5/2021, years=43 @ 2021-03-23T00:00:01.038152+01:00>)>]”

Try this in the Template Editor (change '7' to whatever value necessary to get a match):

{% set bdays = states.sensor 
       | selectattr('attributes.years', 'defined')
       | selectattr('state', 'eq', '7') | list %}
{{ bdays | map(attribute='name') | join(', ') }}

It should not not display 220 instances of anything, just the sensors with a years attribute whose state matches whatever value you chose.


EDIT

FWIW, I use a heavily modified version of mf_social’s countdown sensor and the automation I suggested was confirmed to work on my system. Not sure why you got a dramatically different result.

Thanks for the help. I tested some things, but cannot get it to work. If I try this in the template editor:

{% set bdays = states.sensor 
       | selectattr('attributes.years', 'defined')
       | selectattr('state', 'eq', '41') | list %}
{{ bdays }}

I get:
[<template TemplateState(<state sensor.birthday_peter=41; icon=mdi:cake, unit_of_measurement=days, friendly_name= Peter (03/03/1978 / 43 jaar) , nextoccur=3/3/2021, years=43 @ 2021-03-25T10:22:43.807202+01:00>)>]

When I use:
{{ bdays | map(attribute='friendly_name') | join(', ') }}
I get nothing.

Can I use the set syntax in the automation yaml or do I need to use the bdays: option ?

{% set bdays = states.sensor 
       | selectattr('attributes.years', 'defined')
       | selectattr('state', 'eq', '41') | list %}

or
bdays: "{{ states.sensor | selectattr('attributes.years', 'defined') | selectattr('state', 'eq', '7') | list }}"

{{ bdays | map(attribute='attributes.friendly_name') | list | join(', ') }}

or

{{ bdays | map(attribute='name') | list | join(', ') }}

Sorry, that is due to my mistake. The template is not referring to the attribute correctly. Petro has identified the error. This also works properly:

{{ bdays | map(attribute='attributes.friendly_name') | join(', ') }}

However, all of this is just a minor distraction from the goal of this exercise which was to determine why you originally received a result containing 220 birthdays. It seems that this time, the template didn’t do that and bdays reports just 1 birthday.

Try this version which matches for 41 days (modify it if needed) and reports the friendly_name. It should produce just 1 birthday (for Peter). For testing purposes, you can manually execute this automation.

alias: Birthday notifications
trigger:
  - platform: time
    at: '08:00:00'
action:
  - variables:
      bdays: "{{ states.sensor | selectattr('attributes.years', 'defined') | selectattr('state', 'eq', '41') | list }}"
      qty: "{{ bdays | count }}"
      p1: "{{'is' if qty == 1 else 'are'}}"
      p2: "{{'s'  if qty > 1  else ''}}"
  - condition: template
    value_template: "{{ qty > 0 }}"
  - service: persistent_notification.create
    data:
      title: "Birthday Reminder"
      message: "There {{p1}} {{qty}} birthday{{p2}}. {{bdays | map(attribute='attributes.friendly_name') | join(', ')}}"

Tried it but now I get the following error in the log:
Error while executing automation automation.birthday_notifications: Error rendering data template: UndefinedError: ‘str object’ has no attribute ‘attributes’

7:19:09 PM – Automation (ERROR)

Birthday notifications: Error executing script. Error for call_service at pos 3: Error rendering data template: UndefinedError: ‘str object’ has no attribute ‘attributes’

7:19:09 PM – Automation (ERROR)

post your whole automation, if you’re using what 123 wrote, you have to move bdays out of the variable section because state objects do not transfer through.

If you’re executing the latest automation I posted, I have no idea how that error message is possible. I just executed it on my system and, if there are no birthdays in 41 days, it simply ends quietly, without any error messages. That’s because the Template Condition determines the quantity of birthdays is zero so it prevents execution of the action.

  bdays: "{{ states.sensor | selectattr('attributes.years', 'defined') | selectattr('state', 'eq', '41') | list }}"

That shouldn’t work because the result is __repr__ of state objects. Last I checked, that isn’t supported

I.E. The result would look like this, which doesn’t translate via a variable.

[<template TemplateState(<state light.ceiling_lights=on; min_mireds=153, max_mireds=500, brightness=180, color_temp=380, white_value=200, friendly_name=Ceiling Lights, supported_features=147 @ 2021-03-22T07:50:28.382687-04:00>)>, <template TemplateState(<state light.kitchen_lights=on; min_mireds=153, max_mireds=500, brightness=180, hs_color=(345, 75), rgb_color=(255, 63, 111), xy_color=(0.59, 0.274), white_value=200, friendly_name=Kitchen Lights, supported_features=147 @ 2021-03-22T07:50:28.389316-04:00>)>]

EDIT: Unless that was changed, which it could have been.

You’re right. I had tested it with a value that does not match anything and it completed quietly. However, when tested with a value that does match one or more then the error message is produced. Like you said, bdays doesn’t contain what I expected.

This version really works (adjust 41 days to the appropriate amount):

- alias: Birthday notifications
  trigger:
    - platform: time
      at: '08:00:00'
  action:
    - variables:
        bdays: >
          {% set b = states.sensor | selectattr('attributes.years', 'defined') 
                      | selectattr('state', 'eq', '41') | list %}
          {{ b if b | count == 0 else b | map(attribute='attributes.friendly_name') | list }}
        qty: "{{ bdays | count }}"
        p1: "{{'is' if qty == 1 else 'are'}}"
        p2: "{{'s'  if qty > 1  else ''}}"
    - condition: template
      value_template: "{{ qty > 0 }}"
    - service: persistent_notification.create
      data:
        title: "Birthday Reminder"
        message: "There {{p1}} {{qty}} birthday{{p2}}. {{bdays | join(', ')}}"
2 Likes

I use the one 123 had giving. And in the template editor I get the template respone you posted (<templatexxx)

The weird thing is that when I use the template editor:

{% set bdays = states.sensor | selectattr('attributes.years', 'defined') | selectattr('state', 'eq', '41') | list %}
{{ bdays | count }}

This gives me an output: 1

If I use this in the automation template yaml:

    - variables:
        bdays: "{{ states.sensor | selectattr('attributes.years', 'defined') | selectattr('state', 'eq', '41') }}"
        qty: "{{ bdays | count }}"

And output the qty in the message with {{ qty }} I get an value of 53

You say I have to move the bdays out of the var section, but where should I put it ?

Test the one I just posted above.

Screenshot of the persistent notification:

Screenshot from 2021-03-25 14-57-23

Sorry missed that last update script. The last one did in deed work.

Thank you all for the help

1 Like