Should I Open the Windows? Binary Sensor Script v2.0

v2.0
Here is a script to determine if you should open the windows to cool or heat the house.

In addition to the indoor and outdoor temperatures, this script takes into account humility (using the dew point as a linear value). To determine if the humidity is rising or falling, it uses the calculus derivative of the dew point (rising = >0 and falling = <0).

This script uses weather forecast data as well as 24h averages of indoor temperatures to determine if summer or winter activity should be displayed. Summer activity is defined by opening the windows to cool the house. Winter activity is defined as opening the windows to heat the house. Defining these time periods is essential for transitions between the seasons.

Using this sensor, automations can announce the moment windows should be open and remind you of the status when you come home each day. Enjoy!

Binary Sensor: Using helpers, create a template binary sensor with the following:

{% set forecast_high = state_attr('sensor.weather_forecast_daily', 'forecast')[0].temperature|float %}
{% set forecast_tomorrow = state_attr('sensor.weather_forecast_daily', 'forecast')[1].temperature |float %}
{% set indoor_temp_av = states('sensor.indoor_temperature_24h_average')|float %}
{% set outside_temp = states('sensor.outdoor_temp_average')|float(states('sensor.outdoor_temperature')|float) %}
{% set inside_temp = states('sensor.indoor_temp_average')|float %}
{% set inside_setpoint = state_attr('climate.thermostat','temperature')|float(70)%}
{% set thermostat_on = is_state('climate.thermostat','cool') or is_state('climate.thermostat','heat') %}
{% set curr_high = (state_attr('sensor.weather_forecast_daily', 'forecast')[0].temperature |float + state_attr('sensor.weather_forecast_daily', 'forecast')[1].temperature |float + state_attr('sensor.weather_forecast_daily', 'forecast')[2].temperature |float)/3 %}
{% set future_high = (state_attr('sensor.weather_forecast_daily', 'forecast')[2].temperature |float + state_attr('sensor.weather_forecast_daily', 'forecast')[3].temperature |float + state_attr('sensor.weather_forecast_daily', 'forecast')[4].temperature |float)/3 %}
{% set delta_high = future_high - curr_high | float %}
{% set def_summer = indoor_temp_av>75 or forecast_high>82 %}
{% set more_prob_summer =  indoor_temp_av>72.5 and indoor_temp_av<75 and (delta_high+5>0 or forecast_high>77) and forecast_tomorrow>70 %}
{% set less_prob_summer = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (delta_high+2>0 or forecast_high>79) and forecast_tomorrow>74 %}
{% set poss_summer = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (delta_high>2 or forecast_high>81) and forecast_tomorrow>78 %}
{% set summer = def_summer or more_prob_summer or less_prob_summer or poss_summer %}
{% set def_winter = indoor_temp_av<66.5 or forecast_high<65 %}
{% set more_prob_winter = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (delta_high<2 or forecast_high<71) and forecast_tomorrow<78 %}
{% set less_prob_winter = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (delta_high+2<0 or forecast_high<69) and forecast_tomorrow<74 %}
{% set poss_winter = indoor_temp_av>72.5 and indoor_temp_av<75 and (delta_high+5<0 or forecast_high<67) and forecast_tomorrow<70 %}
{% set winter = def_winter or more_prob_winter or less_prob_winter or poss_winter %}
{% set dew = states('sensor.dew_point_average')|float %}
{% set dew_der = states('sensor.derivative_dew_point)|float %}
{% set dew_low = dew < 62 and inside_temp > dew + 4 %}
{% set dew_fall = dew < 65.5 and dew_der + 0.25 < 0 and inside_temp > dew + 4 %}
{% set dew_ideal = dew_low or dew_fall %}
{% set warmer_outside = outside_temp > inside_temp %}
{% set warmer_inside = outside_temp < inside_temp %}
{% set setpoint_below_outside = inside_setpoint < outside_temp and warmer_outside %}
{% set setpoint_above_outside = inside_setpoint > outside_temp and warmer_inside %}
{% set open_in_winter = ((warmer_outside and not thermostat_on) or (setpoint_below_outside and thermostat_on)) and winter and dew_ideal %}
{% set open_in_summer = ((warmer_inside and not thermostat_on) or (setpoint_above_outside and thermostat_on)) and summer and dew_ideal %}
{% set blw_target_temp_heat = indoor_temp_av < 70 and inside_temp < 70 and warmer_outside and dew_ideal %}
{% set abv_target_temp_cool = indoor_temp_av > 70 and inside_temp > 70 and warmer_inside and dew_ideal %}
{% if winter == true or summer == true %}
{{open_in_winter or open_in_summer}}
{% else %}
{{blw_target_temp_heat or abv_target_temp_cool}}
{% endif %}

Forecast data: In the YAML configuration file, obtain forecast data:

template:
  - trigger:
      - platform: time_pattern
        hours: /8
      - platform: homeassistant
        event: start
    action:
      - service: weather.get_forecasts
        data:
          type: daily
        target:
          entity_id: weather.accuweatherhome_2
        response_variable: daily
    sensor:
      - name: Weather Forecast Daily
        unique_id: weather_forecast_daily
        state: "{{ now().isoformat() }}"
        attributes:
          forecast: "{{ daily['weather.accuweatherhome_2'].forecast }}"

Explained Variables:

  • Indoor/Outdoor Temperature - I average the indoor and outdoor temperatures using statistics sensors to prevent the rapid crossing of the lines and minimize alerts to open, close, then re-open windows. The max age for these sensors is 1-2 hours.
  • Indoor Temperature Average - I average the indoor temperatures for the past 24 hours to capture the variability of lows when the sun has set and highs with the afternoon sun.
  • Inside Setpoint - This reflects the target temperature of the thermostat. Your thermostat cools or heats to this number.
  • Delta High - This identifies if the forecast reflects the next few days will be warmer or cooler than today’s outdoor temperatures.
  • Below Target Temperature Heat / Above Target Temperature Cool - These are fall backs for if the script is unable to determine if summer or winter activity should be displayed.

Temperature and Humidity Assumptions:

  • The script assumes the desired temperature year round is 70F
  • The script assumes that higher temperatures are tolerated when a ‘cold snap’ is coming through
  • This script assumes that lower temperatures are tolerated when a ‘heat wave’ is expected
  • This script assumes a dew point above 65F feels oppressively humid
  • This script assumes a dew point below 62F is tolerable
11 Likes

That’s great!!

Today is a perfect example of why your script is needed. Last night it was cooler out than in, but the humidity made it feel much more uncomfortable. So no point in opening the windows and shutting off the air conditioning.

Now, we just need smart windows we can control through HA and we’d be all set!

1 Like

Hey User87, thanks for the script. Its given me some things to think about as I was only going to work off temperature differences. Before I get too deep in questions:

  • Have you found a better way since this post?
  • Do you know of an automation template that does this?

If not could you explain why you use multiple dew points and how they influence heating/cooling? Did you use any formulas for your calculations?

I have minimal understanding of optimal thermal transfer. I have sensor for both inside and outside:

  • temperature
  • humidity
  • dew point (formula based on temperature and humidity).

If it helps to explain I have huge swings in temperature during summer e.g. 105F high (2pm) 55F low (5am). Humidity 100% high (2pm) 20% low (5am).

Thanks for any input.

Hi! Glad to hear you have interest in this idea! I’ve been working on this concept for well over a year and my original script has received significant revision. I am excited to hear how you will modify it.

Here’s my script as of today:

template:
  - binary_sensor:
      - name: "Windows should be open"
        unique_id: windows_should_be_open
        state: >-
          {% set forecast_high = states('sensor.openweathermap_forecast_temperature')|float %}
          {% set forecast_tomorrow = state_attr('weather.openweathermap', 'forecast')[1].temperature |float %}
          {% set indoor_temp_av = states('sensor.indoor_temperature_24h_average')|float %}
          {% set out_temp_derv = states('sensor.derivative_24h_out_ave_temp')|float %}
          {% set outside_temp = states('sensor.outdoor_temp_average')|float %}
          {% set inside_temp = states('sensor.indoor_temp_average')|float %}
          {% set def_summer = indoor_temp_av>72.5 or forecast_high>80 %}
          {% set prob_summer = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (out_temp_derv>0.50 or forecast_high>75) and forecast_tomorrow>70 %}
          {% set poss_summer = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (out_temp_derv>2 or forecast_high>77) and forecast_tomorrow>70 %}
          {% set summer = def_summer or prob_summer or poss_summer %}
          {% set def_winter = indoor_temp_av<66.5 or forecast_high<65 %}
          {% set prob_winter = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (out_temp_derv+1<0 or forecast_high<72) and forecast_tomorrow<79 %}
          {% set poss_winter = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (out_temp_derv+3<0 or forecast_high<70) and forecast_tomorrow<79 %}
          {% set winter = def_winter or prob_winter or poss_winter %}
          {% set dew = states('sensor.dew_point_average')|float %}
          {% set dew_der = states('sensor.derivative_dew_point_2')|float %}
          {% set dew_low = dew < 62 and inside_temp > dew + 4 %}
          {% set dew_fall = dew < 65.5 and dew_der + 0.25 < 0 and inside_temp > dew + 4 %}
          {% set dew_ideal = dew_low or dew_fall %}
          {% set warmer_outside = outside_temp > inside_temp %}
          {% set warmer_inside = outside_temp < inside_temp %}
          {% set heat_house = warmer_outside and winter %}
          {% set cool_house = warmer_inside and summer %}
          {% set open_in_winter = heat_house and dew_ideal %}
          {% set open_in_summer = cool_house and dew_ideal %}
          {{ open_in_winter or open_in_summer }}

Here’s some explanation of the variables:

sensor:
  - platform: statistics
    name: "Indoor Temperature 24h Average"
    entity_id: sensor.thermostat_00_current_temperature
    state_characteristic: mean
    max_age:
      hours: 23.98
    sampling_size: 720
  - platform: statistics
    name: "Indoor Temp Average"
    entity_id: sensor.thermostat_00_current_temperature
    state_characteristic: mean
    max_age:
      hours: 0.53
    sampling_size: 30
  - platform: statistics
    name: "Outdoor Temperature 24h Average"
    entity_id: sensor.openweathermap_temperature
    state_characteristic: mean
    max_age:
      hours: 23.96
    sampling_size: 150
  - platform: statistics
    name: "Outdoor Temp Average"
    entity_id: sensor.openweathermap_temperature
    state_characteristic: mean
    max_age:
      hours: 0.58
    sampling_size: 10
  - platform: statistics
    name: "Dew Point Average"
    entity_id: sensor.openweathermap_dew_point
    state_characteristic: mean
    max_age:
      hours: 2.96
    sampling_size: 20

First, one of the most difficult things to define in this script was identifying when ‘summer’ behavior should be displayed (cooling the house with open windows) and when ‘winter’ behavior should be displayed (heating the house with open windows). For me there is a great deal of transition time between winter behavior and summer behavior and vice versa. I want to cool the house when the season is moving from winter to summer, but only if tomorrow’s forecast is >70. I want to heat the house when the season is going from summer to winter, but only if the forecast high is <80. Hence, there are a lot of rules that evaluate the 24 hour average of temperatures inside, the high for the current day, the forecast high for tomorrow, and the outdoor temperature 24h derivative (i.e. is it becoming hotter each day [progressing from winter to summer] or is it becoming cooler each day [progressing from summer to winter]. It seems to work really well now!

Second, I do not want to open the windows if the humidity outside feels oppressive. For me, I find that the dew point is the best linear marker of humidity with higher values corresponding to oppressive humidity and lower values corresponding to comfortable conditions. Relative humidity does not linearly reflect the comfort level. A dew point less than 60 does not feel humid. A dew point over 65.5 feels too oppressive to open the windows. The behavior between 60 and 65.5 is determined by the derivative of the dew point (i.e. is the dew point rising or is the dew point falling).

Third, I found there to be too many intersections of the indoor temperature and the outdoor temperature when I used the momentary sensor data. I would receive alerts to open the windows, close the windows, then open them again in a relatively short amount of time. I want one conclusive alert. To mitigate this phenomenon, I used a short term average of the real time sensor data (<60 minutes) as defined above. This helps smooth out the curve of the real time data.

As far as automation, I have TTS alerts to close the windows when the sensor moves from on to off as well as TTS alerts to open the windows when the sensor moves from off to on. I also have a secondary binary sensor that does not take account of the ‘ideal’ dew point which provides a subsequent alert if the windows remain open and the primary sensor is off, should I ignore the original TTS notification.

I have enjoyed modifying this script extensively. It does not account for the phenomenon that sometimes I want to open the windows before the conditions are ideal (when I go to bed), but it works wonderfully and has saved me significant real dollars on my electricity bill.

3 Likes

Here’s an automation to open the windows before bedtime when the conditions will become ideal before awakening.

alias: Thermostat Sleep Open Windows Before Bed
description: ""
trigger:
  - platform: time
    at: "22:05:00"
condition:
  - condition: state
    entity_id: binary_sensor.people_home
    state: "on"
  - condition: state
    entity_id: input_boolean.alerts
    state: "on"
  - condition: state
    entity_id: input_boolean.alerts_minor
    state: "on"
  - condition: numeric_state
    entity_id: sensor.derivative_outdoor_temperature
    below: 0
  - condition: numeric_state
    entity_id: sensor.openweathermap_dew_point
    below: 70
  - condition: template
    value_template: "{{state_attr('weather.openweathermap', 'forecast')[1].templow < 66 }}"
    alias: Forecast Low Tomorrow is < Value
  - condition: template
    value_template: |2-
                {% set forecast_high = states('sensor.openweathermap_forecast_temperature')|float %}
                {% set forecast_tomorrow = state_attr('weather.openweathermap', 'forecast')[1].temperature |float %}
                {% set indoor_temp_av = states('sensor.indoor_temperature_24h_average')|float %}
                {% set out_temp_derv = states('sensor.derivative_24h_out_ave_temp')|float %}
                {% set outside_temp = states('sensor.outdoor_temp_average')|float %}
                {% set inside_temp = states('sensor.indoor_temp_average')|float %}
                {% set def_summer = indoor_temp_av>72.5 or forecast_high>80 %}
                {% set prob_summer = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (out_temp_derv>0.50 or forecast_high>75) and forecast_tomorrow>70 %}
                {% set poss_summer = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (out_temp_derv>2 or forecast_high>77) and forecast_tomorrow>70 %}
                {% set summer = def_summer or prob_summer or poss_summer %}
                {{ summer }}
    alias: Summer is On
  - condition: not
    conditions:
      - condition: state
        entity_id: input_boolean.sleep
        state: "on"
        for:
          hours: 0
          minutes: 30
          seconds: 0
  - condition: not
    conditions:
      - condition: state
        entity_id: input_boolean.windows_open
        state: "on"
        for:
          hours: 0
          minutes: 30
          seconds: 0
action:
  - variables:
      indoor_temp: "{{states('sensor.thermostat_00_current_temperature')|round}}"
      outdoor_temp: "{{states('sensor.openweathermap_temperature')|round}}"
      templow: "{{state_attr('weather.openweathermap', 'forecast')[1].templow}}"
      message_cool: >-
        Tonight the temperature outside will get down to {{templow}} degrees. It
        is currently {{indoor_temp}} degrees inside your home. It would seem
        logical to open the windows before you go to bed to cool the house and
        save electricity.
  - service: script.palm_speech_engine
    data:
      message: "{{message_cool}}"
      player: media_player.alerts
mode: single

well this is cool. i was just comparing temp of a sensor on my patio vs at my thermostat. I have a time of use plan that rates are cheaper before 5 pm and after 8 pm, so on hot days a preload to get it as cold as my old inefficient house can get then let it coast after 5 pm. Since it starts creeping back up again, esp upstairs, I then wonder if I should open the windows and will that let what cool air may still be inside out ?or is it cooler outside and I should open windows?

So if I copy your sensors and the script, and then that last automation you posted with a time of 6 pm does that make sense? this is my simple automation now. `alias: Temp at 6pm (Check Every 30 Minutes)
description: Check temperature every 30 minutes between 6 PM and 8 PM and at 6 PM
trigger:

  • platform: time
    at: “18:00:00”
  • platform: time_pattern
    minutes: /30
    condition:
  • condition: time
    after: “18:00:00”
    before: “20:00:00”
  • condition: numeric_state
    entity_id: sensor.smartsensemotion_temperature
    below: sensor.office_temperature
    action:
  • service: climate.turn_off
    data: {}
  • service: tts.cloud_say
    data:
    cache: false
    entity_id: media_player.move
    message: It is ok to open windows
    mode: single`

i changed it to

`alias: Temp at 6pm (Check Every 30 Minutes)
description: Check ‘Windows should be open’ every 30 minutes between 6 PM and 8 PM
trigger:

  • platform: time_pattern
    minutes: /30
    condition:
  • condition: time
    after: “18:00:00”
    before: “20:00:00”
  • condition: state
    entity_id: binary_sensor.windows_should_be_open
    state: “on”
    action:
  • service: climate.turn_off
    data: {}
  • service: tts.cloud_say
    data:
    cache: false
    entity_id: media_player.move
    message: “It’s a good time to open the windows and turn off the AC .”
    mode: single`

As of HA 2023.9, template binary sensors from the UI are now recommended over the YAML configuration file.

I have made a few minor changes to the binary sensor. It now uses the differences in the future forecast high compared against the current forecast high (delta_high) instead of the outdoor temperature derivative (out_temp_derv). This will allow forward weather forecast data to influence the definition of summer and winter behavior rather than historical weather changes (derivative). Additionally, there is a fail-safe if neither summer or winter are defined.

#Should I Open the Windows Binary Sensor v2023.09
{% set forecast_high = states('sensor.openweathermap_forecast_temperature')|float %}
{% set forecast_tomorrow = state_attr('weather.openweathermap', 'forecast')[1].temperature |float %}
{% set indoor_temp_av = states('sensor.indoor_temperature_24h_average')|float %}
{% set outside_temp = states('sensor.outdoor_temp_average')|float %}
{% set inside_temp = states('sensor.indoor_temp_average')|float %}
{% set curr_high = (state_attr('weather.openweathermap', 'forecast')[0].temperature |float + state_attr('weather.openweathermap', 'forecast')[1].temperature |float + state_attr('weather.openweathermap', 'forecast')[2].temperature |float)/3 %}
{% set future_high = (state_attr('weather.openweathermap', 'forecast')[2].temperature |float + state_attr('weather.openweathermap', 'forecast')[3].temperature |float + state_attr('weather.openweathermap', 'forecast')[4].temperature |float)/3 %}
{% set delta_high = future_high - curr_high | float %}
{% set def_summer = indoor_temp_av>72.5 or forecast_high>82 %}
{% set prob_summer = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (delta_high+2>0 or forecast_high>79) and forecast_tomorrow>70 %}
{% set poss_summer = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (delta_high>2 or forecast_high>81) and forecast_tomorrow>75 %}
{% set summer = def_summer or prob_summer or poss_summer %}
{% set def_winter = indoor_temp_av<66.5 or forecast_high<65 %}
{% set prob_winter = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (delta_high<2 or forecast_high<71) and forecast_tomorrow<82 %}
{% set poss_winter = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (delta_high+2<0 or forecast_high<69) and forecast_tomorrow<79 %}
{% set winter = def_winter or prob_winter or poss_winter %}
{% set dew = states('sensor.dew_point_average')|float %}
{% set dew_der = states('sensor.derivative_dew_point_2')|float %}
{% set dew_low = dew < 62 and inside_temp > dew + 4 %}
{% set dew_fall = dew < 65.5 and dew_der + 0.25 < 0 and inside_temp > dew + 4 %}
{% set dew_ideal = dew_low or dew_fall %}
{% set warmer_outside = outside_temp > inside_temp %}
{% set warmer_inside = outside_temp < inside_temp %}
{% set open_in_winter = warmer_outside and winter and dew_ideal %}
{% set open_in_summer = warmer_inside and summer and dew_ideal %}
{% set blw_target_temp_heat = indoor_temp_av < 70 and inside_temp < 70 and warmer_outside and dew_ideal %}
{% set abv_target_temp_cool = indoor_temp_av > 70 and inside_temp > 70 and warmer_inside and dew_ideal %}
{% if winter == true or summer == true %}
{{open_in_winter or open_in_summer}}
{% else %}
{{blw_target_temp_heat or abv_target_temp_cool}}
{% endif %}

If you are using the “Open the Windows Before Bed” Automation, then I have also created a binary sensor for summer behavior, which should be used instead of the value template ‘Summer is On.’

{% set forecast_high = states('sensor.openweathermap_forecast_temperature')|float %}
{% set forecast_tomorrow = state_attr('weather.openweathermap', 'forecast')[1].temperature |float %}
{% set indoor_temp_av = states('sensor.indoor_temperature_24h_average')|float %}
{% set outside_temp = states('sensor.outdoor_temp_average')|float %}
{% set inside_temp = states('sensor.indoor_temp_average')|float %}
{% set curr_high = (state_attr('weather.openweathermap', 'forecast')[0].temperature |float + state_attr('weather.openweathermap', 'forecast')[1].temperature |float + state_attr('weather.openweathermap', 'forecast')[2].temperature |float)/3 %}
{% set future_high = (state_attr('weather.openweathermap', 'forecast')[2].temperature |float + state_attr('weather.openweathermap', 'forecast')[3].temperature |float + state_attr('weather.openweathermap', 'forecast')[4].temperature |float)/3 %}
{% set delta_high = future_high - curr_high | float %}
{% set def_summer = indoor_temp_av>72.5 or forecast_high>82 %}
{% set prob_summer = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (delta_high+2>0 or forecast_high>79) and forecast_tomorrow>70 %}
{% set poss_summer = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (delta_high>2 or forecast_high>81) and forecast_tomorrow>75 %}
{% set summer = def_summer or prob_summer or poss_summer %}
{% set warmer_outside = outside_temp > inside_temp %}
{% set warmer_inside = outside_temp < inside_temp %}
{% set abv_target_temp_cool = indoor_temp_av > 70 and inside_temp > 70 and warmer_inside %}
{% if winter == true or summer == true %}
{{summer}}
{% else %}
{{abv_target_temp_cool}}
{% endif %}

Sadly, these templates use the depreciated attribute forecast data, so I may have to learn how to use the weather forecast service implemented in HA 2023.9.

Your automation seems reasonable. Is there a reason you have it check every thirty minutes and only between 6PM and 8PM? Would you not want to open the windows at other hours of the day? Would you only want to be notified on the half hour to avoid disturbance?

I have one automation that looks for the binary_sensor.windows_should_be_open state change form ‘off’ to ‘on’ (at any hour of the day / when not sleeping) to trigger an announcement to open the windows (and turn off the thermostat) and another automation that looks for the binary_sensor.windows_should_be_open state change from ‘on’ to ‘off’ to trigger an announcement to close the windows (and turn on the thermostat). I find that these events usually only happen twice a day: one to open the windows and one to close the windows.

Hi User87 - did you ever get this working with the new weather.get_forecasts service?

Also, can you share the senor code for:
'sensor.openweathermap_forecast_temperature

thanks

Hello. I did getting it running, with the new weather.get_forecasts service.

Add the following to your configuration.yaml file:

template:
  - trigger:
      - platform: time_pattern
        hours: /4
      - platform: homeassistant
        event: start
    action:
      - service: weather.get_forecasts
        data:
          type: daily
        target:
          entity_id: weather.openweathermap
        response_variable: daily
    sensor:
      - name: Weather Forecast Daily
        unique_id: weather_forecast_daily
        state: "{{ now().isoformat() }}"
        attributes:
          forecast: "{{ daily['weather.openweathermap'].forecast }}"

Then, change your binary sensor template to the following

#Should I Open the Windows Binary Sensor v2024.02
{% set forecast_high = states('sensor.openweathermap_forecast_temperature')|float %}
{% set forecast_tomorrow = state_attr('sensor.weather_forecast_daily', 'forecast')[1].temperature |float %}
{% set indoor_temp_av = states('sensor.indoor_temperature_24h_average')|float %}
{% set outside_temp = states('sensor.outdoor_temp_average')|float %}
{% set inside_temp = states('sensor.indoor_temp_average')|float %}
{% set curr_high = (state_attr('sensor.weather_forecast_daily', 'forecast')[0].temperature |float + state_attr('sensor.weather_forecast_daily', 'forecast')[1].temperature |float + state_attr('sensor.weather_forecast_daily', 'forecast')[2].temperature |float)/3 %}
{% set future_high = (state_attr('sensor.weather_forecast_daily', 'forecast')[2].temperature |float + state_attr('sensor.weather_forecast_daily', 'forecast')[3].temperature |float + state_attr('sensor.weather_forecast_daily', 'forecast')[4].temperature |float)/3 %}
{% set delta_high = future_high - curr_high | float %}
{% set def_summer = indoor_temp_av>75 or forecast_high>82 %}
{% set more_prob_summer =  indoor_temp_av>72.5 and indoor_temp_av<75 and (delta_high+5>0 or forecast_high>77) and forecast_tomorrow>70 %}
{% set less_prob_summer = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (delta_high+2>0 or forecast_high>79) and forecast_tomorrow>74 %}
{% set poss_summer = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (delta_high>2 or forecast_high>81) and forecast_tomorrow>78 %}
{% set summer = def_summer or more_prob_summer or less_prob_summer or poss_summer %}
{% set def_winter = indoor_temp_av<66.5 or forecast_high<65 %}
{% set more_prob_winter = indoor_temp_av>66.5 and indoor_temp_av<69.5 and (delta_high<2 or forecast_high<71) and forecast_tomorrow<78 %}
{% set less_prob_winter = indoor_temp_av>69.5 and indoor_temp_av<72.5 and (delta_high+2<0 or forecast_high<69) and forecast_tomorrow<74 %}
{% set poss_winter = indoor_temp_av>72.5 and indoor_temp_av<75 and (delta_high+5<0 or forecast_high<67) and forecast_tomorrow<70 %}
{% set winter = def_winter or more_prob_winter or less_prob_winter or poss_winter %}
{% set dew = states('sensor.dew_point_average')|float %}
{% set dew_der = states('sensor.derivative_dew_point_2')|float %}
{% set dew_low = dew < 62 and inside_temp > dew + 4 %}
{% set dew_fall = dew < 65.5 and dew_der + 0.25 < 0 and inside_temp > dew + 4 %}
{% set dew_ideal = dew_low or dew_fall %}
{% set warmer_outside = outside_temp > inside_temp %}
{% set warmer_inside = outside_temp < inside_temp %}
{% set open_in_winter = warmer_outside and winter and dew_ideal %}
{% set open_in_summer = warmer_inside and summer and dew_ideal %}
{% set blw_target_temp_heat = indoor_temp_av < 70 and inside_temp < 70 and warmer_outside and dew_ideal %}
{% set abv_target_temp_cool = indoor_temp_av > 70 and inside_temp > 70 and warmer_inside and dew_ideal %}
{% if winter == true or summer == true %}
{{open_in_winter or open_in_summer}}
{% else %}
{{blw_target_temp_heat or abv_target_temp_cool}}
{% endif %}

In the above, ‘sensor.openweathermap_forecast_temperature’ is provided by the OpenWeatherMap integration, but may be substituted for a different service if desired.

thats awesome - thank you so much!

Just a quick one - the “derivative” sensors for both out-temp and dew…what are these?

Great question! The outdoor temperature derivative is no longer used, so it can be removed. I edited the above template to reflect that. It was a relic of the past versions of the program. Before, I was using it to determine if the historic outdoor temperature was rising or falling. Now, I use the forecast highs to determine if the outdoor temperature is becoming warmer or colder over the next few days. (If it is becoming colder over the next few days, summer behavior should be exhibited. If it is becoming warmer over the next few days, winter behavior should be exhibited.)

The dew point derivative is still important, however. It allows the program to know if the dew point is rising (ie it’s becoming more humid) or falling (ie it’s becoming less humid). The mathematical (calculus) derivative is the same thing as the slope (rise over run) of the line in algebra. Hence, a positive slope indicates the dew point is rising and a negative slope indicates the dew point is falling. In home assistant, I created helpers that calculate the derivative of the dew point because there is no forecast dew point available.

riiiight got it - thanks mate.

one another note, for the (‘sensor.outdoor_temp_average’) - im guessing you have a sensor outside that you take for this?

Sadly I use the weather report rather than a sensor. But, I average values over a half hour to hopefully smooth out any jumping up and down. I don’t want to be notified to open the windows, then close the windows, then open them again in a short amount of time. Generally, I just one notification to open and one to close during the day.