Update blueprints/automations/bzo_climate.yaml

latest version
This commit is contained in:
2025-11-12 11:05:08 +02:00
parent 6f7514f145
commit 7102f5ec6e

View File

@@ -1,137 +1,20 @@
blueprint:
name: BZO's Smart Climate Controller
description: >
Automatically control a climate device based on indoor/outdoor temperatures,
using one command per update. Sends HVAC mode, temperature, and fan settings
only if different from current state. Supports external temp threshold for heat/cool switching,
presence, schedule, optional override, optional away mode, logging level, and optional window detection.
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:
climate_entity:
name: Climate Device
description: 'Selet the unit or units that will be controled.'
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
room_temp_sensor:
name: Room Temperature Sensor
description: 'Sensor or group of sensors used to calculate thermostat values.'
selector:
entity:
domain: sensor
device_class: temperature
outdoor_temp_sensor:
name: Outdoor Temperature Sensor
description: 'Used to determine HVAC mode ( cool or heat ).'
selector:
entity:
domain: sensor
device_class: temperature
presence_entity:
name: ( Optional ) Presence Sensor or Group
description: 'Used to tun off the units if house is empty.'
default: ''
selector:
entity:
domain: person
schedule_entity:
name: Schedule Helper
description: 'Schedule for the unit to run.'
selector:
entity:
domain: schedule
override_switch:
name: (Optional) Manual Override Switch
description: 'Override presence and schedule and turn on the unit.'
default: ''
selector:
entity:
domain: input_boolean
away_mode_helper:
name: (Optional) Away Mode Helper (turns off A/C)
default: ''
selector:
entity:
domain: input_boolean
window_sensor:
name: (Optional) Window Sensor
default: ''
selector:
entity:
domain: binary_sensor
delta_fan_low:
name: Temperature Delta for Mid Fan
default: 2
selector:
number:
min: 1
max: 5
step: 0.5
unit_of_measurement: °C
delta_fan_high:
name: Temperature Delta for High Fan
default: 3
selector:
number:
min: 2
max: 10
step: 0.5
unit_of_measurement: °C
external_temp_threshold:
name: External Temperature Heat/Cool Switch Threshold
default: 18
selector:
number:
min: -10
max: 35
step: 1
unit_of_measurement: °C
target_temp_helper:
name: Target Temperature Helper
description: '
Control your comfort temperature via automations or the UI, you can
specify an *[input_number](https://www.home-assistant.io/integrations/input_number/)*
entity here.
Create your helper [here](https://my.home-assistant.io/redirect/helpers/). '
selector:
entity:
domain: input_number
temp_adjust_threshold:
name: Temperature Delta Adjustment Threshold
description: 'The Delta value, representing the difference between the desired and actual temperature, will adjust the thermostat.'
default: 4
selector:
number:
min: 0
max: 10
step: 0.5
unit_of_measurement: °C
temp_adjust_amount:
name: Temperature Adjustment Amount
description: 'How many degrees to add or subtract if the difference between the desired temp and actual temp is higher than Delta.'
default: 1
selector:
number:
min: 0
max: 5
step: 0.5
unit_of_measurement: °C
fan_mode_profile:
name: Fan Mode Profile
description: 'Fan mode: Standard for Auto, High, mid, low and numerif for Auto, 1, 2, etc.'
@@ -142,220 +25,619 @@
- standard
- numeric
log_level:
name: Logging Level
default: info
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:
- info
- standard
- debug
mode: restart
max_exceeded: silent
trigger_variables:
override_switch: !input override_switch
trigger:
- platform: time_pattern
minutes: "/5"
- platform: state
entity_id: !input schedule_entity
to: "on"
- platform: state
entity_id: !input target_temp_helper
condition:
- condition: template
value_template: >
{{ override_switch == '' or is_state( override_switch, 'off') }}
- condition: state
entity_id: !input schedule_entity
state: "on"
# - condition: state
# entity_id: !input presence_entity
# state: "home"
# - condition: template
# value_template: >
# {% set window = window_sensor %}
# {{ window == '' or is_state(window, 'off') }}
action:
- variables:
climate: !input climate_entity
room_sensor: !input room_temp_sensor
outside_sensor: !input outdoor_temp_sensor
target_temp_entity: !input target_temp_helper
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
adjust_threshold: !input temp_adjust_threshold
adjust_amount: !input temp_adjust_amount
delta_low: !input delta_fan_low
delta_high: !input delta_fan_high
threshold: !input external_temp_threshold
override_switch: !input override_switch
presence: !input presence_entity
log_level: !input log_level
schedule_entity: !input schedule_entity
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
room_temp: >
{% set r = states(room_sensor) %}
{{ r | float(0) if r not in ['unknown', 'unavailable'] else 0 }}
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') }}"
outside_temp: >
{% set o = states(outside_sensor) %}
{{ o | float(999) if o not in ['unknown', 'unavailable'] else 999 }}
desired_temp: >
{% set t = states(target_temp_entity) %}
{{ t | float(22) if t not in ['unknown', 'unavailable'] else 22 }}
adjusted_temp: >
{% set delta = (room_temp - desired_temp) | abs %}
{% if delta >= adjust_threshold %}
{% if room_temp > desired_temp %}
{{ desired_temp - adjust_amount }}
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 %}
{{ desired_temp + adjust_amount }}
false
{% endif %}
{% else %}
{{ desired_temp }}
{% if room_temp > (desired_temp + temp_delta_high) %}
true
{% else %}
false
{% endif %}
hvac_mode: >
{% if outside_temp < threshold %} heat
{% elif outside_temp < 999 %} cool
{% else %} auto {% endif %}
delta: "{{ room_temp - desired_temp }}"
fan_mode: >
{% 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 delta | abs >= delta_high %} high
{% elif delta | abs >= delta_low %} mid
{% if ( temp_delta | abs ) >= temp_delta_high %} high
{% elif ( temp_delta | abs ) >= temp_delta_low %} mid
{% else %} auto {% endif %}
{% else %}
{% if delta | abs >= delta_high %} "5"
{% elif delta | abs >= delta_low %} "3"
{% else %} "1" {% endif %}
{% 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
- choose:
- conditions:
- condition: state
entity_id: !input schedule_entity
state: "off"
sequence:
- service: climate.turn_off
target:
entity_id: !input climate_entity
- service: logbook.log
data:
name: "Smart Climate"
message: "A/C turned off because schedule is OFF"
entity_id: !input climate_entity
- condition: template
value_template: >
{{ schedule_entity != 'off' }}
condition: []
action:
- choose:
- conditions:
- condition: template
value_template: >
{{ presence != '' and is_state(presence, 'not_home') }}
value_template: "{{ not ac_off or ac_off}}"
- condition: template
value_template: "{{ debug == 'debug'}}"
sequence:
- service: climate.turn_off
target:
entity_id: !input climate_entity
- service: logbook.log
data:
name: "Smart Climate"
message: "A/C turned off due to absence (not_home)"
entity_id: !input climate_entity
- condition: template
value_template: >
{{ presence == '' or is_state(presence, 'home') }}
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 climate_entity
entity_id: !input ac_unit
- service: logbook.log
data:
name: "Smart Climate"
message: "A/C turned off due to Away Mode"
entity_id: !input climate_entity
- condition: template
value_template: >
{{ away == '' or is_state(away, 'off') }}
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: template
value_template: "{{ log_level == 'debug' }}"
- 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: >
External temp = {{ outside_temp }}°C, Threshold = {{ threshold }}°C → Mode = {{ hvac_mode }}
entity_id: !input climate_entity
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"
- service: logbook.log
data:
name: "Smart Climate DEBUG"
message: >
Current state = {{ states(climate) }}, HVAC = {{ state_attr(climate, 'hvac_modes') or 'unknown' }},
Temp = {{ state_attr(climate, 'temperature') }}, Fan = {{ state_attr(climate, 'fan_mode') or 'unknown' }};
Target: HVAC = {{ hvac_mode }}, Temp = {{ adjusted_temp }}, Fan = {{ fan_mode }}
entity_id: !input climate_entity
# Not scheduled - turn off A/C
- conditions:
- condition: template
value_template: "{{ log_level == 'info' }}"
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: "Automation triggered (log level: info)"
entity_id: !input climate_entity
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"
- condition: or
# 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
(not should_cool 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:
- condition: template
value_template: >
{{ states(climate) in ['off', 'unavailable', 'unknown'] }}
- condition: template
value_template: >
{% set state = states(climate) %}
{% set fan = (state_attr(climate, 'fan_mode') or 'unknown') | string %}
{% set temp = state_attr(climate, 'temperature') | float(999) %}
{{ state != hvac_mode or fan != fan_mode or (temp | round(1)) != (adjusted_temp | round(1)) }}
- "{{ (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 climate_entity
entity_id: !input ac_unit
data:
temperature: "{{ adjusted_temp | float }}"
hvac_mode: "{{ hvac_mode }}"
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 climate_entity
entity_id: !input ac_unit
data:
fan_mode: "{{ fan_mode }}"
- service: logbook.log
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:
name: "Smart Climate"
message: >
Sent command: HVAC = {{ hvac_mode }}, Temp = {{ adjusted_temp }}°C, Fan = {{ fan_mode }}
entity_id: !input climate_entity
fan_mode: "{{ climate_fan_mode }}"
# Auto intensity (default)
default:
- service: climate.set_fan_mode
target:
entity_id: !input ac_unit
data:
fan_mode: auto
- delay:
minutes: 1
# 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: high
# 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: 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