Automatically Adjusting Indoor Home Temperature to Outdoor Temperature in Home Assistant
Using Home Assistant, I have been able to create a system for scaling my home's indoor temperature based on the outdoor heat index. This will also account for day/night cycles and home presence.
The goal of this automation is to increase the temperature indoors as it gets hotter to help conserve on energy usage from the grid (and to lower my summer electric bills).
The follow graphic provides a visual of how this automation can provide a calculated indoor temperature with an indoor temperature range of 72 - 80, a daytime offset of +2, away offset of +3, and an outdoor heat index range of 87 - 120.
To begin, we need to define our input number and input boolean control variables, as well as a few template (calculated) boolean sensors.
Note: default values are not set due to the fact that if Home Assistant is rebooted, it will revert to the defaults and not keep your previously set values.
input_boolean:
enable_smart_cooling:
name: Enable Smart Cooling
icon: mdi:thermostat-box
is_guest_home:
name: Guest is Home
icon: mdi:account-key
input_number:
climate_cooling_min_temp:
name: Climate Cooling Min Temperature
min: 66
max: 84
step: 1
mode: slider
icon: mdi:thermometer-minus
unit_of_measurement: "°F"
climate_cooling_max_temp:
name: Climate Cooling Max Temperature
min: 68
max: 84
step: 1
mode: slider
icon: mdi:thermometer-plus
unit_of_measurement: "°F"
climate_cooling_day_offset_temp:
name: Climate Cooling Daytime Offset Temperature
min: -10
max: 10
step: 1
mode: slider
icon: mdi:thermometer
unit_of_measurement: "°F"
climate_cooling_away_offset_temp:
name: Climate Cooling Away Offset Temperature
min: -10
max: 10
step: 1
mode: slider
icon: mdi:thermometer
unit_of_measurement: "°F"
climate_min_heat_index:
name: Climate Cooling Min Heat Index
min: 80
max: 125
step: 1
mode: slider
icon: mdi:thermometer-minus
unit_of_measurement: "°F"
climate_max_heat_index:
name: Climate Cooling Max Heat Index
min: 80
max: 125
step: 1
mode: slider
icon: mdi:thermometer-plus
unit_of_measurement: "°F"
- platform: template
sensors:
climate_cooling_calculated_temperature:
friendly_name: "Climate Cooling Calculated Temperature"
unit_of_measurement: "°F"
value_template: >
{% set data = {
"weather_temp": states.sensor.outdoor_heat_index.state|float(default=80.0),
"min_temp": states.input_number.climate_cooling_min_temp.state|float,
"max_temp": states.input_number.climate_cooling_max_temp.state|float,
"day_offset_temp": states.input_number.climate_cooling_day_offset_temp.state|float,
"away_offset_temp": states.input_number.climate_cooling_away_offset_temp.state|float,
"temp_range": (states.input_number.climate_cooling_max_temp.state|float - states.input_number.climate_cooling_min_temp.state|float),
"heat_index_min": states.input_number.climate_min_heat_index.state|float,
"heat_index_max": states.input_number.climate_max_heat_index.state|float,
"heat_index_range": (states.input_number.climate_max_heat_index.state|float - states.input_number.climate_min_heat_index.state|float),
"heat_index_step_value": ((states.input_number.climate_max_heat_index.state|float - states.input_number.climate_min_heat_index.state|float) / (states.input_number.climate_cooling_max_temp.state|float - states.input_number.climate_cooling_min_temp.state|float)),
"home_occupied": (is_state('binary_sensor.is_home_occupied', 'on'))
} %}
{% set temp_factor = iif(
((data.weather_temp - data.heat_index_min) / data.heat_index_step_value < 0), 0,
iif(
((data.weather_temp - data.heat_index_min) / data.heat_index_step_value > data.heat_index_range), data.heat_index_step_range,
((data.weather_temp - data.heat_index_min) / data.heat_index_step_value), 0),
0)
%}
{% set new_temps = {
"day_occupied": iif((data.min_temp + temp_factor + data.day_offset_temp)|int > data.max_temp, data.max_temp, (data.min_temp + temp_factor + data.day_offset_temp)|int, data.min_temp ),
"day_away": iif((data.min_temp + temp_factor + data.day_offset_temp + data.away_offset_temp)|int > data.max_temp, data.max_temp, (data.min_temp + temp_factor + data.day_offset_temp + data.away_offset_temp)|int, data.min_temp),
"night_occupied": iif((data.min_temp + temp_factor)|int > data.max_temp, data.max_temo, (data.min_temp + temp_factor)|int, data.min_temp),
"night_away": iif((data.min_temp + temp_factor + data.away_offset_temp)|int > data.max_temp, data.max_temp, (data.min_temp + temp_factor + data.away_offset_temp)|int, data.min_temp)
} %}
{% if state_attr('sun.sun', 'elevation') > -6 %}
{% if data.home_occupied %}
{{ new_temps.day_occupied }}
{% else %}
{{ new_temps.day_away }}
{% endif %}
{% else %}
{% if data.home_occupied %}
{{ new_temps.night_occupied }}
{% else %}
{{ new_temps.night_away }}
{% endif %}
{% endif %}
template:
- binary_sensor:
name: "Is Home Occupied"
device_class: occupancy
state: >
{{ is_state('person.user1', 'home') or is_state('person.user02', 'home') or is_state('input_boolean.is_guest_home', 'on') }}
- binary_sensor:
name: "Is Calculated Temperature Current"
state: >
{{ is_state("sensor.climate_cooling_calculated_temperature", "unknown") or (states('sensor.climate_cooling_calculated_temperature')|int == state_attr('climate.thermostat', 'temperature')|int) }}
After properly applying these to your Home Assistant and making any necessary adjustments, you should be able to get a calculated temperature based off your variables.
To automate this so that it can set your thermostat's temperature, we can go a step further and create an automation.
The following automation is based on a Honeywell thermostat with Home Assistant's climate integration:
automation:
- id: '1655578078682'
alias: Adjust Climate Controls
description: ''
trigger:
- platform: state
entity_id:
- binary_sensor.is_home_occupied
from: 'off'
to: 'on'
for:
hours: 0
minutes: 5
seconds: 0
- platform: state
entity_id:
- binary_sensor.is_home_occupied
from: 'on'
to: 'off'
for:
hours: 0
minutes: 15
seconds: 0
- platform: state
entity_id:
- input_boolean.enable_smart_cooling
from: 'off'
to: 'on'
for:
hours: 0
minutes: 1
seconds: 0
- platform: state
entity_id:
- binary_sensor.is_calculated_temperature_current
to: 'off'
for:
minutes: 10
from: 'on'
- platform: state
entity_id:
- sensor.climate_cooling_calculated_temperature
for:
hours: 0
minutes: 10
seconds: 0
condition:
- condition: state
entity_id: climate.thermostat
state: cool
action:
- service: script.adjust_smart_cooling_temperature
data: {}
mode: single
The script that will adjust the temperature:
script:
adjust_smart_cooling_temperature:
alias: Adjust Smart Cooling Temperature
sequence:
- if:
- condition: and
conditions:
- condition: state
entity_id: input_boolean.enable_smart_cooling
state: "on"
- condition: state
entity_id: climate.thermostat
state: cool
- condition: template
value_template: '{{ (state_attr("climate.thermostat", "temperature")|int != states("sensor.climate_cooling_calculated_temperature")|int) }}'
then:
- service: climate.set_temperature
data:
temperature: '{{ states("sensor.climate_cooling_calculated_temperature")|int }}'
hvac_mode: cool
target:
entity_id: climate.thermostat
mode: single
After adding these examples and adjusting for your configuration needs, you should be able to add your variables to your Home Assistant's dashboard and enable the automation.