Published on

Enhancing birthday notifications on Ulanzi Smart Pixel Clock

Authors
  • avatar
    Name
    Carsten Noetzel
    Twitter

Preface

In a blog post from December 28th I've implemented a birthday notifcation for the Ulanzi smart pixel clock flashed with AWTRIX Light. Birthdays are read from the Google calendar, which is fed by the birth dates from Google contacts.

My first approach was to read the description state attribute of calendar.geburtstage every 30 minutes and send a notification to the clock if such an all_day event is present. I assumed that {{ state_attr('calendar.geburtstage', 'all_day')}} would evaluate to false if there is no birthday on the current day, but this was false. Even when birthdays had already passed, notifications were sent the next day.

Furthermore the solution wasn't able to handle birthdays of multiple persons on the same day.

Enhancing birthday notifications

The general approach is to use the calendar trigger to get notified about todays birthdays. Information about the person is extracted from the trigger summary and stored in an input text helper. This helper is used to create a noticiation containing all the persons whose birthday is today.

Store birthdays in "input_text.birthdays"

First step is to created an input text helper to store the persons whose birthday is today. The following snippet is stored in configuration.yaml. The helper should be visible under "Settings → Devices & Services → Helper" after reloading configurations.

input_text:
  birthdays:
    name: Todays Birthdays
    icon: mdi:cake-variant

In automations.yaml the following automation is added to fill the input text with data.

- id: 'update_todays_birthdays'
  alias: Collect birthdays from Google Calendar
  trigger:
    - platform: calendar
      entity_id: calendar.geburtstage
  action:
    - service: input_text.set_value
      target:
        entity_id: input_text.birthdays
      data:
        value: >
          {% set name = trigger.calendar_event.summary | replace("hat Geburtstag","") | trim %}
          {{ (name + "," + states('input_text.birthdays')) }}
  mode: queued

This automation will be triggered when an event is present in the calendar calendar.geburtstage for the current day. As Google Calendar stores birthday events like "'First name' 'Last name' hat Geburtstag" the suffix "hat Geburtstag" will be removed from trigger.calendar_event.summary in order to store the persons name. The resulting name is then added to the input_text.birthdays with a , a seperator. Automation mode is set to queued as this automation will be triggered for ever person individually and we wan't all persons in our input_text.birthdays.

If there a multiple persons having birthday on the same day the result in input_text.birthdays will look like Titus,Theodor Fontane,Thomas D,.

Reset "input_text.birthdays" every day

To reset input_text.birthdays every day a second automation is stored in automations.yaml which will be triggered every day at 23:55:00 o'clock. It simply sets the value of input_text.birthdays to an empty string.

- id: 'cleanup_todays_birthdays'
  alias: Nightly cleanup automation for todays birthdays
  trigger:
    - platform: time
      at: '23:55:00'
  action:
    - service: input_text.set_value
      target:
        entity_id: input_text.birthdays
      data:
        value: ''

Send notification to pixel clock

All the persons who are having birthday today are stored in input_text.birthdays. This data could be used to create an automation for sending a notification to the pixel clock.

- id: 'birthday_notification'
  alias: Birthday notification
  trigger:
    - platform: time_pattern
      minutes: '/30'
  condition:
    - condition: template
      value_template: |-
        {{ states('input_text.birthdays') != "unknown" and states('input_text.birthdays') | length > 0 }}
    - condition: state
      entity_id: light.awtrix_XXXXXX_matrix
      state: 'on'
    - condition: time
      after: '10:00:00'
      before: '20:00:00'
  action:
    - service: mqtt.publish
      data:
        topic: awtrix_XXXXXX/notify
        payload: |-
          {% set birthdays = states('input_text.birthdays')[:-1].split(',') %}
          {% if birthdays | length == 1 %}
            {% set text = birthdays[0] + ' hat heute Geburtstag!' %}
          {%- else -%}
            {% set text = birthdays[:-1] | join(', ') + ' und ' + birthdays | last + ' haben heute Geburtstag!' %}
          {%- endif %}
          {
            "text": "{{ text }}", 
            "icon": 14004,
            "repeat": 3,
            "rainbow": true
          }

This automation is pretty similar to that I've created before. It's triggered every 30 minuted and sends a notification to the pixel clock between 10 and 20 o'clock if the pixel matrix is on and (that is new) the input_text.birthdays isn't unknown (inital value) or empty.

The action uses some Jinja2 templating magic to split the persons into an array and strip the trailing ,. Different texts are created based on whether one or more people have a birthday today.

Note

Using the template editor under "Developer Tools → Template" in HomeAssistant is very useful to see in advance what the commands do and get closer to the solution.

Conclusion

With a little more effort, a significantly better solution than before was created, which is now able to provide information about the birthdays of several people. I was also able to deal with templating for the first time and got to know another powerful tool.

birthday notification on pixel clock

Congratulations to todays birthday children Titus, Theodor Fontane und Thomas D.