Automating Holidays with Home Assistant

The Problem

Home Assistant can tell you if it's Thanksgiving if you have a calendar plugin configured with Thanksgiving scheduled. But the included Calendar plugin doesn't have that pre-scheduled, and what if you don't want to use a Cloud calendar service? The date sensor isn't very good with date math, and getting "Thanksgiving" to a date is difficult because it's not a fixed day.

The Solution

Template Sensors and Date Math

I found most of this on the Home Assistant Forums, but I've lost the link. 

The YAML to the left will set a "holiday-season" sensor's state to "christmas" between the day after Thanksgiving and Jan 5th.

It'll set the state to "halloween" in October.

Otherwise it sets the state to "none". Simple enough.

- trigger:

  - platform: time_pattern

    # This will update every night

    hours: '0'

    minutes: '0'

  - platform: event

    event_type: event_template_reloaded

  - platform: homeassistant

    event: start

  sensor:

    - name: "holiday-season"

      state: >

        {%- set today = now().date() -%}

        {%- set month, week, day = 11, 4, 3 -%}

        {%- set temp = today.replace(month=month, day=1) -%}

        {%- set adjust = (day - temp.weekday()) % 7 -%}

        {%- set temp = temp + timedelta(days=adjust) -%}

        {%- set thanksgiving = temp + timedelta(weeks = week - 1) -%}

        {%- set jan6th = temp.replace(month=1, day=6) -%}

        {% if today <= jan6th or today > thanksgiving -%}

          {%- set season = "christmas" -%}

          christmas

        {%- elif today.month == 10 -%}

          {%- set season = "halloween" -%}

          halloween

        {%- else -%}

          {%- set season = "none" -%}

          none

        {%- endif -%}

Example Use-Cases

Dashboards

Using the Card Mod plugin, you can style dashboard cards and use this sensor to change your themes.

How this works in the Lovelace dashboard

type: markdown

content: |-

  ## Holiday Mode

  {% set season = states('sensor.holiday_season') %}

  {% if season == 'christmas' %}

  ### 🎄🎅❄ Christmas ❄🎅🎄

  {% elif season == 'halloween' %}

  ### 🦇🎃👻 Halloween 👻🎃🦇

  {% else %}

  ### 🗿🌴🍹 Default 🍹🌴🗿

  {% endif %}

card_mod:

  style: |

    ha-card {

    {% set season = states('sensor.holiday_season') %}

    {% if season == 'christmas' %}

      background-color: #0F8A5F;

      background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 50 50' style='enable-background:new 0 0 50 50%3B' xml:space='preserve'%3E%3Cstyle type='text/css'%3E.st1%7Bopacity:0.3%3Bfill:%23FFFFFF%3B%7D.st3%7Bopacity:0.1%3Bfill:%23FFFFFF%3B%7D%3C/style%3E%3Ccircle class='st1' cx='5' cy='8' r='1'/%3E%3Ccircle class='st1' cx='38' cy='3' r='1'/%3E%3Ccircle class='st1' cx='12' cy='4' r='1'/%3E%3Ccircle class='st1' cx='16' cy='16' r='1'/%3E%3Ccircle class='st1' cx='47' cy='46' r='1'/%3E%3Ccircle class='st1' cx='32' cy='10' r='1'/%3E%3Ccircle class='st1' cx='3' cy='46' r='1'/%3E%3Ccircle class='st1' cx='45' cy='13' r='1'/%3E%3Ccircle class='st1' cx='10' cy='28' r='1'/%3E%3Ccircle class='st1' cx='22' cy='35' r='1'/%3E%3Ccircle class='st1' cx='3' cy='21' r='1'/%3E%3Ccircle class='st1' cx='26' cy='20' r='1'/%3E%3Ccircle class='st1' cx='30' cy='45' r='1'/%3E%3Ccircle class='st1' cx='15' cy='45' r='1'/%3E%3Ccircle class='st1' cx='34' cy='36' r='1'/%3E%3Ccircle class='st1' cx='41' cy='32' r='1'/%3E%3C/svg%3E");

      animation: animatedBackground 10s linear infinite;

    }

    @keyframes animatedBackground {

      0% {

        background-position: 0 0;

      }

      100% {

        background-position: 0px 300px;

      }

    }

    {%elif season == 'halloween' %}

      // color: black;

      //background-color: #E66B09;

      overflow: hidden;

      background: linear-gradient(0deg, #000000 15%, #E66B09 98%, #000000 0%);

    }

    {% endif %}


Selecting a Scene

Using scenes whenever possible, rather than trying to capture everything manually is the best way to handle lighting and switches and such. In this case, rather than activating a scene, trigger an automation that activates the appropriate scene.

This also works for playlists, videos, whatever.

YAML version

alias: Activate Default Bar Scene

sequence:

  - choose:

      - conditions:

          - condition: state

            entity_id: sensor.holiday_season

            state: christmas

        sequence:

          - service: scene.turn_on

            target:

              entity_id: scene.bsow_bar_christmas_scene

            metadata: {}

      - conditions:

          - condition: state

            entity_id: sensor.holiday_season

            state: halloween

        sequence:

          - service: scene.turn_on

            target:

              entity_id: scene.bsow_bar_halloween_scene

            metadata: {}

    default:

      - service: scene.turn_on

        target:

          entity_id: scene.bsow_bar_default_scene

        metadata: {}

mode: single

icon: mdi:palette-swatch-variant