Python_script for countdown to birthdays/anniversaries/significant dates

Now available on HACS

Thought I’d share this because:

  • a - I haven’t seen anything similar, in spite of a lot of googling
  • b - I’m pretty chuffed with it because I hate python but it actually works!

Lets say you want to add a couple of sensors to homeassistant that countdown to some significant dates. First make sure that you have python_script enabled in your configuration by adding

python_script:

to your configuration.yaml (or whichever of your packages suits you best)

Then, if you don’t already have one, in your configuration directory (the directory where your configuration.yaml resides) create a directory called python_scripts (note that the directory has an s on the end). In there create a file called date_countdown.py and add this…

""" This script creates a sensor that a counts down to the next occurrance """
"""   of a date, like a birthday or anniversary and gives the number of    """
"""                         years as an attribute                          """


"""       Requires python_script: to be enabled in you configuration       """


""" Usage:                                                                 """
"""                                                                        """
""" automation:                                                            """
"""   alias: Refresh John's birthday sensor                                """
"""   trigger:                                                             """
"""     platform: time                                                     """
"""     at: '00:00:01'                                                     """
"""   action:                                                              """
"""     service: python_script.date_countdown                              """
"""     data:                                                              """
"""       name: John                                                       """
"""       type: birthday                                                   """
"""       date: 17/08/1971   #DD/MM/YYYY                                   """


"""  This will create a sensor with entity_id sensor.birthday_john and a   """
"""  friendly name of 'John's birthday' .  The sensors value will be the   """
"""   number of days until the birthday, and the attribute 'years' will    """
"""          show how old John will be on his next birthday                """



today = datetime.datetime.now().date()

name = data.get('name')
type = data.get('type')
sensorName = "sensor.{}_{}".format(type , name.replace(" " , "_"))

dateStr = data.get('date')
dateSplit = dateStr.split("/")

dateDay = int(dateSplit[0])
dateMonth = int(dateSplit[1])
dateYear =  int(dateSplit[2])
date = datetime.date(dateYear,dateMonth,dateDay)

thisYear = today.year
nextOccur = datetime.date(thisYear , dateMonth , dateDay)

numberOfDays = 0
years = int(thisYear) - dateYear


if today < nextOccur:
  numberOfDays = (nextOccur - today).days

elif today > nextOccur:
  nextOccur = datetime.date(thisYear+1 , dateMonth , dateDay)
  numberOfDays = int((nextOccur - today).days)
  years = years+1


hass.states.set(sensorName , numberOfDays ,
  {
    "icon" : "mdi:calendar-star" ,
    "unit_of_measurement" : "days" ,
    "friendly_name" : "{}'s {}".format(name, type) ,
    "years" : years
  }
)

The way that python_scripts work with homeassistant is that you have to run them whenever you want the results, so create an automation that runs the script as many times as you need for the number of sensors you want. Each sensor requires:

  • name: NAME_OF_DATE
  • type: TYPE_OF_DATE
  • date: DD/MM/YYYY_OF DATE

examples:

  • name: John
  • type: birthday
  • date: 17/08/1971

or

  • name: Our wedding
  • type: anniversary
  • date: 14/02/1994

So if those were the two you wanted, an example automation to create and refresh the sensors daily would be:

automation:
  - alias: Reminder - Refresh date countdown sensors
    initial_state: on
    trigger:
      - platform: time
        at: '00:00:01'
      - platform: homeassistant
        event: start
    action:
      - service: python_script.date_countdown
        data:
          name: John
          type: birthday
          date: 17/08/1971
      - service: python_script.date_countdown
        data:
          name: Our wedding
          type: anniversary
          date: 14/02/1994

The sensors will then appear next time you restart homeassistant and refresh at midnight. Each sensor is given the following automatically:

entity_id: sensor.<type>_<name>
friendly_name: <name> 's <type>
state: <Days to the date from today>
years: <Number of years it will be>

So, the two sensors we created above would come out as:

sensor.birthday_john
friendly_name: John’s birthday
state: However many days it is until 17th August
years: However old John will be on his next birthday

sensor.anniversary_our_wedding
friendly_name: Our wedding anniversary
state: However many days to 14th February
years: How many years you will have been married on that day

You can then use the countdowns to send you reminders on the approach to the dates, or wish people happy birthday when they come home via TTS etc. Beware that you’ll probably want a wait_template so the automation doesn’t go off at midnight!!

Hope this is of some use to people :slight_smile:

11 Likes

For my American friends, if you really want to use MM/DD/YYYY ( :face_vomiting: - :laughing: ) then change these two lines in the python_script:

dateDay = int(dateSplit[0])
dateMonth = int(dateSplit[1])

to:

dateDay = int(dateSplit[1])
dateMonth = int(dateSplit[0])

and then in your automation to run the script do:

    action:
      - service: python_script.date_countdown
        data:
          name: John
          type: birthday
          date: 12/31/1971   # New Year's Eve

:slight_smile:

1 Like

Thanks for this. It is very useful because:

  • a - I don’t know python (so I can’t hate it yet :wink: )
  • b - I needed a push to learn how to dynamically create some components in HA

