I like to share this project which aims to simulate the smart heating present in some thermostats, in my case a Tado v3+. The aim is to obtain a certain temperature at a certain time, starting the heating well in advance. As a first step, I estimated the heating capacity of my system, in °C / h. This estimate is empirical, and can be done by observing the delta temperature and time during heating, or by creating a derivative sensor with the thermostat’s temperature sensor. In my case the observed values vary from about 0.5 to 1.5 °C / h, depending on the external temperature. First, I created a sensor to correct this heating ratio as a function of the external temperature (value from a sonoff zigbee sensor placed outdoor ‘sensor.sonoff_a480003084_temperature’). I consequently assumed that this variation occurs between a minimum (I chose 0 °C) and a maximum external temperature of 12 °C, which is the temperature below which my heating system is programmed to start (morning heating starts if the minimum temperature expected for the next day is below 12 °C). I then created two numeric helpers whose values are respectively the minimum and maximum °C / h (called ‘input_number.tado_offset_slope’ and ‘input_number.tado_max_slope’ with starting values of 0.5 and 1.5 as mentioned above) allowing future adjustments.
So, I calculated the correct ratio in °C / h as follows:
adjust_slope_outside_temp_living_room:
friendly_name: adjust_slope_outside_temp_living_room
value_template: >
{%- set delta_slope = ((states('input_number.tado_max_slope')|float(default=16))-(states('input_number.tado_offset_slope')|float(default=16)))/12 -%}
{{(states('input_number.tado_offset_slope')|float(default=16)+((states('sensor.sonoff_a480003084_temperature')|float(default=16))*delta_slope))|round(2)}}
below is a sensor that calculates the delta temperature to be filled in order to reach the preset temperature, as the difference between the target temperature and the current temperature in the room:
delta_t_tado_thermostat:
friendly_name: 'delta_t_tado_thermostat'
value_template: >
{{((states('input_number.tado_thermostat_temp1')|float(default=16)-(states('sensor.state_current_temp_thermostat_living_room')|float(default=16))))|round(2)}}
the value can, of course, be positive or negative. The next sensor calculates the necessary time in minutes, dividing the temperature delta by the ratio in ° C / h and then multiplying by 60:
time_heating_tado_thermostat:
friendly_name: 'time_heating_tado_thermostat'
value_template: >
{{((states('input_number.tado_thermostat_temp1')|float(default=16)-(states('sensor.state_current_temp_thermostat_living_room')|float(default=16)))|round(2)/((states('sensor.adjust_slope_outside_temp_living_room')|float(default=1)))*60)|round(2)}}
the next step was to establish the start time of the heating. A good way for me was to use the next alarm sensor provided in the companion app. Since there are three of us in the house, I wrote a template that returns the value with the alarm set before, and then subtracts the time (converted in seconds) calculated above:
set_preheating_thermostat_tado_living_room:
friendly_name: set_preheating_thermostat_tado_living_room
value_template: >
{%- set alarm_list = [(as_timestamp(states('sensor.emma_next_alarm'))), (as_timestamp(states('sensor.pixel_2_xl_next_alarm'))), (as_timestamp(states('sensor.mi_a2_next_alarm'))) ] -%}
{% if (states('sensor.pixel_2_xl_next_alarm'))== "unavailable" and (states('sensor.emma_next_alarm'))== "unavailable" and (states('sensor.mi_a2_next_alarm'))== "unavailable" -%}
"08:00"
{%- else %}
{{(min(alarm_list)|float(default=1)-(states('sensor.time_heating_tado_thermostat')|float(default=1)*60)) | timestamp_custom('%I:%M') }}
{%- endif %}
The sensor output is like “6:01”. If any alarm is available may be sunday…The value was then used in an automation that set the start time in the morning:
alias: Set tado thermostat by alarm living room
description: ''
trigger:
- platform: state
entity_id: sensor.time_heating_tado_thermostat
for:
hours: 0
minutes: 0
seconds: 0
milliseconds: 0
condition:
- condition: template
value_template: '{{(states(''sensor.time_heating_tado_thermostat''))|float(default=1)>0}}'
- condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
- sat
after: '00:00'
before: '11:00'
action:
- service: input_datetime.set_datetime
data:
time: '{{ states(''sensor.set_preheating_thermostat_tado_living_room'') }}'
target:
entity_id:
- input_datetime.tado_thermostat_start1
mode: single
Condition is that heating time is>0. Automation that contain input_datetime.tado_thermostat_start1 is (This automation also sets up a tado smart radiator other than the thermostat):
alias: Tado schedule thermostat ON1
description: ''
trigger:
- platform: state
entity_id: input_datetime.tado_thermostat_start1
- platform: template
value_template: >-
{{ states('sensor.time') >=
(states('input_datetime.tado_thermostat_start1')) }}
- platform: state
entity_id: input_datetime.tado_thermostat_start1
- platform: state
entity_id: input_datetime.tado_thermostat_end1
condition:
- condition: template
value_template: '{{states(''sensor.valuta_giorno_schedule_thermostat_tado'')}}'
- condition: template
value_template: >-
{{ states('sensor.time') >=
(states('input_datetime.tado_thermostat_start1')) }}
- condition: template
value_template: >-
{{ states('sensor.time') <=
(states('input_datetime.tado_thermostat_end1')) }}
- condition: template
value_template: >-
{{ (states('input_datetime.tado_thermostat_end1'))!="00:00" and
(states('input_datetime.tado_thermostat_start1'))!="00:00" }}
- condition: time
after: '00:00'
weekday:
- mon
- tue
- wed
- thu
- fri
- sat
action:
- delay:
hours: 0
minutes: 0
seconds: 30
milliseconds: 0
- service: climate.turn_on
target:
entity_id:
- climate.tado_smart_thermostat_ruxxxxxxxxxx
- climate.tado_smart_radiator_thermostat_vayyyyyyyyyy
- service: climate.set_temperature
target:
entity_id:
- climate.tado_smart_radiator_thermostat_vayyyyyyyyy
data:
temperature: >
{{
states('input_number.tado_thermostat_temp1')|float-(states('input_number.tado_offset_smart_radiator')|float)}}
- service: climate.set_temperature
target:
entity_id: climate.tado_smart_thermostat_ruxxxxxxxxxx
data:
temperature: |
{{states('input_number.tado_thermostat_temp1')|float}}
mode: single
max: 10
This last automation is not well explained, but the goal here is to set up morning start time. I am a beginner aware that the code could have been written more efficiently and smarter. I’ve been using it for many days and seems to be working fine: heating time is well estimated, of course not perfectly. I’m going to adjust the empirical data. That’s all I have.