-
-
Save bruxy70/b55acd9d69de4b8d8880f63e6dcb44cd to your computer and use it in GitHub Desktop.
blueprint: | |
name: Create Calendar Events with Offset Holidays in Week | |
description: Copy Events (in the next 365 days) from one local calendar to another. Look | |
in the holidays calendar and shift events for each public holiday in the week | |
before the event. | |
domain: script | |
source_url: https://gist.github.com/bruxy70/b55acd9d69de4b8d8880f63e6dcb44cd | |
input: {} | |
fields: | |
source_calendar: | |
name: Source calendar | |
description: Calendar with the events to be copied from | |
required: true | |
selector: | |
entity: | |
filter: | |
integration: local_calendar | |
destination_calendar: | |
name: Destination calendar | |
description: Calendar for the events to be copied to | |
required: true | |
selector: | |
entity: | |
filter: | |
integration: local_calendar | |
public_holidays: | |
name: Public Holidays | |
description: Calendar with the public holidays to be avoided | |
required: true | |
selector: | |
entity: | |
filter: | |
integration: holidays | |
sequence: | |
- service: calendar.get_events | |
data: | |
duration: | |
days: 365 | |
target: | |
entity_id: '{{ source_calendar }}' | |
response_variable: source | |
- service: calendar.get_events | |
data: | |
duration: | |
days: 365 | |
target: | |
entity_id: '{{ destination_calendar }}' | |
response_variable: destination | |
- service: calendar.get_events | |
data: | |
duration: | |
days: 365 | |
target: | |
entity_id: '{{ public_holidays }}' | |
response_variable: holidays | |
- variables: | |
holiday_dates: |- | |
{%- set ns = namespace(dates={}) %} | |
{%- if holidays[public_holidays]["events"] %} | |
{%- for event in holidays[public_holidays]["events"] %} | |
{%- set ns.dates = dict(ns.dates, **{event.start:event.summary}) %} | |
{%- endfor %} | |
{%- endif %} | |
{{ ns.dates}} | |
destination_dates: |- | |
{%- set ns = namespace(dates={}) %} | |
{%- if destination[destination_calendar]["events"]%} | |
{%- for event in destination[destination_calendar]["events"] %} | |
{%- set ns.dates = dict(ns.dates, **{event.start:event.summary}) %} | |
{%- endfor %} | |
{%- endif %} | |
{{ ns.dates}} | |
- repeat: | |
for_each: '{{ source[source_calendar]["events"] }}' | |
sequence: | |
- variables: | |
offset: >- | |
{%- set ns = namespace(offset=0,in_week=False,found=False) %} | |
{%- set collection_date = strptime(repeat.item.start,"%Y-%m-%d").date() %} | |
{%- for i in range(collection_date.weekday()+1) %} | |
{%- set d = ( collection_date + timedelta( days=-i) ).isoformat() %} | |
{%- if d in holiday_dates %} | |
{%- set ns.in_week = true %} | |
{%- set ns.offset = ns.offset + 1 %} | |
{%- endif %} | |
{%- endfor %} | |
{%- if ns.in_week %} | |
{# Increase offset until we find a date that is not public holiday #} | |
{%- for _ in range(7) if not ns.found %} | |
{%- set start = strptime(repeat.item.start,"%Y-%m-%d").date() %} | |
{%- set d = ( start + timedelta( days=ns.offset) ).isoformat() %} | |
{%- if d in holiday_dates %} | |
{%- set ns.offset = ns.offset + 1 %} | |
{% else %} | |
{%- set ns.found = true %} | |
{%- endif %} | |
{% endfor %} | |
{%- endif %} | |
{{ ns.offset }} | |
start_date: >- | |
{%- set start = strptime(repeat.item.start,"%Y-%m-%d").date() %} | |
{{ (start + timedelta(days=offset)).isoformat() }} | |
end_date: >- | |
{%- set end = strptime(repeat.item.end,"%Y-%m-%d").date() %} | |
{{ (end + timedelta(days=offset)).isoformat() }} | |
summary: "{{ repeat.item.summary }}" | |
- if: | |
- condition: template | |
value_template: "{{ start_date not in destination_dates }}" | |
then: | |
- service: calendar.create_event | |
data: | |
summary: "{{ summary }}" | |
start_date: "{{ start_date }}" | |
end_date: " {{ end_date }}" | |
target: | |
entity_id: "{{ destination_calendar }}" | |
mode: single | |
icon: mdi:calendar-blank-multiple |
Hi. I have never used this actually. If you figure it out, feel free to send the corrected version, so I can fix it for the otherts.
Also, Holidays is becoming part of Home Assistant core in January, so there will be no point maintaining a custom integration with the same functionality. So it might be worth updating the scripts to work with the native integration.
I was able to modify the blueprint to get it to work, but it does require a hack that I am not happy with.
I replaced all list_event calls with get_event calls.
I then changed lines of code as follows:
- variables:
holiday_dates: |-
{%- set ns = namespace(dates={}) %}
{%- if holidays["calendar.us_holidays"]["events"] %}
{%- for event in holidays["calendar.us_holidays"]["events"] %}
{%- set ns.dates = dict(ns.dates, **{event.start:event.summary}) %}
{%- endfor %}
{%- endif %}
{{ ns.dates}}
destination_dates: |-
{%- set ns = namespace(dates={}) %}
{%- if destination["calendar.trash_days_offset_for_holidays"]["events"]%}
{%- for event in destination["calendar.trash_days_offset_for_holidays"]["events"] %}
{%- set ns.dates = dict(ns.dates, **{event.start:event.summary}) %}
{%- endfor %}
{%- endif %}
{{ ns.dates}} - repeat:
for_each: '{{ source["calendar.trash_days"]["events"] }}'
in general, instead of say source.event, you now need to use: source["calendar.trash_days"]["events"]
The hack I used is I hard coded the calendar name in the blueprint (like above "calendar.trash_days". there should be a way to use the passed variable: "{{ source_calendar }}", "{{ destination_calendar }}" and "{{ public_holidays }}" which translated to the hardcoded calendars I used, but try as I might, I could not properly modify the code to work.
bruxy70, feel free to use the above to modify your blueprint if you wish, and if you obviously know how to use the proper variables, vs the hard coded values, that would make it a true blueprint again.
Okay. sorry, totally fixed. I learned that I was nesting templates.
the proper solutions for above is to do:
{%- for event in holidays[public_holidays]["events"] %}
{%- for event in destination[destination_calendar]["events"] %}
and
for_each: '{{ source[source_calendar]["events"] }}'
The full code which appears to be working now is below:
template above
`
blueprint:
name: Create Calendar Events with Offset Holidays in Week
description: Copy Events (in the next 365 days) from one local calendar to another. Look
in the holidays calendar and shift events for each public holiday in the week
before the event.
domain: script
source_url: https://gist.github.com/bruxy70/b55acd9d69de4b8d8880f63e6dcb44cd
input: {}
fields:
source_calendar:
name: Source calendar
description: Calendar with the events to be copied from
required: true
selector:
entity:
filter:
integration: local_calendar
destination_calendar:
name: Destination calendar
description: Calendar for the events to be copied to
required: true
selector:
entity:
filter:
integration: local_calendar
public_holidays:
name: Public Holidays
description: Calendar with the public holidays to be avoided
required: true
selector:
entity:
filter:
integration: holidays
sequence:
- service: calendar.get_events
data:
duration:
days: 365
target:
entity_id: '{{ source_calendar }}'
response_variable: source
- service: calendar.get_events
data:
duration:
days: 365
target:
entity_id: '{{ destination_calendar }}'
response_variable: destination
- service: calendar.get_events
data:
duration:
days: 365
target:
entity_id: '{{ public_holidays }}'
response_variable: holidays
- variables:
holiday_dates: |-
{%- set ns = namespace(dates={}) %}
{%- if holidays[public_holidays]["events"] %}
{%- for event in holidays[public_holidays]["events"] %}
{%- set ns.dates = dict(ns.dates, **{event.start:event.summary}) %}
{%- endfor %}
{%- endif %}
{{ ns.dates}}
destination_dates: |-
{%- set ns = namespace(dates={}) %}
{%- if destination[destination_calendar]["events"]%}
{%- for event in destination[destination_calendar]["events"] %}
{%- set ns.dates = dict(ns.dates, **{event.start:event.summary}) %}
{%- endfor %}
{%- endif %}
{{ ns.dates}}
- repeat:
for_each: '{{ source[source_calendar]["events"] }}'
sequence:
- variables:
offset: >-
{%- set ns = namespace(offset=0,in_week=False,found=False) %}
{%- set collection_date = strptime(repeat.item.start,"%Y-%m-%d").date() %}
{%- for i in range(collection_date.weekday()+1) %}
{%- set d = ( collection_date + timedelta( days=-i) ).isoformat() %}
{%- if d in holiday_dates %}
{%- set ns.in_week = true %}
{%- set ns.offset = ns.offset + 1 %}
{%- endif %}
{%- endfor %}
{%- if ns.in_week %}
{# Increase offset until we find a date that is not public holiday #}
{%- for _ in range(7) if not ns.found %}
{%- set start = strptime(repeat.item.start,"%Y-%m-%d").date() %}
{%- set d = ( start + timedelta( days=ns.offset) ).isoformat() %}
{%- if d in holiday_dates %}
{%- set ns.offset = ns.offset + 1 %}
{% else %}
{%- set ns.found = true %}
{%- endif %}
{% endfor %}
{%- endif %}
{{ ns.offset }}
start_date: >-
{%- set start = strptime(repeat.item.start,"%Y-%m-%d").date() %}
{{ (start + timedelta(days=offset)).isoformat() }}
end_date: >-
{%- set end = strptime(repeat.item.end,"%Y-%m-%d").date() %}
{{ (end + timedelta(days=offset)).isoformat() }}
summary: "{{ repeat.item.summary }}"
- if:
- condition: template
value_template: "{{ start_date not in destination_dates }}"
then:
- service: calendar.create_event
data:
summary: "{{ summary }}"
start_date: "{{ start_date }}"
end_date: " {{ end_date }}"
target:
entity_id: "{{ destination_calendar }}"
mode: single
icon: mdi:calendar-blank-multiple
`
Thanks for this contribution, I have updated the blueprint to this.
Hi. I love your blueprint and am using it to load a holiday calendar to shift my trash day. I have it set up to run on the first of the year (which it just did), and I just got an error message:
I'm going to look to see if I can fix the blueprint for my own use, but wanted to put it out there so if you are still managing the blueprint you may want to address