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 %}
tempalte:
  - 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.

Mastodon: @[email protected]