Setting up multiple / complex automation

Hi

I am trying to create an automation to set the temperature of my TRV at a specific time and on certain days of week.

I have managed to get a simple automation working called “Heating Schedule 1” as follows:

At 06:00:00 on Mon-Fri set the temperature of the TRV to 25, and here’s the code (everything working as it should):

alias: Heating Schedule 1
description: ''
trigger:
  - platform: time
    at: '06:00:00'
condition:
  - condition: time
    weekday:
      - mon
      - tue
      - wed
      - thu
      - fri
action:
  - service: climate.set_temperature
    target:
      device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
    data:
      temperature: 25
mode: single

What I would like to do (if possible) is to add to this automation the following without having to set up multiple automation, i.e from within one automation do all the following:

At 06:00:00 on Mon-Fri set the temperature of the TRV to 25
At 09:00:00 on Mon-Fri set the temperature of the TRV to 15
At 15:00:00 on Mon-Fri set the temperature of the TRV to 20
At 18:00:00 on Mon-Fri set the temperature of the TRV to 22
At 22:00:00 on Mon-Fri set the temperature of the TRV to 18

Basically, I’m wanting to have a schedule to set all of the above from within one automation called “Heating Schedule 1” without having to make 5 individual automatons for 1 TRV because later on I am planning to have 2-3 different schedules (all with 5 set points) and assign specific TRVs in the house to these schedules depending on the room the TRV is in.

Thanks in advance for any help and guidance !!

I have a similar setup for my hot water tank. I have a schedule defined by input_datetime and input_number helpers, with separate workday and non-workday schedules (workday integration):

My single automation to manage the target value (which is also an input_number):

- alias: Hot water - tank target manager

  description: >-
    This automation updates the value of the tank target based on the values in the
    schedule. The action identifies which slot matches the current time, then sets
    the target to that slot's target value.

  id: 9ac52ecb-3e29-4474-b64b-9261ee9dce4e

  trigger:
    - platform: template
      value_template: >
          {{ (states('binary_sensor.workday_sensor') == 'off') and
             (states('sensor.time') in
             [states('input_datetime.wehw1_time')[0:5],
              states('input_datetime.wehw2_time')[0:5],
              states('input_datetime.wehw3_time')[0:5],
              states('input_datetime.wehw4_time')[0:5],
              states('input_datetime.wehw5_time')[0:5]]) }}
    - platform: template
      value_template: >
          {{ (states('binary_sensor.workday_sensor') == 'on') and
             (states('sensor.time') in
             [states('input_datetime.wdhw1_time')[0:5],
              states('input_datetime.wdhw2_time')[0:5],
              states('input_datetime.wdhw3_time')[0:5],
              states('input_datetime.wdhw4_time')[0:5],
              states('input_datetime.wdhw5_time')[0:5]]) }}

  condition:
    condition: not
    conditions:
      - condition: state
        entity_id: sensor.time
        state: '00:00'

  action:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.tank_target
        value: >
          {% if states('binary_sensor.workday_sensor') == 'off' %}
            {% set idx = [states('input_datetime.wehw1_time')[0:5],
                          states('input_datetime.wehw2_time')[0:5],
                          states('input_datetime.wehw3_time')[0:5],
                          states('input_datetime.wehw4_time')[0:5],
                          states('input_datetime.wehw5_time')[0:5]].index(states('sensor.time')) %}
            {{ [states('input_number.wehw1_tgt'),
                states('input_number.wehw2_tgt'),
                states('input_number.wehw3_tgt'),
                states('input_number.wehw4_tgt'),
                states('input_number.wehw5_tgt')][idx] }}
          {% else %}
            {% set idx = [states('input_datetime.wdhw1_time')[0:5],
                          states('input_datetime.wdhw2_time')[0:5],
                          states('input_datetime.wdhw3_time')[0:5],
                          states('input_datetime.wdhw4_time')[0:5],
                          states('input_datetime.wdhw5_time')[0:5]].index(states('sensor.time')) %}
            {{ [states('input_number.wdhw1_tgt'),
                states('input_number.wdhw2_tgt'),
                states('input_number.wdhw3_tgt'),
                states('input_number.wdhw4_tgt'),
                states('input_number.wdhw5_tgt')][idx] }}
          {% endif %}

The condition is to ignore any “unset” schedule slots, with the side-effect that I can’t set a slot to midnight. You’ll need sensor.time to use this: see the time_date integration.

Hi Troon

Thanks for the quick reply but I’m very new to HS and that code is like a foreign language to me. Can you add comments to it so I know what each section is doing?

I can see your inputs are the time, which I need and also a “target”, which I will need to substitute to set the temperature for the TRV.

Thanks

