blueprint: name: BZO's Smart A/C Temperature Control description: Comprehensive A/C control with automatic temperature management, presence detection, scheduling, and safety features domain: automation input: thermostat_section: name: Climate Unit & Sensors icon: mdi:thermostat input: # Core Devices ac_unit: name: A/C Unit description: The climate entity for your A/C unit selector: entity: domain: climate fan_mode_profile: name: Fan Mode Profile description: 'Fan mode: Standard for Auto, High, mid, low and numerif for Auto, 1, 2, etc.' default: standard selector: select: options: - standard - numeric room_temperature_sensor: name: Room Temperature Sensor description: Dedicated room temperature sensor selector: entity: domain: sensor #device_class: temperature external_temperature_sensor: name: External Temperature Sensor description: External temperature sensor for heat/cool mode selection selector: entity: domain: sensor device_class: temperature helper_section: name: Helper section icon: mdi:sun-clock collapsed: true input: # Helpers desired_temperature_helper: name: Desired Temperature Helper description: Input number helper to store desired temperature selector: entity: domain: input_number schedule_helper: name: Schedule Helper description: Schedule helper for time-based control selector: entity: domain: schedule override_helper: name: Override Helper description: Boolean helper to override automatic control selector: entity: domain: input_boolean away_mode_helper: name: (Optional) Away Mode Helper (turns off A/C) default: '' selector: entity: domain: input_boolean temp_control_waiting_helper: name: temp_control_waiting Helper selector: entity: domain: input_boolean temp_control_last_check_helper: name: temp_control_last_check Helper selector: entity: domain: input_datetime presence_section: name: Presence and Detection section icon: mdi:sun-clock collapsed: true input: window_detection_entity: name: Window Detection Entity description: Entity that detects if windows are open (binary_sensor) - Optional default: "" selector: entity: domain: binary_sensor # Presence Detection presence_entity: name: Presence Entity description: Entity that tracks if someone is home - Optional default: "" selector: entity: domain: - person - group # Timing Configuration home_duration: name: Home Duration description: Minutes to wait after arriving home before turning on A/C default: 5 selector: number: min: 0 max: 60 unit_of_measurement: minutes away_duration: name: Away Duration description: Minutes to wait after leaving home before turning off A/C default: 15 selector: number: min: 0 max: 120 unit_of_measurement: minutes window_reaction_time: name: Window Reaction Time description: Minutes to wait after window detection before taking action default: 2 selector: number: min: 0 max: 30 unit_of_measurement: minutes # off_duration_check: # name: Off Duration Check # description: Minutes to keep A/C off when desired temperature is reached # default: 10 # selector: # number: # min: 5 # max: 60 # unit_of_measurement: minutes no_action_duration: name: No Action Duration description: Minutes of no actions after A/C was turned off default: 5 selector: number: min: 1 max: 30 unit_of_measurement: minutes # restart_check_duration: # name: Restart Check Duration # description: Minutes to wait before checking if A/C should restart # default: 15 # selector: # number: # min: 5 # max: 60 # unit_of_measurement: minutes # Temperature Configuration temp_delta_low: name: Temperature Delta for Med Intensity description: Temperature difference to trigger low fan intensity default: 2.0 selector: number: min: 0.5 max: 5.0 step: 0.5 unit_of_measurement: "°C" temp_delta_high: name: Temperature Delta for High Intensity description: Temperature difference to trigger high fan intensity default: 3.0 selector: number: min: 1.0 max: 10.0 step: 0.5 unit_of_measurement: "°C" calibration_offset: name: Calibration Offset description: Temperature offset for A/C unit calibration default: 0.0 selector: number: min: -5.0 max: 5.0 step: 0.1 unit_of_measurement: "°C" cool_heat_threshold: name: Cool/Heat Threshold description: External temperature threshold to switch between cooling and heating default: 20.0 selector: number: min: 10.0 max: 30.0 step: 0.5 unit_of_measurement: "°C" debug_mode: name: Debug Mode description: 'Set Debug mode to show values for variables.' default: standard selector: select: options: - standard - debug variables: climate_dev: !input ac_unit room_temperature_sensor: !input room_temperature_sensor desired_temperature_helper: !input desired_temperature_helper external_temperature_sensor: !input external_temperature_sensor presence_entity: !input presence_entity schedule_helper: !input schedule_helper override_helper: !input override_helper window_detection_entity: !input window_detection_entity calibration_offset: !input calibration_offset cool_heat_threshold: !input cool_heat_threshold temp_delta_high: !input temp_delta_high temp_delta_low: !input temp_delta_low fan_profile: !input fan_mode_profile away: !input away_mode_helper temp_control_last_check: !input temp_control_last_check_helper temp_control_waiting: !input temp_control_waiting_helper no_action_duration_var: !input no_action_duration debug: !input debug_mode no_action_duration_sec: "{{ no_action_duration_var*60 }}" ac_off: "{{ is_state(climate_dev, 'off') }}" room_temp: "{{ states(room_temperature_sensor) | float(0) }}" desired_temp: "{{ states(desired_temperature_helper) | float(20) }}" external_temp: "{{ states(external_temperature_sensor) | float(20) }}" temp_delta: "{{ (room_temp - desired_temp) | abs }}" is_home: "{{ presence_entity == '' or is_state(presence_entity, 'home') }}" is_scheduled: "{{ is_state(schedule_helper, 'on') }}" is_override: "{{ is_state(override_helper, 'on') }}" is_window_open: "{{ window_detection_entity != '' and is_state(window_detection_entity, 'on') }}" should_cool: "{{ external_temp > cool_heat_threshold }}" should_heat: "{{ external_temp <= cool_heat_threshold }}" should_be_off: >- {% if should_cool %} {% if room_temp < (desired_temp - temp_delta_high) %} true {% else %} false {% endif %} {% else %} {% if room_temp > (desired_temp + temp_delta_high) %} true {% else %} false {% endif %} {% endif %} hvac_mode: >- {% if should_cool %} "cool" {% else %} "heat" {% endif %} calibrated_temp: >- {% if should_cool %} {% if room_temp > desired_temp %} {{ desired_temp - calibration_offset }} {% elif room_temp <= desired_temp %} {{ desired_temp }} {% endif %} {% else %} {% if room_temp > desired_temp %} {{ desired_temp }} {% elif room_temp <= desired_temp %} {{ desired_temp + calibration_offset }} {% endif %} {% endif %} climate_fan_mode: >- {% if fan_profile == 'standard' %} {% if ( temp_delta | abs ) >= temp_delta_high %} high {% elif ( temp_delta | abs ) >= temp_delta_low %} mid {% else %} auto {% endif %} {% else %} {% if ( temp_delta | abs ) >= temp_delta_high %} 5 {% elif ( temp_delta | abs ) >= temp_delta_low %} 3 {% else %} auto {% endif %} {% endif %} ac_fan_mode: "{{ state_attr(climate_dev, 'fan_mode') }}" trigger: - platform: state entity_id: !input desired_temperature_helper id: desire_temp_change # - platform: state # entity_id: !input room_temperature_sensor # id: temp_change - platform: state entity_id: !input schedule_helper id: schedule_change - platform: state entity_id: !input override_helper id: override_change # - platform: state # entity_id: !input external_temperature_sensor # id: external_temp_change - platform: state entity_id: !input away_mode_helper id: state - platform: state entity_id: !input temp_control_waiting_helper to: "off" id: temp_control_waiting_off #Time-based trigger to handle optional entities - platform: time_pattern minutes: "/5" id: periodic_check condition: [] action: - choose: - conditions: - condition: template value_template: "{{ not ac_off or ac_off}}" - condition: template value_template: "{{ debug == 'debug'}}" sequence: - service: logbook.log data: name: "Smart Climate" message: ' Room_temp = {{ room_temp }}°C, Desired_temp = {{ desired_temp }}°C Calculated = {{ calibrated_temp }}°C → Cool = {{ should_cool }} Fan_mode = {{ climate_fan_mode }}, AC_off = {{ ac_off }} AC_mode = {{ states(climate_dev) }} Temp_delta = {{ temp_delta }}, Is_Home = {{ is_home }} date= {{ states(temp_control_last_check) | as_datetime }}, seconds: {{ (now().timestamp() - states(temp_control_last_check) | as_datetime | as_timestamp) }} time_no_action: {{ no_action_duration_sec }} ' entity_id: !input ac_unit - choose: # AWAY mode - turn off A/C if on, otherwise stop - conditions: - condition: template value_template: > {{ away != '' and is_state(away, 'on') }} sequence: - choose: - conditions: - condition: not conditions: - condition: state entity_id: !input ac_unit state: "off" sequence: - service: climate.turn_off target: entity_id: !input ac_unit - service: logbook.log data: name: "Smart Climate" message: "A/C turned off due to Away Mode" entity_id: !input ac_unit default: - stop: "Away mode active but A/C already off" - stop: "Away mode active" # Window open - turn off A/C - conditions: - condition: template value_template: "{{ is_window_open }}" - "{{ not ac_off }}" sequence: - service: climate.turn_off target: entity_id: !input ac_unit - service: logbook.log data: name: "Smart Climate" message: "A/C turned off due to Window detected open" entity_id: !input ac_unit - stop: "Window detected open" # Not home - turn off A/C - conditions: - condition: template value_template: "{{ not is_home }}" sequence: - choose: - conditions: - condition: not conditions: - condition: state entity_id: !input ac_unit state: "off" sequence: - service: climate.turn_off target: entity_id: !input ac_unit - service: logbook.log data: name: "Smart Climate" message: "A/C turned off due Nobody Home" entity_id: !input ac_unit default: - stop: "Nobody Home active but A/C already off" - stop: "Nobody Home mode active" # Not scheduled - turn off A/C - conditions: - condition: template value_template: "{{ not is_scheduled }}" - "{{ not is_override }}" #- "{{ not ac_off }}" sequence: - choose: - conditions: - condition: not conditions: - condition: state entity_id: !input ac_unit state: "off" sequence: - service: climate.turn_off target: entity_id: !input ac_unit - service: logbook.log data: name: "Smart Climate" message: "A/C turned off due Outside schedule" entity_id: !input ac_unit default: - stop: "Outside schedule active but A/C already off" - stop: "Outside schedule mode active" # Currently waiting - check if 10 minutes have passed - conditions: - condition: state entity_id: !input temp_control_waiting_helper state: 'on' - condition: template value_template: >- {{ (now().timestamp() - states(temp_control_last_check) | as_datetime | as_timestamp) >= no_action_duration_sec }} sequence: - if: - condition: template value_template: >- {{ (should_cool and room_temp <= desired_temp) or (not should_cool and room_temp >= desired_temp) }} then: - service: input_datetime.set_datetime target: entity_id: !input temp_control_last_check_helper data: datetime: "{{ now() }}" - if: - condition: template value_template: >- {{ (should_cool and room_temp < desired_temp) or (should_heat and room_temp > desired_temp) }} then: - service: input_boolean.turn_off target: entity_id: !input temp_control_waiting_helper - service: logbook.log data: name: Temperature Control message: >- 10-minute wait completed. Rechecking temperature: {{ room_temp }}° vs {{ desired_temp }}° # Temperature reached target - turn off and wait - conditions: - condition: template value_template: "{{ room_temp + 0.5 <= desired_temp }}" - condition: state entity_id: !input ac_unit state: 'cool' sequence: - service: climate.turn_off target: entity_id: !input ac_unit - service: input_boolean.turn_on target: entity_id: !input temp_control_waiting_helper - service: input_datetime.set_datetime target: entity_id: !input temp_control_last_check_helper data: datetime: "{{ now() }}" - service: logbook.log data: name: Temperature Control message: >- Target reached ({{ room_temp }}° vs {{ desired_temp }}° ). Stopping unit for 10 minutes. - stop: "Temperature control cycle" # # Similar logic for heating mode - conditions: - condition: template value_template: "{{ room_temp - 0.5 > desired_temp }}" - condition: state entity_id: !input ac_unit state: 'heat' sequence: - service: climate.turn_off target: entity_id: !input ac_unit - service: input_boolean.turn_on target: entity_id: !input temp_control_waiting_helper - service: input_datetime.set_datetime target: entity_id: !input temp_control_last_check_helper data: datetime: "{{ now() }}" - service: logbook.log data: name: Temperature Control message: >- Target reached ({{ room_temp }}° vs {{ desired_temp }}°). Stopping unit for 10 minutes. - stop: "Temperature control cycle" # Main control logic default: - choose: # Cooling mode - conditions: - condition: template value_template: "{{ should_cool and (is_scheduled or is_override) }}" - condition: and conditions: - "{{ (room_temp + 0.5) >= desired_temp and ((climate_fan_mode != state_attr(climate_dev, 'fan_mode') or calibrated_temp != state_attr(climate_dev, 'temperature') or ac_off)) }}" - condition: state entity_id: !input temp_control_waiting_helper state: 'off' sequence: - service: climate.set_temperature target: entity_id: !input ac_unit data: temperature: "{{ calibrated_temp | abs }}" hvac_mode: cool - choose: # High intensity - conditions: - condition: template value_template: "{{ temp_delta >= temp_delta_high }}" sequence: - service: climate.set_fan_mode target: entity_id: !input ac_unit data: fan_mode: "{{ climate_fan_mode }}" # Low intensity - conditions: - condition: template value_template: "{{ temp_delta >= temp_delta_low }}" sequence: - service: climate.set_fan_mode target: entity_id: !input ac_unit data: fan_mode: "{{ climate_fan_mode }}" # Auto intensity (default) default: - service: climate.set_fan_mode target: entity_id: !input ac_unit data: fan_mode: auto # Heating mode - conditions: - condition: template value_template: "{{ should_heat and (is_scheduled or is_override) }}" - condition: and conditions: #- states(climate_dev) != heat - "{{ (room_temp - 0.5) <= desired_temp and (climate_fan_mode != state_attr(climate_dev, 'fan_mode') or calibrated_temp != state_attr(climate_dev, 'temperature') or ac_off) }}" sequence: - service: climate.set_temperature target: entity_id: !input ac_unit data: temperature: "{{ calibrated_temp }}" hvac_mode: heat - choose: # High intensity - conditions: - condition: template value_template: "{{ temp_delta >= temp_delta_high }}" sequence: - service: "{{ climate_fan_mode }}" target: entity_id: !input ac_unit data: fan_mode: high # Low intensity - conditions: - condition: template value_template: "{{ temp_delta >= temp_delta_low }}" sequence: - service: "{{ climate_fan_mode }}" target: entity_id: !input ac_unit data: fan_mode: mid # Auto intensity (default) default: - service: climate.set_fan_mode target: entity_id: !input ac_unit data: fan_mode: auto # Turn off if temperature is within acceptable range default: - condition: template value_template: "{{ should_be_off == true }}" - service: climate.turn_off target: entity_id: !input ac_unit mode: queued max_exceeded: silent