Smarter AC Control - Combined inside, outside and UV Heat Indexes

I’ve been spending some time to get my AC’s to not only use the temperature sensor in the room, but also to also take into account the outside temperature and UV index. The main reason was that we have large windows in our house and just automating the AC mode based on the inside temperature did not seem to work well. Example: 22 deg C in the room didn’t feel the same when it’s cloudy outside compared to a very hot and sunny day. Another factor was the heat transfer through the windows… Example: when it’s cold outside, I might want the AC to “try” and heat the room more due to the heat constantly transferring to the outside. I live in South Africa and due to our climate conditions, there are little to no building regulations around insulation, glazed windows etc so this plays a larger role.

One of the main reasons I started with this is because I don’t always want to have the AC on hot/cold because if the room is at the correct temperature it should just be on “fan_mode”. If it’s always on hot/cold it uses between 400 and 800 W, whereas the fan mode uses 15W. Then the temperature goes outside of the automation figure, then only does it go to hot/cold and similarly it goes to fan if it managed to cool the room by a figure set via input slider.

So to get to it. I measure the following, which allows me to build the logic and automations:

  1. The outside temperature, via a Sonoff Basic with a waterproof temperature sensor (ESPHome). This has to be installed in a ventilated area with no direct sunlight to better measure the ambient temperature without other factor affecting the reading
  2. The inside temperature is based on the attributes directly from the Midea AC component attributes
    The DarkSky UV index for my location, there is about a 10 minute delay, but the sun and overcast conditions don’t really change over a shorter period of time

First I created “heat_index template sensor”:

- platform: template
  sensors:
    living_room_heat_index:
      value_template: "{{ (
                          ((states.sensor.living_room_temperature.state | float) * ((states.input_number.living_room_inside_temperature_percentage.state | float) / 100)) + 
                          ((states.sensor.ac_outside_temperature.state | float) * (1 - ((states.input_number.living_room_inside_temperature_percentage.state | float) / 100))) + 
                          (((states.sensor.dark_sky_uv_index.state | float) * (states.input_number.living_room_uv_index.state | float)) / 500)
                          ) | round(2) }}"
      friendly_name: "Living Room Heat Index"
      icon_template: mdi:thermometer
      unit_of_measurement: "°C"

The “input_number.living_room_inside_temperature_percentage” is a variable number that is multiplied by the inside temperature, where (1 - “input_number.living_room_inside_temperature_percentage”) is multiplied by the outside temperature. These two figures are then added up, given a weighted average of the two temperatures based on how many % is allocated to them.

The “input_number.living_room_uv_index” is a variable number that is multiplied by the outside UV index. This number is then added to the sum of the two values above.

Since all the variable inputs are between 0 and 100, I had to divide by 100 to get to % weightings. With the UV index I divide by 500, it basically means that if the UV index is 10, I’m dividing by 5 and thus adding 2 deg C to my heat_index when the input slider is at 100%.