I can recommend schedy:

This is a nice app for homeassistant which is made for controlling heaters. It is maybe a little bit more complicated then a simple automation, but it can do a lot more.

Thanks Se7enair, I’ll check it out !!

This is quite an involved automation for a beginner, but if you want a single automation to do this job without hard-coding the times into the automation, tough :wink:. If you work through it slowly, it’s not that hard.

There are two triggers, both template triggers. The template is a bit of code that is evaluated whenever one of its elements changes, and the trigger fires if that evaluation returns a true value.

The two triggers are functionally the same: the first is for non-workdays, the second for workdays, which is the first part of each trigger’s if statement. The next bit of the code checks if the current time is in the list of schedule times — if it is, the trigger fires. The [0:5] pulls the hours and minutes out of the stored times, which also have seconds: "12:34:56"[0:5] == "12:34".

The action is again split into a workday and non-workday part. The set idx bit finds out which of the five timeslots matches the current time, and then uses that idx to extract the corresponding target value, which is then used to update the target input_number.

EDIT: Prompted by this topic, I’ve rewritten my automation to remove the hard-coded five slots (although it’s even less beginner-friendly now!). It will now handle any number of slots, but the helpers need to be customized to include a class attribute. It now reads thus:

- alias: Hot water - tank target manager

  description: >-
    This automation updates the value of the tank target based on the values in the
    schedule. The action identifies which slot matches the current time, then sets
    the target to that slots target value. Slots at midnight are considered unset,
    and ignored. All schedule-related helpers must be customized with the relevant
    class attribute: we (weekend) / wd (workday) plus tm (time) / tg (target).

  id: 9ac52ecb-3e29-4474-b64b-9261ee9dce4e

  trigger:
    - platform: template
      value_template: >
          {% set wetm = states.input_datetime|selectattr('attributes.class','eq','wehw_time')|map(attribute='state')|map('truncate',5,False,'',0)|list %}
          {% set wdtm = states.input_datetime|selectattr('attributes.class','eq','wdhw_time')|map(attribute='state')|map('truncate',5,False,'',0)|list %}
          {{ ((states('binary_sensor.workday_sensor') == 'off') and (states('sensor.time') in wetm)) or
             ((states('binary_sensor.workday_sensor') == 'on') and (states('sensor.time') in wdtm)) }}

  condition: "{{ states('sensor.time') != '00:00' }}"

  action:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.tank_target
        value: >
          {% set wetm = states.input_datetime|selectattr('attributes.class','eq','wehw_time')|map(attribute='state')|map('truncate',5,False,'',0)|list %}
          {% set wdtm = states.input_datetime|selectattr('attributes.class','eq','wdhw_time')|map(attribute='state')|map('truncate',5,False,'',0)|list %}
          {% set wetg = states.input_number|selectattr('attributes.class','eq','wehw_tgt')|map(attribute='state')|list %}
          {% set wdtg = states.input_number|selectattr('attributes.class','eq','wdhw_tgt')|map(attribute='state')|list %}
          {{ wetg[wetm.index(states('sensor.time'))] if states('binary_sensor.workday_sensor') == 'off' else wdtg[wdtm.index(states('sensor.time'))] }}

Although yes, there are many ways you can do it which have advantages, a very simply way which works from the UI is just:

alias: Heating Schedule 1
description: ''
mode: single
trigger:
  - platform: time
    at: '06:00:00'
  - platform: time
    at: '09:00:00'
  - platform: time
    at: '15:00:00'
  - platform: time
    at: '18:00:00'
  - platform: time
    at: '22:00:00'
condition:
  - condition: time
    weekday:
      - mon
      - tue
      - wed
      - thu
      - fri
action:
  - choose:
      - conditions:
          - condition: time
            after: '22:00:00'
        sequence:
          - service: climate.set_temperature
            target:
              device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
            data:
              temperature: 18
      - conditions:
          - condition: time
            after: '18:00:00'
        sequence:
          - service: climate.set_temperature
            target:
              device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
            data:
              temperature: 22
      - conditions:
          - condition: time
            after: '15:00:00'
        sequence:
          - service: climate.set_temperature
            target:
              device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
            data:
              temperature: 20
      - conditions:
          - condition: time
            after: '09:00:00'
        sequence:
          - service: climate.set_temperature
            target:
              device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
            data:
              temperature: 15
      - conditions:
          - condition: time
            after: '06:00:00'
        sequence:
          - service: climate.set_temperature
            target:
              device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
            data:
              temperature: 25
    default: []
2 Likes

Triggers at the time and days you specified . Action section checks what temp to set.

