Help with Calendar template sensor

Hi, I’m trying to create individual custom:button-card for calendar events, so far i use the following template to gather the attributes from my various google calendar entities

- trigger:
    - platform: time_pattern
      minutes: /15
    - platform: homeassistant
      event: start
  action:
  - action: calendar.get_events
    target:
      entity_id:
        - calendar.my_calendar_1
        - calendar.my_calendar_2
        - calendar.my_calendar_3
        - calendar.my_calendar_4
        - calendar.my_calendar_5
    data:
      duration:
        days: 30
    response_variable: calendar_events
  sensor:
  - name: Upcoming Calendar Events
    unique_id: 43c6bde9-1758-1227-b156-093ee61c4222
    icon: mdi:calendar
    state: >
      {{
        calendar_events.values()
        | map(attribute='events')
        | map('count')
        | sum
      }}
    attributes:
      events: >
        {{
          calendar_events.values()
          | map(attribute='events')
          | sum(start=[])
          | sort(attribute='start')
        }}

This works great and i’ve created a custom:button-card with the date number in a circle container to the left of the event name and time.

What i’m trying to do now is colour the circle container in the custom:button-card based on the calendar the event has come from, but i can’t find a way to change my template sensor above to also collect the calendar the event has come from for each state attribute.

I currently get these attributes from the above sensor

 - start: "2025-12-02T08:00:00+00:00"
    end: "2025-12-02T16:00:00+00:00"
    summary: Car MOT and Service

but what i’d like to include is

- start: "2025-12-02T08:00:00+00:00"
    end: "2025-12-02T16:00:00+00:00"
    summary: Car MOT and Service
    calendar: calendar.my_calendar_1

That way i cal dynamically colour the button card based on this.

does anybody know a way to gather this in a teamplate?

I previously used Calendar Card Pro Hacs which could do this but I want to create my own with custom:button-card

I hope somebody can help

Cheers

Use the merge_response function.

This will provide the calendar entity ID for each event as the value for the key “entity_id”.

- trigger:
    - platform: time_pattern
      minutes: /15
    - platform: homeassistant
      event: start
  action:
  - action: calendar.get_events
    target:
      entity_id:
        - calendar.my_calendar_1
        - calendar.my_calendar_2
        - calendar.my_calendar_3
        - calendar.my_calendar_4
        - calendar.my_calendar_5
    data:
      duration:
        days: 30
    response_variable: calendar_events
  - variables:
      merged: "{{ merge_response(calendar_events) | sort(attribute='start') | list }}"
  sensor:
  - name: Upcoming Calendar Events
    unique_id: 43c6bde9-1758-1227-b156-093ee61c4222
    icon: mdi:calendar
    state: "{{ merged | count }}"
    attributes:
      events: "{{ merged }}"
1 Like

Thank you so much, this appears to work great. I spent 3 hours going round in circles with chatgpt suggesting things that didn’t work. now i just need to continue styling my custom:button-card, thanks for the quick reply.

If anyone is at all interested this is where i’ve got to so far with the card, the coding is a bit messy as it’s a mix of what i’ve found and what chatgpt provided. when i get something i finally like the look of i plan to create a button card template to reduce the repitition throughout my yaml.

- type: conditional
            conditions:
              - condition: numeric_state
                entity: sensor.upcoming_calendar_events
                above: 1
            card:
              type: custom:button-card
              entity: sensor.upcoming_calendar_events
              show_icon: false
              show_name: false
              styles:
                card:
                  - padding-left: 14px
                  - padding-top: 14px
                  - padding-right: 14px
                  - padding-bottom: 14px
                  - margin: 0px
                  - position: relative
                grid:
                  - grid-template-areas: '"date event" "date time"'
                  - grid-template-columns: 42px 1fr
                  - grid-auto-rows: min-content
                  - row-gap: 0px
                custom_fields:
                  date:
                    - position: absolute
                    - left: 14px
                    - top: 50%
                    - transform: translateY(-50%)
                    - width: 42px
                    - height: 42px
                    - border-radius: 50%
                    - display: flex
                    - justify-content: center
                    - align-items: center
                    - font-size: 18px
                    - font-weight: 600
                    - color: white
                    - box-sizing: border-box
                    - z-index: 2
                    - background-color: |
                        [[[
                          // Map of calendars → colors
                          const colorMap = {
                            "calendar.my_calendar_1": "#016795",
                            "calendar.my_calendar_2": "#8a9a5b",
                            "calendar.my_calendar_3": "#6f2da8",
                            "calendar.my_calendar_4": "#ffb7c5",
                            "calendar.my_calendar_5": "#ffe135"
                          };

                          const event = entity.attributes.events[1];

                          // Depending on integration, the attribute may be:
                          // event.calendar_id, event.entity_id, or event.source
                          // Try to match all possibilities safely:

                          const cal =
                            event.calendar_id ||
                            event.entity_id ||
                            event.source ||
                            "";

                          return colorMap[cal] || "var(--primary-color)";
                        ]]]
                  event:
                    - justify-self: start
                    - align-self: start
                    - padding-left: 12px
                    - font-size: 15px
                    - font-weight: 500
                    - text-align: left
                  time:
                    - justify-self: start
                    - font-size: 13px
                    - padding-left: 12px
              custom_fields:
                date: |
                  [[[
                    const d = new Date(entity.attributes.events[1].start);
                    return d.getDate();   // circle displays only day number
                  ]]]
                event: |
                  [[[
                    return entity.attributes.events[1].summary
                  ]]]
                time: |
                  [[[
                    const event = entity.attributes.events[1];
                    const start = new Date(event.start);
                    const end = event.end ? new Date(event.end) : null;

                    const isAllDay =
                      event.all_day ||
                      (start.getHours() === 0 && start.getMinutes() === 0 &&
                       end && end.getHours() === 0 && end.getMinutes() === 0);

                    if (isAllDay) return "All day";
                    if (start && end)
                      return `${helpers.formatTime24h(event.start)} - ${helpers.formatTime24h(event.end)}`;
                    if (start)
                      return helpers.formatTime24h(event.start);

                    return "";
                  ]]]

and this is what it currently looks like, just needs a bit more styling and i may remove the background to the card

Screenshot 2025-11-17 211747