Help with birthday automation (optimize code)

has one try the date countdown python script in the HACS

That works great. Thank you.

I havent but I will Google it and check it out. Thanks.

Just wanted to share my implementation of the version by @CCOSTAN and/or @silvrr (mentioned in the second post). My version checks for anniversaries happening today, tomorrow and in one week. It builds a notification and merges possible overlapping “today and tomorrow etc.” anniversaries into single notification.
In my example I’ve placed “important_days.json” in the same folder than my configuration.yaml.

important_days.json:

{
      "2/1": "Jane's birthday",
	  "2/2": "John's birthday",
	  "6/6": "Mary's and Mark's birthday",   # for overlapping birthdays
}
  - platform: command_line
    name: Anniversary
    command: 'cat important_days.json'
    value_template: >
      {% set today = now().month  ~ '/' ~ now().day  %}
      {% set tomorrow = (as_timestamp(now())+86400*1)| timestamp_custom("%-m")~ '/' ~(as_timestamp(now())+86400*1)| timestamp_custom("%-d")%}
      {% set in_a_week = (as_timestamp(now())+86400*7)| timestamp_custom("%-m")~ '/' ~(as_timestamp(now())+86400*7)| timestamp_custom("%-d")%}
      
      {% set anniversary_today =  value_json[ today ] %}
      {% set anniversary_tomorrow =  value_json[ tomorrow ] %}
      {% set anniversary_in_a_week =  value_json[ in_a_week ] %}
      
      {% if anniversary_today | trim != "" %}
        {% set notification = "Today is " + anniversary_today %}
      {% endif %}
      
      {% if anniversary_tomorrow | trim != "" %}
        {% if notification | trim == "" %}
          {% set notification = "Tomorrow is " + anniversary_tomorrow %}
        {% else %}
          {% set notification = notification + " and tomorrow is " + anniversary_tomorrow %}
        {% endif %}
      {% endif %}
      
      {% if anniversary_in_a_week | trim != "" %}
        {% if notification | trim == "" %}
          {% set notification = "In a week is " + anniversary_in_a_week %}
        {% else %}
          {% set notification = notification + " and in a week is " + anniversary_in_a_week %}
        {% endif %}
      {% endif %}
      
      {{notification}}
    scan_interval: 14400

Result for the 1st of February:
{{states(‘sensor.anniversary’)}} = Today is Jane’s birthday and tomorrow is John’s birthday

For european date format (Day-Month, e.g. 24/12 for Christmas Eve), swap now().month and now().day, and also swap timestamp_custom("%-m") and timestamp_custom("%-d")

2 Likes

Hi @haaghala, can you help?

I started with your example and with json file stored under /config/data/days.json. At the end I get nothing after several days. Also my script isn’t returning any state

image

Here is the script:

  - platform: command_line
    name: Holiday
    command: 'cat /config/data/days.json'
    value_template: >
      {% set today = now().day  ~ '/' ~ now().month  %}
      {% set tomorrow = (as_timestamp(now())+86400*1)| timestamp_custom("%-d")~ '/' ~(as_timestamp(now())+86400*1)| timestamp_custom("%-m")%}
      {% set in_a_week = (as_timestamp(now())+86400*7)| timestamp_custom("%-d")~ '/' ~(as_timestamp(now())+86400*7)| timestamp_custom("%-m")%}
      
      {% set holiday_today =  value_json[ today ] %}
      {% set holiday_tomorrow =  value_json[ tomorrow ] %}
      {% set holiday_in_a_week =  value_json[ in_a_week ] %}
      
      {% if holiday_today | trim != "" %}
        {% set notification = "Today is " + holiday_today %}
      {% endif %}
      
      {% if holiday_tomorrow | trim != "" %}
        {% if notification | trim == "" %}
          {% set notification = "Tomorrow is " + holiday_tomorrow %}
        {% else %}
          {% set notification = notification + " and tomorrow is " + holiday_tomorrow %}
        {% endif %}
      {% endif %}
      
      {% if holiday_in_a_week | trim != "" %}
        {% if notification | trim == "" %}
          {% set notification = "In a week is " + holiday_in_a_week %}
        {% else %}
          {% set notification = notification + " and in a week is " + holiday_in_a_week %}
        {% endif %}
      {% endif %}
      
      {{notification}}
    scan_interval: 14400