alias: Heating Schedule 1
description: ''
trigger:
  - platform: time
    at: '06:00:00'
  - platform: time
    at: '09:00:00'
  - platform: time
    at: '15:00:00'
  - platform: time
    at: '18:00:00'
  - platform: time
    at: '22:00:00'
condition:
  - condition: time
    weekday:
      - mon
      - tue
      - wed
      - thu
      - fri
action:
  - service: climate.set_temperature
    target:
      device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
    data:
      temperature: >
        {% if is_state('sensor.time', '06:00')%}
          25
        {% elif is_state('sensor.time', '09:00')%}
          15
        {% elif is_state('sensor.time', '15:00')%}
          20
        {% elif is_state('sensor.time', '18:00')%}
          22
        {% elif is_state('sensor.time', '22:00')%}
          18
        {% endif %}
mode: single
1 Like

Yet another way to do it:

alias: 'Example 1'
trigger:
  - platform: time
    at:
    - '06:00:00'
    - '09:00:00'
    - '15:00:00'
    - '18:00:00'
    - '22:00:00'
condition:
  - condition: time
    weekday:
      - mon
      - tue
      - wed
      - thu
      - fri
action:
  - service: climate.set_temperature
    target:
      device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
    data:
      temperature: >
        {% set temps = {6: 25, 9: 15, 15: 20, 18: 22, 22: 18} %}
        {{ temps[now().hour] }}

Or reduced to this:

alias: 'Example 2'
trigger:
  - platform: template
    value_template: "{{ now().hour in [6, 9, 15, 18, 22] and now().minute == 0 }}"
condition: "{{ 1 <= now().isoweekday() <= 5 }}"
action:
  - service: climate.set_temperature
    target:
      device_id: d8c34b0dce275e2c56a9b1f68f0a6d19
    data:
      temperature: "{{ {6: 25, 9: 15, 15: 20, 18: 22, 22: 18}[now().hour] }}"

How it works:

  • The Template Trigger checks if the current hour exists in a list of hours. If it is then it triggers provided it is the start of the hour (minute = 0).
  • The Template Condition checks if the current weekday (ISO version is 1 to 7 where 1 represents Monday and 7 is Sunday) lies between 1 (Monday) and 5 (Friday).
  • The action uses a dictionary containing each triggered hour and its associated temperature. It simply uses the current hour to look up the desired temperature.

FWIW, ‘Example 1’ is probably easier to read and understand whereas ‘Example 2’ attempts to demonstrate what can be done with templates. Feel free to mix and match the techniques to suit your preferences.

4 Likes

Thanks septillionTimo, obaldius & 123Taras all of your suggestions are exactly what I was looking for and all work equally as well. I really appreciate your input and advice.

Now I would like to expand on this (if possible) by having the following features / functionality to allow the schedule to be set dynamically via a lovelace frontend (rather than doing it statically via automations).

  1. Have a card where I can dynamically set the parameters for the days the schedule will run. The selected days will be knows as say “Workdays” and they will have a specific time and set temperature schedule. The days not selected will be known “Off Days” and they will also have a specific time and set temperature schedule but independent of the “Workdays” schedule.

  2. Have cards where I can dynamically set the parameters for the “Workdays” and “Off Days” schedules. This will allow me to set the times and temperatures.

  3. The above 2 don’t need to be on separate cards, if it can all be achieved on one card that is also fine.

I have attached a picture which kind of shows visually what I am trying to achieve.

Again, thank in advance for your help and guidance!!

I refer you to my post above, which does exactly this, although it uses the workday sensor to distinguish workdays and “off” days, as that is used in other areas of my system also.

1 Like

OK, thanks. I will read through the code and try and understand it and modify it with my TRV temperature. Might take me a while as I’m fairly new to coding.

What card type do you use and do you get the info on the card?

not sure how you do this

You need to set up the helpers first under Configuration / Helpers (partial screenshot):

Obviously, use your own names as appropriate. Mine are “weekday” / “weekend” “hot water” “time” / “target”.

Then just use an entities card:

The template editor is great for working out bits of code:

I suggest you start with my first version, not the re-written one in my second post.

1 Like

Thanks Troon, Also where do I insert the code in your post above, is it an automation and in the yaml for the automation?

Yes, that’s an automation. I keep my automations as documented here:

1 Like

Thanks for the tip Troon, I’m working through your code it it’s making sense, just need to edit bits to include my TRV temp setting.

1 Like

For future reference, a Time Trigger also accepts an input_datetime.

trigger:
  - platform: time
    at:
    - input_datetime.time_1
    - input_datetime.time_2
    - input_datetime.time_3
    - input_datetime.time_etc
3 Likes

Are there 4 or 5 daily Start Times in your requirements?

Can be any where from 5-7 but also separate ones for scheduling for weekdays & weekends.