Whilst I don’t think I need the date countdown functionality your very clear example is going to be a great help .

1 Like

I like to write my dates YYYY/MM/DD but I think I can probably figure out the fix for that…I think…:thinking:

Thanks for putting this out. I can definitely see getting some use out of it.

EDIT:

Yes I figured it out:

dateDay = int(dateSplit[2])
dateMonth = int(dateSplit[1])
dateYear =  int(dateSplit[0])
1 Like

Im getting the wrong days. it says 600 days on birthday 25/08/1977.

The years old is right though

1 Like

Ha, that’s cos I’ve ballsed up the calculation but I didn’t realise because I did in December :smile:

I’ll fix it over the weekend and update the thread :+1:

I just noticed this too and was about to post about it.

Glad to see in it’s already in the queue.

@Johnny_Karlberg , @finity

I think this should do it - seems to be working right here - LMK if anything wrong with your reults :slight_smile:

today = datetime.datetime.now().date()

name = data.get('name')
type = data.get('type')
sensorName = "sensor.{}_{}".format(type , name.replace(" " , "_"))

dateStr = data.get('date')
dateSplit = dateStr.split("/")

dateDay = int(dateSplit[0])
dateMonth = int(dateSplit[1])
dateYear =  int(dateSplit[2])
date = datetime.date(dateYear,dateMonth,dateDay)

thisYear = today.year
nextOccur = datetime.date(thisYear , dateMonth , dateDay)

numberOfDays = 0
years = int(thisYear) - dateYear


if today < nextOccur:
  numberOfDays = (nextOccur - today).days

elif today > nextOccur:
  nextOccur = datetime.date(thisYear+1 , dateMonth , dateDay)
  numberOfDays = int((nextOccur - today).days)
  years = years+1


hass.states.set(sensorName , numberOfDays ,
  {
    "icon" : "mdi:calendar-star" ,
    "unit_of_measurement" : "days" ,
    "friendly_name" : "{}'s {}".format(name, type) ,
    "years" : years
  }
)
4 Likes

Looks like the change worked for me. Thanks!

1 Like

Great script, thank you for sharing.

1 Like

HI,
very nice, had been looking for this sometime, thanks!
played a bit with the customizing, and because we cant customize python created sensors via homeassistant: customize adapted the script a little to do so by itself.
Made a small addition to the friendly_name to have it show the number of days till the next countdown :wink:

only need a set of entity_pictures with the same name as the ‘name’:

hass.states.set(sensorName , numberOfDays ,
  {
    #"icon" : "mdi:calendar-star" ,
    "entity_picture" : "/local/family/{}.jpg".format(name.lower()),
    "unit_of_measurement" : "days" ,
    "friendly_name" : "{}'s {} turning ({}) in:".format(name, type, years) ,
    "years" : years
  }

cool!

is it possible to provide day of the week (for weekly tasks coundown) instead of the entire date?

thanks!

I believe the workday component does this already not entirely sure if this is what you mean though:

This will give only the state on/off if it’s the weekday I set, and not the countdown until this day.

Ah yeah, then I had understood you wrong. My apologies .

I have implemented by myself based on the date countdown in the top of this thread:


""" This script creates a sensor that a counts down to the next occurrance """
"""   of a day , like a recurrence meetings                                """

"""       Requires python_script: to be enabled in you configuration       """

""" Usage:                                                                 """
"""                                                                        """
""" automation:                                                            """
"""   alias: Refresh Plastic Bin sensor                                    """
"""   trigger:                                                             """
"""     platform: time                                                     """
"""     at: '00:00:01'                                                     """
"""   action:                                                              """
"""     service: python_script.day_countdown                               """
"""     data:                                                              """
"""       name: Plastic                                                    """
"""       type: Bin                                                        """
"""       day: 0 # 0-6(monday0-sunday6)                                    """


"""  This will create a sensor with entity_id sensor.plastic_bin and a     """
"""  friendly name of 'Plastic Bin' .  The sensors value will be the       """
"""   number of days until the provided day                                """

today = int(datetime.datetime.now().weekday())

name = data.get('name')
type = data.get('type')
sensorName = "sensor.{}_{}".format(type, name.replace(" ", "_"))

day = int(data.get('day')) # 0(Monday),6(Sunday)

if day == today:
    result = 0
elif day > today:
    result = day - today
else:
    result = 7 - abs(day - today)

hass.states.set(sensorName, result,
  {
    "icon": "mdi:calendar-star",
    "unit_of_measurement": "days",
    "friendly_name": "{} {}".format(name, type)
  }
)

Sorry to rehash this older post, but im a bit confused.

I installed this using HACS, but now im not sure where to configure the sensors.

I tried to make sensore in my sensors.yaml but no platform was placed in the example.
I don’t know much about python yet…
edit… maybe I just create a automation for it?
Thanks for any information anybody could provide.

Sorry I figured it out, disregard my stupidity…

The sensors are created when the automation runs. So it’s critical that the automation is running correctly.

An issue I had is that I switched the date formatting to USA as per a comment above. But it was throwing an error because I had the dates wrong. So make sure to check your log once the automation is up, because it will show clues if the sensors aren’t showing up.