Workday/Holiday Exclude/Exemption

Happy Indigenous Peoples Day (ex: Columbus Day)!

This morning, I found that the workday sensor believed our office was on holiday, because the second Monday of October is a holiday in our region. However, unless you’re a US bank, your office is probably still in operation today. I also found that there wasn’t an easy way to exempt a holiday from the workday sensor. So I had to build a template in the condition that unlocks/locks our office door. Hopefully this will help someone else who runs across this problem. The python holiday code is really nice otherwise.

  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: switch.front_door_maglock_power
        state: 'on'
      - condition: or
        conditions:
          - condition: state
            entity_id: binary_sensor.workday
            state: 'on'
          # Indigenous People's Day, still a workday
          - condition: template
            value_template:
              "{{ now().weekday() == 0 and now().day > 7 and now().day < 15 and now().month == 10 }}"
1 Like

One of my biggest complaints about the workday sensor is the fact that you have to restart HA every time you add/remove a holiday. Plus, as you said, excluding holidays is a pain.

I have this type of thing coded into NodeRed as well using the Calendarifc API (https://calendarific.com/api-documentation) that I can single out holidays for and then set a global var to true/false based upon that.

Well done and I think I’ll incorporate your logic into a couple of my automations.

1 Like

I’ve since moved this to its own binary_sensor to make things simpler in multiple automations.

binary_sensor:
  - platform: workday
    name: python_workday
    country: 'US'
    province: 'UT'

  - platform: template
    sensors:
      workday:
        value_template: >-
           {{ is_state('binary_sensor.python_workday', 'on')
             or (now().weekday() == 0 and now().day > 14 and now().day < 22 and now().month == 1)
             or (now().weekday() == 0 and now().day > 7 and now().day < 15 and now().month == 10)
             or (now().weekday() < 5 and now().day == 11 and now().month == 11) }}
  # Holidays that are not office closings
  # MLK day
  # Indigenous Peoples' Day
  # Veterans Day

This continues to evolve. Needed something for the day after Thanksgiving, which is not a holiday in my state, but is also not a workday for my office.

binary_sensor:
  - platform: workday
    name: python_workday
    country: 'US'
    province: 'UT'
  
  - platform: template
    sensors:
      workday:
        value_template: >-
          {# MLK day, office open #}
          {% if now().weekday() == 0 and now().day > 14 and now().day < 22 and now().month == 1 %}
            {{ true }}
          {# Indigenous Peoples' Day, office open #}
          {% elif now().weekday() == 0 and now().day > 7 and now().day < 15 and now().month == 10 %}
            {{ true }}
          {# Veterans' Day, office open #}
          {% elif now().weekday() < 5 and now().day == 11 and now().month == 11 %}
            {{ true }}
          {# Day after Thanksgiving, office closed #}
          {% elif now().weekday() == 4 and now().day > 22 and now().day < 30 and now().month == 11 %}
            {{ false }}
          {# Python holiday via workday sensor #}
          {% elif is_state('binary_sensor.python_workday', 'on') %}
            {{ true }}
          {%- endif %}

Personally I created just a regular sensor, suppose it could be a binary_sensor as well…

    date_workday:
      value_template: >
        {% set ct = states('sensor.date_time') %}
        {% set ct = as_timestamp(strptime(ct,'%Y-%m-%d, %H:%M')) %}
        {% set date = states('sensor.date') %}
        {% set holidays = {
        '2020-01-01' : '1',
        '2020-05-25' : '1',
        '2020-07-03' : '1',
        '2020-09-07' : '1',
        '2020-11-26' : '1',
        '2020-12-24' : '1',
        '2020-12-25' : '1'} %}
        {% if 'Saturday' in ct | timestamp_custom("%A") %}
          off
        {% elif 'Sunday' in ct | timestamp_custom("%A") %}
          off
        {% elif holidays[date] == '1' %}
          off
        {% else %}
          on
        {% endif %}

Still needs a restart to update dates, but I like the cleanliness of the array for adding new dates.

It’s even cleaner with the add_holidays attribute of the workday binary_sensor; see https://www.home-assistant.io/integrations/workday/ and the standard holidays are already in there, so they don’t need yearly updating for new year and christmas like yours.

Yes and no.

The holidays that are added with add_holidays are not necessarily days that our office is OPEN / CLOSED - which is the point of my sensor - to know specifically if it’s a workday or not. Would be bad for my office to not have the coffee maker turn on for Columbus Day or one of the non-out-of-the-office holidays… :wink:

Add/remove_holidays doesn’t work on “3rd Thursday of November”. Those dates would have to be looked up and the sensor regularly maintained.

Yes; I think your solution is an elegant addition to it. I was just pointing out to Markus that the add_holidays parameter is a more elegant way to add non-standard holidays, and would also handle some of the hardcoded holidays he added for 2020 on a yearly basis, needing less maintenance.

I’m not sure I’m following Markus99’s counterpoint - seems like remove_holidays would handle the days where he wants the office to be open?

1 Like