Skip to content

Instantly share code, notes, and snippets.

@gbasile
Created January 6, 2026 20:28
Show Gist options
  • Select an option

  • Save gbasile/e35bc2b5ecdefe77a374567c2d79d813 to your computer and use it in GitHub Desktop.

Select an option

Save gbasile/e35bc2b5ecdefe77a374567c2d79d813 to your computer and use it in GitHub Desktop.
Blueprint Calendar
blueprint:
name: Giuseppe MatrixLed Calendar Notifier
description: "Displays upcoming calendar events on AWTRIX LED matrix displays.
**Features:**
- Monitors multiple calendars simultaneously
- Shows all upcoming events within a configurable time window
- Displays day-of-month icons (1-31) for each event
- Automatically calculates and displays age for birthday events (e.g., 'Birthday 1984' becomes 'Birthday 41')
- Smart time display: shows time for timed events, omits for all-day events
- Updates every 5 minutes and on Home Assistant restart
- Unique MQTT topics for each event to avoid conflicts
**Calendar Support:**
Tested with [Google Calendar](https://www.home-assistant.io/integrations/google), but should work with any Home Assistant calendar integration.
**Icon Support:**
Uses day-of-month icons (11543-11571) from the AWTRIX icon library. Custom icons can be configured via the default_icon setting."
domain: automation
input:
awtrix:
name: AWTRIX Device
description: Select the Awtrix device
selector:
device:
integration: mqtt
manufacturer: Blueforcer
model: AWTRIX 3
multiple: true
app_name:
name: Awtrix Application name
description: This is the app name listed in the MQTT topic - it should be unique
selector:
text:
multiple: false
multiline: false
default: calendar_notifier
calendar:
name: Calendar with schedule
description: Select one or more calendars to monitor
default: []
selector:
entity:
domain: calendar
multiple: true
hours_before:
name: Number of Hours before Event
description: Number of hours to start notify before actual event
selector:
number:
max: 96.0
min: 0.0
unit_of_measurement: hours
mode: box
step: 1.0
default: 15
default_icon:
name: A default icon name
description: A default icon name to use for calendar events. Default - empty.
default: ""
duration:
name: Duration (in seconds)
description: Sets how long the app or notification should be displayed.
default: "10"
lifetime:
name: Lifetime of the app (in seconds)
description:
Removes the custom app when there is no update after the given
time in seconds. Keep this value higher than 59 seconds to get the AWTRIX
app automatically deleted when disabling the automation.
default: "70"
push_icon:
name: Icon Mode
description:
"Please select the pushIcon setting for the icon\n\n - `0` Icon
doesn't move\n\n - `1` Icon moves with text and will not appear again\n\n
\ - `2` Icon moves with text but appears again when the text starts to scroll
again\n"
selector:
select:
options:
- label: Icon doesn't move (default)
value: "0"
- label: Icon moves with text and will not appear again
value: "1"
- label:
Icon moves with text but appears again when the text starts to
scroll again
value: "2"
custom_value: false
multiple: false
sort: false
source_url: https://raw.githubusercontent.com/Brunas/HomeAssistant/master/blueprints/automation/awtrix_calendar_notifier.yaml
mode: single
variables:
device_ids: !input awtrix
app_name: !input app_name
devices_topics: "{%- macro get_device_topic(device_id) -%}
{%- set topic_entities = device_entities(device_id) | select('search','device_topic') | list -%}
{%- if topic_entities | length > 0 -%}
{{- states(topic_entities[0]) -}}
{%- endif -%}
{%- endmacro -%}
{%- set ns = namespace(devices=[]) -%}
{%- for device_id in device_ids -%}
{%- set device = get_device_topic(device_id) | replace(' ','') -%}
{%- if device -%}
{%- set ns.devices = ns.devices + [device] -%}
{%- endif -%}
{%- endfor -%}
{{- ns.devices | reject('match','unavailable') | list -}}"
calendar: !input calendar
hours_before: !input hours_before
default_icon: !input default_icon
duration: !input duration
lifetime: !input lifetime
push_icon: !input push_icon
trigger:
- platform: time_pattern
minutes: /5
- platform: homeassistant
event: start
condition: []
action:
- repeat:
for_each: "{{ calendar }}"
sequence:
- variables:
calendar_entity: "{{ repeat.item }}"
calendar_index: "{{ repeat.index }}"
- service: calendar.get_events
target:
entity_id: "{{ calendar_entity }}"
data:
start_date_time: "{{ now() }}"
duration:
hours: "{{ hours_before }}"
response_variable: agenda
- repeat:
for_each: "{{ agenda[calendar_entity].events }}"
sequence:
- variables:
event_start_str: "{{ repeat.item.start }}"
event_summary: "{{ repeat.item.summary }}"
is_all_day: "{{ repeat.item.all_day | default(false) or ('T' not in repeat.item.start) }}"
icon: >-
{%- set event_start = as_datetime(repeat.item.start) %}
{%- set day_of_month = event_start.day %}
{%- if day_of_month == 1 %}11543
{%- elif day_of_month == 2 %}11544
{%- elif day_of_month == 3 %}11545
{%- elif day_of_month == 4 %}11546
{%- elif day_of_month == 5 %}11547
{%- elif day_of_month == 6 %}11548
{%- elif day_of_month == 7 %}11549
{%- elif day_of_month == 8 %}11572
{%- elif day_of_month == 9 %}11550
{%- elif day_of_month == 10 %}11551
{%- elif day_of_month == 11 %}11552
{%- elif day_of_month == 12 %}11553
{%- elif day_of_month == 13 %}11554
{%- elif day_of_month == 14 %}11555
{%- elif day_of_month == 15 %}11556
{%- elif day_of_month == 16 %}11557
{%- elif day_of_month == 17 %}11558
{%- elif day_of_month == 18 %}11542
{%- elif day_of_month == 19 %}11559
{%- elif day_of_month == 20 %}11560
{%- elif day_of_month == 21 %}11561
{%- elif day_of_month == 22 %}11562
{%- elif day_of_month == 23 %}11563
{%- elif day_of_month == 24 %}11564
{%- elif day_of_month == 25 %}11565
{%- elif day_of_month == 26 %}11566
{%- elif day_of_month == 27 %}11567
{%- elif day_of_month == 28 %}11568
{%- elif day_of_month == 29 %}11569
{%- elif day_of_month == 30 %}11570
{%- elif day_of_month == 31 %}11571
{%- else %}{{ default_icon }}
{%- endif %}
processed_message: >-
{%- set year_matches = event_summary | regex_findall('\\b(19\\d{2}|20\\d{2})\\b') %}
{%- if year_matches | length > 0 %}
{%- set birth_year = year_matches[0] | int %}
{%- set current_year = now().year %}
{%- set age = current_year - birth_year %}
{{- event_summary | regex_replace('\\b(19\\d{2}|20\\d{2})\\b', age | string) }}
{%- else %}
{{- event_summary }}
{%- endif %}
event_text: >-
{%- if is_all_day %}
{{- processed_message }}
{%- else %}
{%- set event_start = as_datetime(repeat.item.start) %}
{{- event_start.strftime('%H:%M') }} {{ processed_message }}
{%- endif %}
app_topic: "{{ app_name }}_cal{{ calendar_index }}_{{ repeat.index }}"
- choose:
- conditions: "{{ devices_topics | length > 0 }}"
sequence:
- repeat:
for_each: "{{ devices_topics }}"
sequence:
- service: mqtt.publish
data:
qos: 0
retain: false
topic: "{{ repeat.item }}/custom/{{ app_topic }}"
payload: >-
{"icon":"{{ icon }}",
"text":"{{ event_text }}",
"pushIcon":"{{ push_icon }}",
"repeat":1,"textCase":2,"textOffset":33,"duration":{{ duration }},"lifetime":{{ lifetime }}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment