Workday sensor - remove_holiday not working

That is exactly what I am looking for. Thank you everyone for all your help.

Yeah, but I think he wanted to maybe turn on Saturday or Sunday. By he I meant @Markus99 not OP.

I have same problem with “remove_holidays”.
I will add new binary sensor for fixing this bug.

Seems adding remove_holidays with any valid non-holiday day causes the integration not to load and pukes an error:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 200, in _async_setup_platform
    await asyncio.shield(task)
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/src/homeassistant/homeassistant/components/workday/binary_sensor.py", line 105, in setup_platform
    obj_holidays.pop(date)
  File "/usr/local/lib/python3.8/site-packages/holidays/holiday_base.py", line 158, in pop
    return dict.pop(self, self.__keytransform__(key))
KeyError: datetime.date(2021, 3, 18)

Testing on latest version of HA OS, i might not have enough skills to pinpoint the exact problem but seems to have issues out of the box. Haven’t filed a bug yet or searched for an existing one.

I have same problem with “remove_holidays"…
version HA: 2021.2.3

@123 that works like a charm, thanks heaps for this.

Could this also be used to compare the current date with the list of holidays and return the next holiday?

For example, if I compare today (2021-04-22) with the holidays in the script, the return value should be 2021-05-31).
I want to display the next holiday on my lovelace dashboard :slight_smile:

Thank you

Try this:

sensor:
- platform: template
  sensors:
    next_holiday:
      friendly_name: 'Next Holiday'
      value_template: >
        {% set d = now().date()|string %}
        {% set holidays = ([
          '2021-01-01',
          '2021-05-31',
          '2021-07-05',
          '2021-09-06',
          '2021-11-25',
          '2021-12-23',
          '2021-12-24'] + [d]) | sort %}
        {% set i = holidays.index(d) %}
        {{ holidays[i+1] if i+1 <= holidays|count-1 else 'None' }}

Thanks @123
That works brilliant!

