Calling all template gurus | Towel rail automation linked to Season

I’m looking to tidy up my towel rail automations that leverage a Shelly 1 to turn the towels rails on and off twice a day for 4hrs.

What I’d like to do is have them linked to my Season sensor so that in Winter and Autumn they run for 6hrs twice daily and in Summer and Spring, 4hrs. Can anyone advise the best way of going about that? My current code is this:

## Turn on and off towel rails ##
  - alias: 'Turn on ensuite towel rail twice a day'
    initial_state: true
    hide_entity: false
    trigger:
      - platform: time
        at: '06:00:00'
      - platform: time
        at: '18:00:00'
    action:
      - service: switch.turn_on
        entity_id: switch.ensuite_towel_rail

  - alias: 'Turn on bathroom towel rail twice a day'
    initial_state: true
    hide_entity: false
    trigger:
      - platform: time
        at: '06:00:00'
      - platform: time
        at: '18:00:00'
    action:
      - service: switch.turn_on
        entity_id: switch.bathroom_towel_rail

  - alias: 'Turn off towel rails twice a day'
    initial_state: true
    hide_entity: true
    trigger:
      - platform: time
        at: '10:00:00'
      - platform: time
        at: '22:00:00'
    action:
      - service: switch.turn_off
        entity_id:
          - switch.ensuite_towel_rail
          - switch.bathroom_towel_rail

N.B I have the turn on automations separate so that I can turn off automations for our ensuite towel rail when we are on holiday. Other one is always on as we have house sitters.

I’d do the turn on the same but also start a timer to trigger the off automation. The length of time can be templated depending on the season.

  - alias: 'Turn on bathroom towel rail twice a day'
    initial_state: true
    hide_entity: false
    trigger:
      - platform: time
        at: '06:00:00'
      - platform: time
        at: '18:00:00'
    action:
      - service: switch.turn_on
        entity_id: switch.bathroom_towel_rail
      - service: timer start
        data_template:
          entity_id: timer.towl_rail ### <- you need to create this (see below)
          duration: >
            {% if states('sensor.season') == 'winter' %}
              06:00:00
            {% else %}
              04:00:00
            {% endif %}
  - alias: 'Turn off towel rails twice a day'
    initial_state: true
    hide_entity: true
    trigger:
      - platform: event
        event_type: timer.finished
        event_data:
          entity_id: timer.towl_rail
    action:
      - service: switch.turn_off
        entity_id:
          - switch.ensuite_towel_rail
          - switch.bathroom_towel_rail

How to create a timer:

Note the template used for the timer duration will set 6 hours for winter and 4 hours for every other season. If you are not disabling this automation in spring and summer you might want to add a shorter duration for these seasons in the template.

        data_template:
          entity_id: timer.towl_rail 
          duration: >
            {% if states('sensor.season') == 'winter' %}
              06:00:00
            {% if states('sensor.season') == 'autumn' %}
              04:00:00
            {% else %}
              00:30:00
            {% endif %}

Thank you. This was fast and awesome! If possible, I’d like to try and steer away from timers as they are not persistent through HA restarts and as I do a heck of a lot of those, I’ll likely to screw a timer on any given day. Is there a way to do it by programming a variable end time?

It is possible to set datetime objects in the template but that get’s a but trickier (template triggers for the off time automations) . Unfortunately I’m out of time and need to go but if you haven’t received a satisfactory answer from someone else I’ll have a go when I get home tonight.

There’s probably an easier way to do this and I’d be interested too but this is how I currently do similar things.

Create an input_datetime with time only. A date could complicate things if set for an on time of 6 hours at 6pm. https://www.home-assistant.io/components/input_datetime/ Let’s call it towel_rail_off_time.

Your on time automation looks like this:

  - alias: 'Turn on bathroom towel rail twice a day'
    initial_state: true
    hide_entity: false
    trigger:
      - platform: time
        at: '06:00:00'
      - platform: time
        at: '18:00:00'
    action:
      - service: switch.turn_on
        entity_id: switch.bathroom_towel_rail
      - service: input_datetime.set_datetime ###  Set the off time based on season and time triggered
        entity_id: input_datetime.towel_rail_off_time
        data_template:
          time: >
            {% if now().hour == 6 }}
              {% if states('sensor.season') == 'winter' %}
                12:00:00
              {% else %}
                10:00:00
              {% endif %}
            {% else %}
              {% if states('sensor.season') == 'winter' %}
                00:00:00
              {% else %}
                22:00:00
              {% endif %}
            {% endif %}

For the off timer you need to check the current time against the off datetime. Creating a template binary sensor may seem like an extra step but it helps immensely with debugging if something is not working. You can see instantly if the towel heater should be off without having to use the template editor.

binary sensor:

- platform: template
  sensors:
    towel_heater_off:
      friendly_name: Towel Heater Off
      entity_id:
      - input_datetime.towel_rail_off_time  ### if you manually change the off time this sensor will also update!
      - sensor.time ### required to update now(), hopefully you already have this sensor if not, make it
      value_template: >-
        {% set d = now().strftime("%Y-%m-%d ") %}
        {% set t = now().timestamp() %}
        {% set heat_end = strptime(d + states('input_datetime.towel_rail_off_time'), '%Y-%m-%d %H:%M:%S').timestamp() %}
        {{ t >= heat_end }}

Off automation:

  - alias: 'Turn off towel rails twice a day'
    initial_state: true
    hide_entity: true
    trigger:
      - platform: state
        entity_id: binary_sensor.towel_heater_off
        to: 'on'
    action:
      - service: switch.turn_off
        entity_id:
          - switch.ensuite_towel_rail
          - switch.bathroom_towel_rail
1 Like

Here’s another possible solution. It uses your three existing automations and adds a fourth one.

  1. Keep your two existing automations to turn on the towel rails.
  2. Add a condition to your existing automation that turns off the towel rails. It will check if it is spring or summer
  3. Add an automation to turn off the towel rails if it is autumn or winter.

Here’s your turn-off automation with an added condition for spring and summer:

  - alias: 'Turn off towel rails twice a day in spring or summer'
    initial_state: true
    hide_entity: true
    trigger:
      - platform: time
        at: '10:00:00'
      - platform: time
        at: '22:00:00'
    condition:
      condition: template
      value_template: >-
        {% set season = states('sensor.season') %}
        {{ season == 'spring' or season == 'summer' }}
    action:
      - service: switch.turn_off
        entity_id:
          - switch.ensuite_towel_rail
          - switch.bathroom_towel_rail

Here’s the automation to turn off the towel rails in autumn and winter:

  - alias: 'Turn off towel rails twice a day in autumn or winter'
    initial_state: true
    hide_entity: true
    trigger:
      - platform: time
        at: '12:00:00'
      - platform: time
        at: '00:00:00'
    condition:
      condition: template
      value_template: >-
        {% set season = states('sensor.season') %}
        {{ season == 'autumn' or season == 'winter' }}
    action:
      - service: switch.turn_off
        entity_id:
          - switch.ensuite_towel_rail
          - switch.bathroom_towel_rail
2 Likes

Go with 123’s solution. I completely misread this:

I did it for 6 hours in winter and 4hours for the rest.

@tom_l and @123 Thank you so much! That is some serious Ninja stuff I’d never be able to figure out on my own. Very late in NZ so I’ll give that a go in the morning and report back. :grinning: