644 lines
22 KiB
YAML
644 lines
22 KiB
YAML
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.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
|
|
|
|
# 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
|