Me again, next configuration - start time to heat house based on outside temperature

Hi, so this is my next step in home automation and need help again.

I have set up my thermostats (baseboard heating) to start at a specific time of day depending if it’s a weekday or weekend and if the person is present or not. This is working fine. Now I want to take it a step further.

I want to adjust the start time based on the outside temperature. Colder it is (living in Canada so it can get pretty cold), sooner it will start so by the time the person has to get up, the room will be at a comfortable level.

I haven’t used template enough do figure it out. I want to do something like this (in C syntax):

start_time_in_minutes + (outside_temp < 0 ? -outside_temp * 2 : 0)

So if start time is 6:00:00 (360 minutes from midnight) and the temperature is -15C, it will start at 5:30:00 (360 + (-15) * 2 = 330)

Can it be done?

Thanks

Yes. Buy an ecobee.

Very funny. Did you miss the part when I said I have baseboard heating? My Sinope thermostats works very well thank you and I want to contained the home automation within Home Assistant as much as possible.

https://support.ecobee.com/hc/en-us/articles/227874607-Line-voltage-equipment

And I wasn’t trying to be funny. (Well, ok, maybe a little. :wink:)

But seriously, the answer to your question is yes, but it can get tricky, and if you’re not careful you can possibly cause your heating to switch frequently. And you might cause damage, or worse. Or maybe your thermostat is smart enough to compensate for improper usage. I don’t know.

It just seems like you’re trying to duplicate what smart thermostats already do well.

So basically I think what you want to do is to use a template trigger that compares sensor.time against a calculated start time. The reason I say it can get tricky is, have you considered what will, or should, happen as the temperature changes? The calculated start time will also change. How should it handle the start time changing after the heat has already been “turned on”? or off?

My thermostats already use duty cycles to regulate the baseboard’s heating (0%, 25%, 50%, 75% and 100%). A relay would simply do full heat and no heat which would be a huge step back to the rooms controlled temperature.

Ok, I’ll look at sensor.time and see what I can do.

Thanks.

Feel free to post your question again (in a new topic, and delete/close/rename/whatever this one.) I won’t reply so maybe you’ll get more useful answers from others.

Or, I’d be happy to help with writing an appropriate template trigger. I suspect you may even be able to collapse some of what you did before into a slightly more template trigger.

That’s ok, I’ve found a solution. Might not be the best or prettiest but it seems to work. Here’s what it looks like:

{% set at_time=5 * 60  %} 
{% set cur_time=now().hour * 60 + now().minute %}
{% set max_temp=15.0 %}
{% set out_temp=float(states('sensor.outside_temperature')) %}
{{ at_time - cur_time == 0 or (at_time - cur_time > 0 and out_temp < max_temp and at_time - cur_time + out_temp * 1.5 - 30.0 < 0) }}

Basically, the heat will turn on up to an hour before the wake time (at_time) but only if the outside temperature (out_temp, taken from my Acurite weather station, thank JardiamJ for the work) is already less than 15C (max_temp). At 15C, it will start 7 minutes 30 seconds before wake time. At -20, it will start an hour before the wake time.

To trigger it, I’ve set time templates of 5 and 7 for the hour and * for the minutes so it will try every minute of those hours.

So my code for turning on the heat in the morning looks like this now:

- id: '1578617316410'
  alias: Présence - Martin le matin
  description: ''
  trigger:
  - hours: '5'
    minutes: '*'
    platform: time_pattern
  - hours: '7'
    minutes: '*'
    platform: time_pattern
  condition:
  - condition: state
    entity_id: person.martin
    state: home
  - condition: or
    conditions:
    - condition: and
      conditions:
      - condition: state
        entity_id: binary_sensor.workday_sensor
        state: 'on'
      - after: '5:00:00'
        before: '6:00:00'
        condition: time
      - condition: template
        value_template: '"{% set at_time=5 * 60 %} {% set cur_time=now().hour * 60
          + now().minute %} {% set max_temp=15.0 %} {% set out_temp=float(states(''sensor.outside_temperature''))
          %} {{ at_time - cur_time == 0 or (at_time - cur_time > 0 and out_temp <
          max_temp and at_time - cur_time + out_temp * 1.5 - 30.0 < 0) }}"'
    - condition: and
      conditions:
      - condition: state
        entity_id: binary_sensor.workday_sensor
        state: 'off'
      - after: '7:00:00'
        before: '8:00:00'
        condition: time
      - condition: template
        value_template: '"{% set at_time=7 * 60 %} {% set cur_time=now().hour * 60
          + now().minute %} {% set max_temp=15.0 %} {% set out_temp=float(states(''sensor.outside_temperature''))
          %} {{ at_time - cur_time == 0 or (at_time - cur_time > 0 and out_temp <
          max_temp and at_time - cur_time + out_temp * 1.5 - 30.0 < 0) }}"'
  action:
  - data:
      temperature: 22
    entity_id: climate.neviweb130_climate_martin
    service: climate.set_temperature

Like I said, not the prettiest but with my current knowledge of Home Assistant (only 3 weeks), that’s the best I could muster :slight_smile:

Not bad! :slightly_smiling_face:

I haven’t analyzed your code in detail, but after a quick look I’d make a couple of suggestions.