I created a second sensor to conver the output date, that works too (I’m pretty sure it could be done in one sensor but thats fine with me now. Where I’m struggliging though was to convert the days to local language - I saw your other post here where you explain this, but the value of the above next_holiday sensor does not have the .weekday() or .month() attribute, do you know how to translate the date from next_holiday to local named days and months?

  - platform: template
    sensors:
      next_holiday_formatted:
        friendly_name: "Next Holiday formatted"
        value_template: >
          {{ as_timestamp(states('sensor.next_holiday')) | timestamp_custom('%a, %d. %b') }}
        icon_template: mdi:calendar-clock

I do but I’ll leave it for you as an exercise to expand your templating skills.

HINT:

This converts a date string into a datetime object:

{% set d = now().fromtimestamp('2021-11-25' | as_timestamp) %}

From the datetime object you can get these day, month, and weekday values (integers) which can be used as index values to respective month and weekday lists (as demonstrated in the linked example you posted).

d.day
d.month
d.weekday()

Thanks heaps @123 , your hint did the trick.

Here is the code, if somebody is looking for it. What it does, it converts the above “Next Holiday” date into a local named date .

  1. you need the sensor above sensor.next_holiday and the second sensor below (sensor.next_holiday_formatted), format the date to your local language.

It could probably be done with one sensor only, but for me, this solution with two sensors is just fine :slight_smile:

  - platform: template
    sensors:
      next_holiday_formatted:
        friendly_name: "Next Holiday formatted"
        value_template: >
          {% set months = ["Jan.", "Feb.", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez."] %}
          {% set days = ["MO", "DI", "MI", "DO", "FR", "SA", "SO"]  %}
          {% set d = now().fromtimestamp(states('sensor.next_holiday') | as_timestamp) %}
          {{ d.timestamp() | timestamp_custom(days[d.weekday()] ~ ', %-d. ' + months[d.month-1]) }}
        icon_template: mdi:calendar-clock

Good work!

Be advised that if your sensor.next_holiday returns None (when there is no ‘next holiday’) your template will report an error:

TypeError: an integer is required (got type NoneType)

You should check the sensor’s value first and ensure it is not None before using it.


Here’s the all-in-one version:

sensor:
- platform: template
  sensors:
    next_holiday:
      friendly_name: 'Next Holiday'
      icon_template: mdi:calendar-clock
      value_template: >
        {% set months = ["", "Jan.", "Feb.", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez."] %}
        {% set days = ["MO", "DI", "MI", "DO", "FR", "SA", "SO"]  %}
        {% set d = now().date()|string %}
        {% set holidays = ([
          '2021-01-01',
          '2021-05-31',
          '2021-07-05',
          '2021-09-06',
          '2021-11-25',
          '2021-12-23',
          '2021-12-24'] + [d]) | sort %}
        {% set i = holidays.index(d) %}
        {% set h = holidays[i+1] if i+1 <= holidays|count-1 else '' %}
        {% if h != '' %}
          {% set d = now().fromtimestamp(as_timestamp(h)) %}
          {{ '{}, {}. {}'.format(days[d.weekday()], d.day, months[d.month]) }}
        {% else %}
          None
        {% endif %}

Thanks for the advice and the all-in-one-sensor, that is much more convenient.

I’m using the same array of holidays in another sensor (binary sensor). Is it possible to save such an array in a variable so that both sensors, the sensor and the binary sensor can access the same values? I would then not need to paste the values into two sensors every year.

Home Assistant currently doesn’t support native global variables.

There are at least two custom components available that attempt to create the equivalent of global variables (they store the variables in the state and attributes of an entity). Feel free to explore their capabilities:

FWIW, unless you have a need for many global variables, or wish to refer to the holiday list from far more than just two entities, it’s easier to just make a copy of the list.

For now, its just the two sensors where I need to c&p the list, so thats fine. If I find myself in need of more variables down the track, I’ll give these components a go. Thank you @123 !

This is really neat. Is it possible to set the holiday date without the year. For example, New Years Day is always YYYY-01-01. How would it be possible to create the Holiday to always be on 01-01 regardless of year?

binary_sensor:
- platform: template
  sensors:
    holiday:
      friendly_name: 'Holiday'
      value_template: >
        {% set holidays = [
          '01-01',
          '05-31',
          '07-05',
          '09-06',
          '11-25',
          '12-23',
          '12-24',
          '01-01'] %}
        {{ now().isoweekday() in [6, 7] or (now().date()|string)[-5:] in holidays }}
2 Likes

Incorrect, according to the documentation:
" One other thing to watch is how the holiday keyword is used. Your first instinct might be to add it to the exclude configuration, thinking that it means to skip the holidays. Actually it means to exclude the days in the holidays’ list from the workdays. So when you exclude holiday and a workday falls on that day, then that workday is excluded. Meaning the sensor will be off. If you want the workday flagged without regarding holidays, make sure that there is something in your Excludes configuration other than holiday ."

At the time of the post, that’s how it worked. I can’t comment on how it works now as I don’t use the integration.

Same with me, I started with it, was not much satisfied, stumbled on your above post, implemented it with satisfaction.

@JDogg016 @kolia
After 2 years, it was time for me again to update those string lists in the config to have the next holidays.
I found an easy way now to eliminate this manual step also. :slight_smile:

There is now a Holiday Sensor that you can configure, if you are lucky, your country is included too, you can also find it in HACS: GitHub - bruxy70/Holidays: 📅 Custom Home Assistant integration for public holidays - also used for garbage_collection integration to automatically move scheduled events that fall on a public holiday (by an automation blueprint)

It will create a helper, in this case “calendar.holidays”

Here is the config for the two sensors “Weekend & Holidays” and “Next Holiday with Locale Name”:

# Weekend and Holiday Sensor (will be ON on Saturday [6], Sunday [7] and all Holidays from the calendar.holidays helper
binary_sensor:
  - platform: template
    sensors:
      weekend_holiday:
        friendly_name: 'Wochenende & Feiertage'
        icon_template: mdi:palm-tree
        value_template: "{{ now().isoweekday() in [6, 7] or now().date()|string in state_attr('calendar.holidays', 'next_date')|string }}"
# Next Holiday with Locale Date-Name
sensor:
  - platform: template
    sensors:
      next_holiday:
        friendly_name: 'Nächster Feiertag'
        icon_template: mdi:calendar-clock
        value_template: >
          {% set months = ["", "Jan.", "Feb.", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez."] %}
          {% set days = ["MO", "DI", "MI", "DO", "FR", "SA", "SO"]  %}
          {% set nh = state_attr('calendar.holidays', 'next_date') %}
          {{ '{}, {}. {}'.format(days[nh.weekday()], nh.day, months[nh.month])}}

Cheers