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