Automating an heater's early start to get a room to temperature in time

Hi everybody,

My first post here, so please tell me if I should do something different.

My question might be: how to turn a number (say 2.5) from a helper into a time offset (-02:30:00) for an automation—but that could be a XY problem so here’s the whole situation:

Say I know I want to take a shower at 10pm, I’d like the bathroom to be a comfy 20 degrees at 10 pm.

I’ve set up two helpers for this:
Input Date/Time (time only): that I can manually set to 10pm, or 7am or anything else.
Input boolean - to indicate that the automation should run at all (I don’t shower every day…)

Then my automation checks at “time - 2 hours” if it should run based on the boolean, and turn on my climate, then turns off the boole so it doesn’t run the next day, and eventually turns the heating back off.

alias: Badkamer - Planning
description: ""
triggers:
  - trigger: time
    at:
      entity_id: input_datetime.badkamer_tijd
      offset: "-02:00:00"
conditions:
  - condition: state
    entity_id: input_boolean.badkamer_verwarming_boole
    state:
      - "on"
actions:
  - action: climate.set_temperature
    metadata: {}
    data:
      temperature: "{{ states('input_number.temperatuur_hoog')| float(0) }}"
    target:
      entity_id: climate.badkamer
  - action: input_boolean.turn_off
    metadata: {}
    data: {}
    target:
      entity_id: input_boolean.badkamer_verwarming_boole
  - delay:
      hours: 2
      minutes: 30
      seconds: 0
      milliseconds: 0
  - action: climate.set_temperature
    metadata: {}
    data:
      temperature: "{{ states('input_number.temperatuur_standby')| float(0) }}"
    target:
      entity_id: climate.badkamer
mode: single

This is all working fine, but I’d like to offset the heating start a little smarter, not just two hours before the target time, but based on the difference in current temp and target temp. I know my heating can heat the room with about 3 degrees per hour (approaching this linearly is fine for me).

I’ve created a template helper (number) that calculates the amount of hours the heating should start before the target time:

{{ ((states('input_number.temperatuur_hoog') | float(0) - states('sensor.badkamer_temperatuur') | float(0)) / 3) | round(2) }}

I’ve been messing around in turning this value (which is a float number) into the offset in the automation above, but frankly i have no idea what I’m doing… Does anyone have a suggestion?

Thanks a heap!

I think you’re going to need to switch to a template trigger.

trigger: template
value_template: |
  {% set offset_hours = ((states('input_number.temperatuur_hoog') | float(0) 
  - states('sensor.badkamer_temperatuur') | float(0)) / 3) | round(2) %}
  {{ now() >= states('input_datetime.badkamer_tijd')|as_datetime - timedelta(hours=offset_hours) }}

Depending on how bouncy your temperature sensor is, you might want to consider adding a for variable to that.

FWIW, I would avoid using a 2+ hour long delay. Consider what other trigger event might be appropriate and more temporally proximate to the time you want to turn off the heater or use a timer.

1 Like

Thanks a lot! I’m trying your implementation now. Is it better to move away from the helper and directly implement the expected time directly in the template trigger?

Also, why is it better to avoid a long delay in automations? Because the automation will keep running in memory? The fix was pretty easy, I created another trigger just after the target time helper.

Thank you again! I’m learning a lot from this.

HI, the reason is that the automation can get interrupted during that delay making that automation less reliable.

1 Like

Don’t know if this always works and if it works in all timezones but it seems to work now and with 2.5 and in Europe.

alias: Badkamer - Planning
description: ""
triggers:
  - trigger: time
    at:
      entity_id: input_datetime.badkamer_tijd
      offset: "-{{ (today_at() + timedelta(minutes=60*((states('input_number.temperatuur_hoog') | float(0) -states('sensor.badkamer_temperatuur') | float(0)) / 3) | round(2) )).time() }}"
    id: hoog
  - trigger: template
    value_template: "{{ state_attr('climate.badkamer', 'temperature') == states('input_number.temperatuur_hoog') }}"
    for:
      minutes: "{{ (((states('input_number.temperatuur_hoog') | float(0) - states('sensor.badkamer_temperatuur') | float(0)) / 3) | round(2) *60)+30 }}"
    id: standby
conditions:
  - condition: state
    entity_id: input_boolean.badkamer_verwarming_boole
    state: "on"
actions:
  - action: climate.set_temperature
    metadata: {}
    data:
      temperature: "{{ states('input_number.temperatuur_' ~ trigger.id)| float(0) }}"
    target:
      entity_id: climate.badkamer
  - action: input_boolean.turn_off
    metadata: {}
    data: {}
    target:
      entity_id: input_boolean.badkamer_verwarming_boole
mode: single

This should set the temperature to “hoog” according to your calculation (2.5) * 60 => -02:30:00 as an offset from the datetime.
When the set_temperature of the climate has been “hoog” for [calculation minutes] + 30 (I wasn’t sure if you wanted 30 minutes here or 2:30 hours) then it will switch it back to standby.
In both cases the boolean will be turned off.
This is obviously not correct but assumption is that it will not matter.

The code is untested, make sure to keep your current automation as a copy at least to fall back to in case this does not work