JSON file is under the config/data/ folder and it is named days.json. Below is the sample:

{
    "11/04/2020": "Test 1",
    "12/04/2020": "Test 2",
    "13/04/2020": "Test 3",
    "14/04/2020": "Test 4",
    "16/04/2020": "Test 5",
    "06/05/2020": "Test 6",
}

I am notifying on my telegram via bot instead of app

- id: '1585689238292'
  alias: Holiday and Birthday Notification
  trigger:
  - entity_id:
    - sensor.holiday
    platform: state
  condition:
  - condition: template
    value_template: '{{ states(''sensor.holiday'') != ''unknown'' }}'
  - condition: template
    value_template: '{{ states.sensor.holiday.state | trim != '''' }}'
  action:
  - data:
      message: Today is {{ states.sensor.holiday.state }}.
      title: '{{ states.sensor.holiday.state }}'
    service: telegram_bot.send_message
  initial_state: true

When execute automation manually it send message ***Today is .***.
Can you have look and let me know what I am doing wrong.

Thank you in advance

Hello,

I had placed my json in /config/important_days.json and I access it by:
command: 'cat important_days.json'
If you have yours in /config/data/days.json, so the first thing that came to my mind would be this correction:
command: 'cat data/days.json'
Or try my way first and see if it works. Then we would know it’s related to paths.

The last date does not get a comma. So it should end “06/05/2020”: “Test 6”

Thank you for the prompt reply.

I tried both ways having days json in data/days.json and also in config folder where configuration yaml is stored.
I kept my sensor Holiday which pointing to the data/days.json and added yours Aniversary pointing to days.json
Then created additional automation for for newly added “Aniversary” sensor.

On booth I updated scan_interval: to 10 seconds and nothing is happening on booth.
If manualy execute automation is sends message like this:

image

@silvrr than you for pointing that out. Figued it out after posting a question and corrected it. Actually I added approx 250 lines in days.json untill 2025, first Test 1 to 6 were added by intention to occur these days to have proper test. Last line don’t have comma.

What is different in my case compared to booth of you examples is that I have year included in days.json.
Does sensor has to be updated to include year into calculation?

Hi, I might have found the problem in your code.
My version has the dates in DD/MM format:

"2/1": "Jane's birthday",
"2/2": "John's birthday",
"6/6": "Mary's and Mark's birthday"

and you have them in DD/MM/YYYY:

"11/04/2020": "Test 1",
"12/04/2020": "Test 2",
"13/04/2020": "Test 3",

My code does not understand the YYYY year:
{% set today = now().day ~ '/' ~ now().month %}

It will never find any matching date because it will be comparing e.g. “11/04” against “11/04/2020” (which is always FALSE)

See the original posts in this thread from Jan 2019, there were examples on also including the year.

You are right, My date format is DD/MM/YYYY:.
I tried adding a year inspired by example from @silvrr, but obviously I am doing something wrong.

  - platform: command_line
    name: Holiday
    command: 'cat data/days.json'
    value_template: >
      {% set today = now().day  ~ '/' ~ now().month  ~ '/' ~ now().year  %}
      {% set tomorrow = (now().day+1)  ~ '/' ~ now().month ~ '/' ~ now().year %}
      {% set in_a_week = (now().day+7)  ~ '/' ~ now().month ~ '/' ~ now().year %}
      
      {% set holiday_today =  value_json[ today ] %}
      {% set holiday_tomorrow =  value_json[ tomorrow ] %}
      {% set holiday_in_a_week =  value_json[ in_a_week ] %}
      
      {% if holiday_today | trim != "" %}
        {% set notification = "Today is " + holiday_today %}
      {% endif %}
      
      {% if holiday_tomorrow | trim != "" %}
        {% if notification | trim == "" %}
          {% set notification = "Tomorrow is " + holiday_tomorrow %}
        {% else %}
          {% set notification = notification + " and tomorrow is " + holiday_tomorrow %}
        {% endif %}
      {% endif %}
      
      {% if holiday_in_a_week | trim != "" %}
        {% if notification | trim == "" %}
          {% set notification = "In a week is " + holiday_in_a_week %}
        {% else %}
          {% set notification = notification + " and in a week is " + holiday_in_a_week %}
        {% endif %}
      {% endif %}
      
      {{notification}}
    scan_interval: 10

And one followed by your example

  - platform: command_line
    name: Anniversary
    command: 'cat days.json'
    value_template: >
      {% set today = now().day  ~ '/' ~ now().month  ~ '/' ~ now().year  %}
      {% set tomorrow = (as_timestamp(now())+86400*1)| timestamp_custom("%-d")~ '/' ~(as_timestamp(now())+86400*1)| timestamp_custom("%-m")~ '/' ~(as_timestamp(now())+86400*1)| timestamp_custom("%-y")%}
      {% set in_a_week = (as_timestamp(now())+86400*7)| timestamp_custom("%-d")~ '/' ~(as_timestamp(now())+86400*7)| timestamp_custom("%-m")~ '/' ~(as_timestamp(now())+86400*7)| timestamp_custom("%-y")%}
      
      {% set anniversary_today =  value_json[ today ] %}
      {% set anniversary_tomorrow =  value_json[ tomorrow ] %}
      {% set anniversary_in_a_week =  value_json[ in_a_week ] %}
      
      {% if anniversary_today | trim != "" %}
        {% set notification = "Today is " + anniversary_today %}
      {% endif %}
      
      {% if anniversary_tomorrow | trim != "" %}
        {% if notification | trim == "" %}
          {% set notification = "Tomorrow is " + anniversary_tomorrow %}
        {% else %}
          {% set notification = notification + " and tomorrow is " + anniversary_tomorrow %}
        {% endif %}
      {% endif %}
      
      {% if anniversary_in_a_week | trim != "" %}
        {% if notification | trim == "" %}
          {% set notification = "In a week is " + anniversary_in_a_week %}
        {% else %}
          {% set notification = notification + " and in a week is " + anniversary_in_a_week %}
        {% endif %}
      {% endif %}
      
      {{notification}}
    scan_interval: 10

any of those giving trigger for notification.

I also updated json file and now consist only

{
    "10/04/2020": "Test 1",
    "12/04/2020": "Test 2",
    "16/04/2020": "Test 3",
    "11/04/2020": "Test 4",
    "21/04/2020": "Test 5",
    "13/04/2020": "Test 6",
    "14/04/2020": "Test 7",
    "15/04/2020": "Test 8",
    "06/05/2020": "Test 9"
}

Hi, I tried your code in hassio template editor:

{% set today = now().day  ~ '/' ~ now().month  ~ '/' ~ now().year  %}
{{today}}

15/4/2020

This would suggest you’d have to remove leading zeros from the month numbers. Could you try that?

Hi, updated as you described and it giving proper result

image

I tested script for end of the month setting today is 30/4/2020 on HW clock (simulating today is the last day of April) , and playing with json as below…

{
    "16/4/2020": "Test 7 bd",
    "17/4/2020": "Test 2 bd",
    "18/4/2020": "Test 3 bd",
    "19/4/2020": "Test 4 bd",
    "20/4/2020": "Test 5 bd",
    "23/4/2020": "Test 9 bd",
    "30/4/2020": "Test 1 bd",
    "1/5/2020": "Test 2 bd",
    "7/5/2020": "Test 3 bd",
    "25/5/2020": "Test 11 bd"
}

It seems that end/beginning of the month isn’t handling right since only result for today (30/4/2020) is shown
image
Probably same will happen at the end / beginning of the year.

Thanks for pointing that out. I now vaguely remember that I noticed the same thing some days after posting my solution. Haven’t done anything to resolve it yet. One solution could be counting the days since the beginning of year.

Please post your solution if you have the time and effort to fix it! I might have a look for it at some point.

My coding skills are not that good. /i can understand intention and maybe modify a bit to fit my needs but to make it from scratch I am not capable doing.

If you ever reach that “some point” post solution here.

Until then I can live with existing one and thanks a lot for help and support.

Cheers!

Hi. Did you figure out this warning? It started to appear a few months back and I have yet to figure it out. It is looking at date 2/19 ( 7 days ahead) and is empty.

Template variable warning: 'dict object' has no attribute '2/19' when rendering '{% set today = now().month ~ '/' ~ now().day %} {% set tomorrow = (as_timestamp(now())+86400*1)| timestamp_custom("%-m")~ '/' ~(as_timestamp(now())+86400*1)| 
timestamp_custom("%-d")%} {% set in_a_week = (as_timestamp(now())+86400*7)| timestamp_custom("%-m")~ '/' ~(as_timestamp(now())+86400*7)| timestamp_custom("%-d")%} {% set anniversary_today = value_json.MAJOR_JP.anniversary[ today ] %}
{% set anniversary_tomorrow = value_json.MAJOR_JP.anniversary[ tomorrow ] %} {% set anniversary_in_a_week = value_json.MAJOR_JP.anniversary[ in_a_week ] %} {% if anniversary_today | trim != "" %} {% set notification = "Today is " + 
anniversary_today %} {% endif %} {% if anniversary_tomorrow | trim != "" %} {% if notification | trim == "" %} {% set notification = "Tomorrow is " + anniversary_tomorrow %} {% else %} {% set notification = notification + " and tomorrow is " + 
anniversary_tomorrow %} {% endif %} {% endif %} {% if anniversary_in_a_week | trim != "" %} {% if notification | trim == "" %} {% set notification = "In a week is " + anniversary_in_a_week %} {% else %} {% set notification = notification + " and in a week is " 
+ anniversary_in_a_week %} {% endif %} {% endif %} {{notification}}'

I know that there has not been activity on this thread for some time, but parts of the codeing has changed because the command_line process has changed.

I moved the command_line to it’s own directory. It does create the sensor, but always shows as unavailable.

I have updated my code to reflect it but it stopped working.

If some one who still has this working could post there yaml for the script as well as the automation I would be most greatful.

Here is what I changed my code to.

####################################################
#     HOLIDAYS / BIRTHDAYS 2024Apr15               #
####################################################
  - sensor:
      name: hbrtoday
      command: "cat /opt/homeassistant/config/data/days.json"
      value_template: >
        {% set today = now().month  ~ '/' ~ now().day  %}
        {% set holiday =  value_json.MAJOR_US.static[ today ] %}
        {% if holiday | trim == "" %}
          {% set today = now().month  ~ '/' ~ now().day ~ '/' ~ now().year %}
          {% set holiday =  value_json.MAJOR_US.dynamic[ today ] %}
        {% endif %}
        {{ holiday }}
      scan_interval: 14400
####################################################
#  HOLIDAYS / BIRTHDAYS TOMORROW  2024Apr15        #
####################################################
  - sensor:
      name: hbrtomorrow
      command: "cat /opt/homeassistant/config/data/days.json"
      value_template: >
        {% set today = now().month  ~ '/' ~ (now().day+1)  %}
        {% set holiday =  value_json.MAJOR_US.static[ today ] %}
        {% if holiday | trim == "" %}
          {% set today = now().month  ~ '/' ~ (now().day+1) ~ '/' ~ now().year %}
          {% set holiday =  value_json.MAJOR_US.dynamic[ today ] %}
        {% endif %}
        {{ holiday }}
      scan_interval: 14400
####################################################
#  HOLIDAYS / BIRTHDAYS IN A WEEK 2024Apr15        #
####################################################
  - sensor:
      name: hbrinaweek
      command: "cat /opt/homeassistant/config/data/days.json"
      value_template: >
        {% set today = now().month  ~ '/' ~ (now().day+7)  %}
        {% set holiday =  value_json.MAJOR_US.static[ today ] %}
        {% if holiday | trim == "" %}
          {% set today = now().month  ~ '/' ~ (now().day+7) ~ '/' ~ now().year %}
          {% set holiday =  value_json.MAJOR_US.dynamic[ today ] %}
        {% endif %}
        {{ holiday }}
      scan_interval: 14400  
####################################################
#            END OF CONFIGURATION FILE             #
####################################################   

Thanks