So this template sensor calculates a heat_index, which is the “new” temperature that I use in automations instead of the actual inside temperature. The formula does the following:
“heat_index” = (“inside_temperature” * “%_of_inside_temperature_to_use” / 100) + (“outside_temperature” * (1 - “%_of_inside_temperature_to_use” / 100) + (“outside_uv” * “%_of_outside_to_use” / 500).

Then we get to the automations, which are a bit complex because of the preference to have the AC on fan mode. I’m not going into detail, but I’ll explain the main logic and give an example:

###########################################|###########################################
#                                                                                     #
#                              SET LIVING ROOM AC TO COOL                             #
#                                                                                     #
#   Check if Living Room AC is NOT OFF and set to low cool mode when room is warm     #
#                                                                                     #
###########################################|###########################################

- id: '1533333569253'
  alias: Living Room AC Cool Mode
  initial_state: 'true'
  trigger:
  - minutes: /1
    seconds: 30  
    platform: time_pattern
  condition:
  - condition: template
    value_template: "{% if not is_state('climate.lounge_kitchen', 'off') %}true{% endif %}"
  - condition: template
    value_template: "{% if not is_state('binary_sensor.chimney_is_use', 'on') %}true{% endif %}"   
  - condition: template
    value_template: "{{ states('sensor.living_room_heat_index') | float > states('input_number.living_room_start_cool') | float }}"
  - condition: template
    value_template: "{% if not is_state('climate.lounge_kitchen', 'cool') %}true{% endif %}"  
  action:
  - service: climate.set_hvac_mode
    data:
      entity_id: climate.lounge_kitchen
      hvac_mode: "cool"
  - service: climate.set_temperature
    data:
      entity_id: climate.lounge_kitchen
      temperature: 22
  - service: climate.set_fan_mode
    data:
      entity_id: climate.lounge_kitchen
      fan_mode: "Low"

So this checks that the AC is not OFF, the Chimney is not being used (this was because when I used the fireplace, the room would get hot and the AC went to cool mode :slight_smile:), the heat_index is larger than my start_cool temperature set point (different input slider) and also that the AC is not currently in COOL mode. When all of this is true, the AC will set to COOL, low fan speed and 22 deg. One thing I could not get right was to have the 22 deg C use the information from another input number, it kept seeing the input as a string, maybe someone can help me there?

###########################################|###########################################
#                                                                                     #
#                              SET LIVING ROOM AC TO HEAT                             #
#                                                                                     #
#   Check if Living Room AC is NOT OFF and set to low heat mode when room is cold     #
#                                                                                     #
###########################################|###########################################

- id: '1532244299253'
  alias: Living Room AC Heat Mode
  initial_state: 'true'
  trigger:
  - minutes: /1
    seconds: 30  
    platform: time_pattern
  condition:
  - condition: state
    entity_id: binary_sensor.chimney_in_use
    state:  'off'
  - condition: template
    value_template: "{% if not is_state('climate.lounge_kitchen', 'off') %}true{% endif %}"    
  - condition: template
    value_template: "{{ states('sensor.living_room_heat_index') | float < states('input_number.living_room_start_heat') | float }}"
  - condition: template
    value_template: "{% if not is_state('climate.lounge_kitchen', 'heat') %}true{% endif %}"  
  action:
  - service: climate.set_hvac_mode
    data:
      entity_id: climate.lounge_kitchen
      hvac_mode: "heat"
  - service: climate.set_temperature
    data:
      entity_id: climate.lounge_kitchen
      temperature: 22
  - service: climate.set_fan_mode
    data:
      entity_id: climate.lounge_kitchen
      fan_mode: "Low"

So this checks that the AC is not OFF, the Chimney is not being used, the heat_index is smaller that my start_heat temperature set point (different input slider) and also that the AC is not currently in HEAT mode. When all of this is true, the AC will set to HEAT, low fan speed and 22 deg.

Then I created two additional automations, which sets the AC to fan_mode after being on COOL or HEAT, if the heat_index has gone up (heating) or down (cooling) by an amount set in another input_slider:

###########################################|###########################################
#                                                                                     #
#                          SET LIVING ROOM AC TO FAN AFTER HEAT                       #
#                                                                                     #
# Check if Living Room AC is NOT OFF and set to low fan mode when room heated enough  #
#                                                                                     #
###########################################|###########################################

- id: '1533223456853'
  alias: Living Room AC Fan Mode After Heating
  initial_state: 'true'
  trigger:
  - minutes: /1
    seconds: 0
    platform: time_pattern
  condition:
  - condition: state
    entity_id: input_boolean.heat_overdrive_boolean
    state:  'off'
  - condition: template
    value_template: "{% if not is_state('climate.lounge_kitchen', 'off') %}true{% endif %}"    
  - condition: or
    conditions:
    - condition: template
      value_template: "{{ states('sensor.living_room_heat_index') | float >= (states('input_number.living_room_start_heat') | float + states('input_number.living_room_temperature_variance') | float) }}"
  - condition: template
    value_template: "{% if not is_state('climate.lounge_kitchen', 'fan_only') %}true{% endif %}"  
  - condition: template
    value_template: "{% if is_state('climate.lounge_kitchen', 'heat') %}true{% endif %}"  
  action:
  - service: climate.set_hvac_mode
    data:
      entity_id: climate.lounge_kitchen
      hvac_mode: "fan_only"
  - service: climate.set_fan_mode
    data:
      entity_id: climate.lounge_kitchen
      fan_mode: "Low"

###########################################|###########################################
#                                                                                     #
#                          SET LIVING ROOM AC TO FAN AFTER COOL                       #
#                                                                                     #
# Check if Living Room AC is NOT OFF and set to low fan mode when room heated enough  #
#                                                                                     #
###########################################|###########################################

- id: '1533986637853'
  alias: Living Room AC Fan Mode After Cooling
  initial_state: 'true'
  trigger:
  - minutes: /1
    seconds: 0  
    platform: time_pattern
  condition:
  - condition: state
    entity_id: input_boolean.heat_overdrive_boolean
    state:  'off'
  - condition: template
    value_template: "{% if not is_state('climate.lounge_kitchen', 'off') %}true{% endif %}"    
  - condition: template
    value_template: "{{ states('sensor.living_room_heat_index') | float <= (states('input_number.living_room_start_cool') | float - states('input_number.living_room_temperature_variance') | float) }}"
  - condition: template
    value_template: "{% if not is_state('climate.lounge_kitchen', 'fan_only') %}true{% endif %}"  
  - condition: template
    value_template: "{% if is_state('climate.lounge_kitchen', 'cool') %}true{% endif %}"  
  action:
  - service: climate.set_hvac_mode
    data:
      entity_id: climate.lounge_kitchen
      hvac_mode: "fan_only"
  - service: climate.set_fan_mode
    data:
      entity_id: climate.lounge_kitchen
      fan_mode: "Low"

I’ve added some screenshots below to show the UI with the variables. I hope this gives someone an idea for an integration or Lovelace card, as I definitely don’t know how to do any of that.

8 Likes

This is very good and useful. Is there also a way to add “feels like” or a heat-index based on inside temperature and humidity

Hi, you could use the “heat index” formula here to combine the temperature and humidity into a single “feels-like” temperature…

Here is a template sensor I worked out to get the heat index from a DHT11 temp/humidity sensor. I can’t say how accurate it is since I don’t have a way to positively measure it (or I wouldn’t use the template sensor :wink:) but I found the formula online and came up with the template based on it. Interestingly, I found several discussions on calculating the heat index and many were different in some ways. I always assumed the calculation was an exact science but apparently not. I used the one that seemed the most “official” and had a general consensus.

- platform: template
  sensors:
    livingroom_heat_index:
      friendly_name: "Livingroom Heat Index"
      entity_id: sensor.livingroom_temperature
      unit_of_measurement: '°F'
      value_template: >
        {% set T = states.sensor.livingroom_temperature.state | float %}
        {% set RH = states.sensor.livingroom_humidity.state | float %}
        {% set HI_full = ((-42.379) + (2.04901523*T) + (10.14333127*RH) - (0.22475541*T*RH) - (0.00683783*T*T) - (0.05481717*RH*RH) + (0.00122874*T*T*RH) + (0.00085282*T*RH*RH) - (0.00000199*T*T*RH*RH)) | round (2) %}
        {% set adj1 =  (((13-RH)/4)*((17-(T-95.0)|abs)/17)|sqrt) | round (2) %}
        {% set adj2 = ((((RH-85)/10) * ((87-T)/5)))| round (2) %}
        {% set HI_simple = (0.5 * (T + 61.0 + ((T-68.0)*1.2) + (RH*0.094))) |round (2) %}
        {% if ((HI_simple + T)/2) >= 80 %}
          {% if RH < 13 and (T > 80 and T < 112) %}
            {{ (HI_full - adj1) | round (1) }}
          {% elif RH > 85 and (T > 80 and T < 87 ) %}
            {{ (HI_full + adj2) | round (1) }}
          {% else %}
            {{HI_full | round (1)}}
          {%endif%}
        {% else %}
          {{HI_simple | round (1)}}
        {% endif %}

I like your solution! What is the utility of the heat_overdrive_boolean?

Hi, so that automation sets the AC back to fan when on heat and the required temperature has been reached. When it’s really cold outside, or we go in and out a lot I have this boolean that I turn ON to just keep blasting hot air as much as possible. Rarely use it. There is then a separate automation that when I turn that boolean ON, the AC just go heat crazy :-)… so unless I turn it off the AC will keep going. Hope that makes sense

1 Like