blueprint: name: "🏰 Yet Another Automatic HVAC Control Bluprint (YAAHCB) following the KISS Principle" description: > Turns off the HVAC when a window or door is opened (binary sensor 'on'), with optional notifications for high humidity, low pressure, and temperature. Restores climate state when windows are closed (binary sensor 'off'). Starts a timer before turning off the HVAC for energy-saving purposes. domain: automation input: climate_entity: name: Climate Entity description: > Select the HVAC system entity to manage (e.g., air conditioning or heating). selector: entity: domain: climate window_sensors: name: Window/Door Sensors description: > The sensors that detect open windows or doors. selector: entity: domain: binary_sensor multiple: true temperature_sensor: name: Outside Temperature Sensor description: > Optional sensor for measuring outdoor temperature. selector: entity: domain: sensor device_class: temperature default: "" humidity_sensor: name: Outside Humidity Sensor description: > Optional sensor for measuring outdoor humidity. selector: entity: domain: sensor device_class: humidity default: "" pressure_sensor: name: Atmospheric Pressure Sensor description: > Optional sensor for measuring atmospheric pressure. selector: entity: domain: sensor device_class: atmospheric_pressure default: "" humidity_threshold: name: Humidity Threshold description: > Threshold for high humidity notifications. default: 60 selector: number: min: 0 max: 100 unit_of_measurement: "%" step: 1 pressure_threshold: name: Pressure Threshold description: > Threshold for low pressure notifications. default: 1000 selector: number: min: 900 max: 1050 unit_of_measurement: "hPa" step: 1 notify_device: name: Notify Device description: > Device to send notifications to. selector: device: integration: mobile_app window_open_timer: name: Timer for Window Open Notification description: > Select the timer to use when a window is opened. selector: entity: domain: timer temp_high_threshold: name: High Temperature Threshold description: > Temperature threshold above which HVAC will be turned off immediately when windows are opened (optional). default: 25 selector: number: min: 15 max: 40 unit_of_measurement: "°C" step: 0.5 temp_low_threshold: name: Low Temperature Threshold description: > Temperature threshold below which HVAC will be turned off immediately when windows are opened (optional). default: 15 selector: number: min: -5 max: 20 unit_of_measurement: "°C" step: 0.5 daytime_hvac_timeout: name: Daytime HVAC Off Timeout description: > How long to wait before turning off the HVAC during the day (e.g., 6:00-22:00). selector: duration: enable_day: false nighttime_hvac_timeout: name: Nighttime HVAC Off Timeout description: > How long to wait before turning off the HVAC during the night (e.g., 22:00-6:00). selector: duration: enable_day: false night_check_time: name: Nighttime Check Time description: > Time to check if any windows are still open before night (format: HH:MM). selector: time: night_start_time: name: Night Period Start description: > When the night period starts (format: HH:MM). selector: time: night_end_time: name: Night Period End description: > When the night period ends (format: HH:MM). selector: time: require_temperature_sensor: name: Require Temperature Sensor description: If enabled, automation will not run without a valid temperature sensor default: false selector: boolean: debug_mode: name: Debug Mode description: Enable additional logging for troubleshooting default: false selector: boolean: restore_climate_state: name: Remember Previous Climate State description: Restore the previous HVAC mode instead of always using auto default: true selector: boolean: seasonal_mode: name: Seasonal Mode description: Adjust behavior based on season default: auto selector: select: options: - auto - summer - winter notification_cooldown: name: Notification Cooldown description: Minimum time (in minutes) between notifications default: 5 selector: number: min: 1 max: 60 unit_of_measurement: "min" variables: humidity_sensor: !input humidity_sensor pressure_sensor: !input pressure_sensor temperature_sensor: !input temperature_sensor humidity_threshold: !input humidity_threshold pressure_threshold: !input pressure_threshold window_open_timer: !input window_open_timer window_sensors: !input window_sensors night_check_time: !input night_check_time night_start_time: !input night_start_time night_end_time: !input night_end_time daytime_hvac_timeout: !input daytime_hvac_timeout nighttime_hvac_timeout: !input nighttime_hvac_timeout temp_sensor_available: > {% set sensor = temperature_sensor %} {{ sensor | length > 0 and states(sensor) not in ['unknown', 'unavailable'] and states(sensor) | float(-1000) > -999 }} any_window_open: > {% for sensor in window_sensors %} {% if is_state(sensor, 'on') %} {{ true }} {% break %} {% endif %} {% endfor %} {{ false }} is_night_time: > {% set current_hour = now().hour %} {% set night_start = night_start_time.split(':')[0] | int %} {% set night_end = night_end_time.split(':')[0] | int %} {{ current_hour >= night_start or current_hour < night_end }} last_notification_key: "last_notification_{{trigger.entity_id}}" # Add a helper variable to get window names open_windows: > {% set names = [] %} {% for sensor in window_sensors %} {% if is_state(sensor, 'on') %} {% set name = state_attr(sensor, 'friendly_name') or area_name(sensor) or 'Unknown window' %} {% set names = names + [name] %} {% endif %} {% endfor %} {{ names | join(', ') }} closed_window: > {% if trigger.entity_id is defined %} {{ state_attr(trigger.entity_id, 'friendly_name') or area_name(trigger.entity_id) or 'Unknown window' }} {% else %} 'Unknown window' {% endif %} seasonal_temp_check: > {% set mode = seasonal_mode %} {% if mode == 'auto' %} {{ true }} {# Always check in auto mode #} {% elif mode == 'summer' and states(temperature_sensor) | float > temp_high_threshold %} {{ true }} {# In summer, only check high temps #} {% elif mode == 'winter' and states(temperature_sensor) | float < temp_low_threshold %} {{ true }} {# In winter, only check low temps #} {% else %} {{ false }} {% endif %} trigger: - platform: state entity_id: !input window_sensors from: "off" to: "on" - platform: state entity_id: !input window_sensors from: "on" to: "off" - platform: event event_type: timer.finished event_data: entity_id: !input window_open_timer - platform: time at: !input night_check_time condition: [] # [Previous blueprint configuration and variables remain exactly the same until the action section] action: - choose: # BLOCK 1: Window Opening Handler with Environmental Checks and HVAC Control - conditions: - condition: template value_template: > {% if trigger is defined %} {% if trigger.to_state is defined %} {{ trigger.to_state.state == 'on' }} {% elif trigger.event is defined %} {{ trigger.event.event_type != 'timer.finished' }} {% else %} false {% endif %} {% else %} false {% endif %} - condition: or conditions: - condition: state entity_id: !input window_open_timer state: "idle" - condition: template value_template: > {% if trigger is defined and trigger.event is defined %} {{ trigger.event.event_type == 'timer.finished' }} {% else %} false {% endif %} sequence: # Start notification timer only if it's idle - if: condition: state entity_id: !input window_open_timer state: "idle" then: - service: timer.start target: entity_id: !input window_open_timer # Initial window open notification (with notification cooldown check) - if: condition: template value_template: > {% set last_time = states('input_datetime.' + last_notification_key) %} {% if last_time != 'unknown' %} {% set time_diff = (as_timestamp(now()) - as_timestamp(last_time)) / 60 %} {{ time_diff > notification_cooldown }} {% else %} true {% endif %} then: - device_id: !input notify_device domain: mobile_app type: notify message: > 🚪 The window or door in {{ area_name(window_sensors[0]) | default('an unknown area') }} has been opened. The current outside temperature is {{ states(temperature_sensor) | float }}°C. {% if states(temperature_sensor) | float < 15 %} Please close it within {{ (state_attr(window_open_timer, 'duration').split(':')[1] | int) }} minute{{ 's' if (state_attr(window_open_timer, 'duration').split(':')[1] | int) > 1 else '' }} to conserve energy. {% endif %} # Check humidity immediately - if: condition: and conditions: - condition: template value_template: "{{ humidity_sensor != '' }}" - condition: numeric_state entity_id: !input humidity_sensor above: !input humidity_threshold then: - device_id: !input notify_device domain: mobile_app type: notify message: > 💧 The humidity outside is currently {{ states(humidity_sensor) | float }}%, which is above the {{ humidity_threshold }}% threshold. Please be cautious about increased humidity levels. # Check pressure immediately - if: condition: and conditions: - condition: template value_template: "{{ pressure_sensor != '' }}" - condition: numeric_state entity_id: !input pressure_sensor below: !input pressure_threshold then: - device_id: !input notify_device domain: mobile_app type: notify message: > 🌧️ The atmospheric pressure outside is currently {{ states(pressure_sensor) | float }} hPa, below the {{ pressure_threshold }} hPa threshold. This may indicate potential bad weather. Please be cautious. # Combined HVAC control with immediate and timed responses - choose: # Daytime handling - conditions: - condition: time after: !input night_end_time before: !input night_start_time sequence: - if: condition: or conditions: - condition: numeric_state entity_id: !input temperature_sensor above: !input temp_high_threshold - condition: numeric_state entity_id: !input temperature_sensor below: !input temp_low_threshold then: - service: climate.turn_off target: entity_id: !input climate_entity - device_id: !input notify_device domain: mobile_app type: notify message: > ❄️ HVAC turned off immediately due to outside temperature ({{ states(temperature_sensor) | float }}°C) being outside comfort range. else: - delay: !input daytime_hvac_timeout - condition: state entity_id: !input window_sensors state: "on" - service: climate.turn_off target: entity_id: !input climate_entity - device_id: !input notify_device domain: mobile_app type: notify message: > ⏱️ The window has remained open for {{ daytime_hvac_timeout.seconds // 60 }} minute{{'s' if daytime_hvac_timeout.seconds // 60 > 1 else ''}} during daytime. The HVAC system has been turned off for energy conservation. # Nighttime handling - conditions: - condition: time after: !input night_start_time before: !input night_end_time sequence: - if: condition: or conditions: - condition: numeric_state entity_id: !input temperature_sensor above: !input temp_high_threshold - condition: numeric_state entity_id: !input temperature_sensor below: !input temp_low_threshold then: - service: climate.turn_off target: entity_id: !input climate_entity - device_id: !input notify_device domain: mobile_app type: notify message: > ❄️ HVAC turned off immediately due to outside temperature ({{ states(temperature_sensor) | float }}°C) being outside comfort range. else: - delay: !input nighttime_hvac_timeout - condition: state entity_id: !input window_sensors state: "on" - service: climate.turn_off target: entity_id: !input climate_entity - device_id: !input notify_device domain: mobile_app type: notify message: > ⏱️ The window has remained open for {{ nighttime_hvac_timeout.seconds // 60 }} minute{{'s' if nighttime_hvac_timeout.seconds // 60 > 1 else ''}} during nighttime. The HVAC system has been turned off for energy conservation. # BLOCK 2: Window Closing Handler - conditions: - condition: template value_template: "{{ trigger.platform == 'state' and trigger.to_state.state == 'off' }}" sequence: # Cancel any running timer first - service: timer.cancel target: entity_id: !input window_open_timer # Check remaining open windows - variables: windows_still_open: > {% set open_count = 0 %} {% for sensor in window_sensors %} {% if is_state(sensor, 'on') %} {% set open_count = open_count + 1 %} {% endif %} {% endfor %} {{ open_count }} # Handle HVAC restoration and notifications - if: condition: template value_template: "{{ windows_still_open == 0 }}" then: - service: climate.turn_on target: entity_id: !input climate_entity - delay: 1 # Restore previous climate state or set to auto - if: condition: template value_template: "{{ restore_climate_state }}" then: - service: climate.set_hvac_mode target: entity_id: !input climate_entity data: hvac_mode: "{{ state_attr(climate_entity, 'hvac_mode') }}" else: - service: climate.set_hvac_mode target: entity_id: !input climate_entity data: hvac_mode: "auto" - device_id: !input notify_device domain: mobile_app type: notify message: > ✅ {{ closed_window }} has been closed. All windows are now closed. The HVAC system has been restored{% if restore_climate_state %} to its previous state{% else %} to auto mode{% endif %}. else: - device_id: !input notify_device domain: mobile_app type: notify message: > ℹ️ {{ closed_window }} has been closed. The following windows are still open: {{ open_windows }} # BLOCK 3: Timer Events Handler - conditions: - condition: and conditions: - condition: template value_template: > {% if trigger is defined and trigger.event is defined %} {{ trigger.event.event_type == 'timer.finished' and trigger.event.data.entity_id == window_open_timer }} {% else %} false {% endif %} - condition: state entity_id: !input window_sensors state: "on" - condition: state entity_id: !input window_open_timer state: "idle" sequence: - choose: # Temperature-based reminder when window is open too long - conditions: - condition: template value_template: "{{ temperature_sensor | length > 0 }}" - condition: numeric_state entity_id: !input temperature_sensor below: 15 sequence: - device_id: !input notify_device domain: mobile_app type: notify message: > 🥶 Reminder: The window or door in {{ area_name(window_sensors[0]) | default('an unknown area') }} has been open for {{ state_attr(window_open_timer, 'duration').split(':')[1] | int }} minutes. The outside temperature is below 15°C. Please check your windows. # Default reminder without temperature data - conditions: - condition: template value_template: "{{ temperature_sensor | length == 0 }}" sequence: - device_id: !input notify_device domain: mobile_app type: notify message: > ⏱️ Reminder: The window or door in {{ area_name(window_sensors[0]) | default('an unknown area') }} has been open for {{ state_attr(window_open_timer, 'duration').split(':')[1] | int }} minutes. Please close it to conserve energy. # BLOCK 4: Night Check Handler - conditions: - condition: template value_template: "{{ trigger.platform == 'time' }}" - condition: state entity_id: !input window_sensors state: "on" sequence: - device_id: !input notify_device domain: mobile_app type: notify message: > 🌙 Night Check: A window or door in {{ area_name(window_sensors[0]) | default('your home') }} is still open. Please close it before going to bed (night period starts at {{ night_start_time }}). Current outside temperature: {{ states(temperature_sensor) | float }}°C. mode: restart