First, I wouldn’t have two calls to now() in the same template. Although unlikely, it’s possible for the first to happen right before the hour changes, and for the second to happen right after. In which case, e.g., 04:59 would look like 04:00 or 05:59.

Second, the float filter is better than the float function. The former will return 0.0 if the “input” can’t be converted to a float (such as ‘unknown’), whereas the latter will cause an error.

So this might be better:

{% set at_time=5 * 60  %} 
{% set cur_time=now() %}
{% set cur_time=cur_time.hour * 60 + cur_time.minute %}
{% set max_temp=15.0 %}
{% set out_temp=states('sensor.outside_temperature')|float %}
{{ at_time - cur_time == 0 or (at_time - cur_time > 0 and out_temp < max_temp and at_time - cur_time + out_temp * 1.5 - 30.0 < 0) }}

Both makes lot of sense, thanks :+1: :slight_smile:

Merci to have shared this!

Our main heater is a boiler and when the outdoor T is very low it takes forever to heat the house in the morning. I just added this to my installation but curious if you’ve made any changes to this logic since 2020? If so, I’d sure be interested to hear about them.

Hi, no, no change. It’s still working well for us.

1 Like

Trying to understand the logic, I break up things and ended up with this :

# "at_time=cur_hour * 60 is valid because of 'conditions: after HH:00 && before HH+1:00'
{% set cur_hour=now().hour %}
{% set cur_minute=now().minute %}
{% set at_time=cur_hour * 60 %}
{% set cur_time=at_time + cur_minute %}

I don’t write code often in HA, I thought this would be valid but it failed. It’s late here, I’ll give this a try later in the week or weekend.

Can you check your template again if you’ve made any changes at all? I know it’s been almost 4y.

Per the orig code:

{% set at_time=5 * 60  %} 
{% set cur_time=now() %}
{% set cur_time=cur_time.hour * 60 + cur_time.minute %}
{{ at_time - cur_time == 0 or (at_time - cur_time > 0 and ... ... }}

At 05:00:xx , at_time is assigned 300. cur_time 5 * 60 + 0 is also 300.
The first condition at_time - cur_time equals 0, the condition pass and thus the thermostat will be adjusted.
For the second condition, at_time - cur_time > 0, at 05:01:xx at_time equals 300 and cur_time 301. This condition never passes since the result is below 0.

Correct me if I’m wrong, I ended up with this :

{% set cur_time=now() %}
{% set cur_hour=cur_time.hour %}
{% set cur_minute=cur_time.minute %}
{% set at_time=cur_hour * 60 + 59 %}
{% set cur_time=cur_hour * 60 + cur_minute %}

With the above, at worst at 05:59:xx the thermostat will be set. This also fix the second condition.

[edit] not fully tested yet but I believe the changes will make it work.

[ UPDATED ]

The forum didn’t allow me to reply, so I had to edit this last post. After more thinking, I added a delay at the end of the action to prevent the automation to run every minute of the hour.

alias: Thermostat Morning
description: ""
trigger:
  - hours: "5"
    minutes: "*"
    platform: time_pattern
  - hours: "7"
    minutes: "*"
    platform: time_pattern
condition:
  - condition: state
    entity_id: person.XX
    state: home
  - condition: or
    conditions:
      - condition: and
        conditions:
          - after: "5:00:00"
            before: "6:00:00"
            condition: time
          - condition: state
            entity_id: binary_sensor.workday_today_sensor
            state: "on"
      - condition: and
        conditions:
          - after: "7:00:00"
            before: "8:00:00"
            condition: time
          - condition: state
            entity_id: binary_sensor.workday_today_sensor
            state: "off"
action:
  - if:
      - condition: and
        conditions:
          - condition: numeric_state
            entity_id: sensor.thermostat_attr_temperature
            below: 20
          - condition: template
            value_template: >-
              {% set out_temp=float(states.weather.openweathermap.attributes.forecast[0].temperature)  %}
              {{ out_temp <= 14.0 }}
    then:
      - delay:
          minutes: >-
            {% set max_trigger_minute=59 %}
            {% set cur_time=now() %}
            {% set cur_hour=cur_time.hour %}
            {% set cur_minute=cur_time.minute %}
            {% set cur_time=cur_hour * 60 + cur_minute %}
            {% set out_temp=float((states.weather.openweathermap.attributes.forecast[0].temperature
            + states.weather.openweathermap.attributes.forecast[1].temperature ) / 2.0) %}
            {% set trigger_minute=( max_trigger_minute + out_temp * 1.5 - 22.0 ) | round %}
            {% if cur_minute >= trigger_minute -%}
              0
            {%- else -%}
              {{ trigger_minute }}
            {%- endif %}
      - data:
          temperature: 20
        service: climate.set_temperature
        target:
          entity_id: climate.thermostat
        enabled: true
  - delay:
      minutes: "{{ 59 - now().minute + 1 }}"
mode: single

If I am not home, it will run every minute… maybe that’s fine in case I was away and make it back home early in the morning. In the end, I might move that as well inside the action section.

The above ran just fine this morning… the added delays do prevent the automation to run top to bottom but every minute there’s still a trace saying that it stopped because of “single” mode. I’ll probably increase the number of saved traces.