|
|
######################################################################
|
|
|
# @CCOSTAN - Follow Me on X
|
|
|
# For more info visit https://www.vcloudinfo.com/click-here
|
|
|
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
|
|
|
# -------------------------------------------------------------------
|
|
|
# Climate Control - Seasonal HVAC automations and sensors.
|
|
|
# Thermostat helpers for upstairs/downstairs comfort.
|
|
|
# -------------------------------------------------------------------
|
|
|
######################################################################
|
|
|
# Contact: @CCOSTAN | Entity reference details below
|
|
|
# Entity reference and attribute summaries:
|
|
|
#
|
|
|
# Entity ID: climate.downstairs
|
|
|
# Supported hvac_modes: heat, cool, heat_cool, off
|
|
|
# Supported fan_modes: on, off
|
|
|
# Supported preset_modes: none, eco
|
|
|
# Supported temperature range: 50°F (min_temp) – 90°F (max_temp)
|
|
|
#
|
|
|
# Current state (example):
|
|
|
# current_temperature: 77
|
|
|
# temperature: 83
|
|
|
# target_temp_high: null
|
|
|
# target_temp_low: null
|
|
|
# current_humidity: 58
|
|
|
# fan_mode: off
|
|
|
# hvac_action: idle
|
|
|
# preset_mode: none
|
|
|
# Supported features: 411
|
|
|
# --------------------------------------------------------------
|
|
|
# Entity ID: climate.upstairs
|
|
|
# Supported hvac_modes: off, heat, cool, heat_cool
|
|
|
# Supported temperature range: 50°F (min_temp) – 90°F (max_temp)
|
|
|
#
|
|
|
# Current state (example):
|
|
|
# current_temperature: 76
|
|
|
# temperature: 78
|
|
|
# target_temp_high: null
|
|
|
# target_temp_low: null
|
|
|
# friendly_name: Upstairs
|
|
|
# Supported features: 387
|
|
|
|
|
|
######################################################################
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# Template helpers – compressor status flags and numeric runtime helpers
|
|
|
# ---------------------------------------------------------------------------
|
|
|
template:
|
|
|
- binary_sensor:
|
|
|
- name: "Downstairs AC is Cooling"
|
|
|
unique_id: downstairs_ac_cooling
|
|
|
state: >
|
|
|
{{ state_attr('climate.downstairs', 'hvac_action') == 'cooling' }}
|
|
|
- name: "Upstairs AC is Cooling"
|
|
|
unique_id: upstairs_ac_cooling
|
|
|
state: >
|
|
|
{{ state_attr('climate.upstairs', 'hvac_action') == 'cooling' }}
|
|
|
|
|
|
sensor:
|
|
|
- name: "Downstairs AC Cooling Numeric"
|
|
|
unique_id: downstairs_ac_cooling_numeric
|
|
|
state: "{{ 1 if is_state('binary_sensor.downstairs_ac_cooling', 'on') else 0 }}"
|
|
|
- name: "Upstairs AC Cooling Numeric"
|
|
|
unique_id: upstairs_ac_cooling_numeric
|
|
|
state: "{{ 1 if is_state('binary_sensor.upstairs_ac_cooling', 'on') else 0 }}"
|
|
|
|
|
|
input_datetime:
|
|
|
downstairs_last_filter_change:
|
|
|
name: Downstairs Last Filter Change
|
|
|
has_date: true
|
|
|
has_time: true
|
|
|
upstairs_last_filter_change:
|
|
|
name: Upstairs Last Filter Change
|
|
|
has_date: true
|
|
|
has_time: true
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# Integration sensors tally runtime based on compressor state
|
|
|
# ---------------------------------------------------------------------------
|
|
|
sensor:
|
|
|
- platform: integration
|
|
|
name: Downstairs AC Runtime Raw
|
|
|
source: sensor.downstairs_ac_cooling_numeric
|
|
|
unit_time: h
|
|
|
method: left
|
|
|
round: 2
|
|
|
- platform: integration
|
|
|
name: Upstairs AC Runtime Raw
|
|
|
source: sensor.upstairs_ac_cooling_numeric
|
|
|
unit_time: h
|
|
|
method: left
|
|
|
round: 2
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# Utility‑meters that act like odometers (reset when you swap the filter)
|
|
|
# ---------------------------------------------------------------------------
|
|
|
utility_meter:
|
|
|
downstairs_ac_runtime_since_last_filter_change:
|
|
|
source: sensor.downstairs_ac_runtime_raw
|
|
|
upstairs_ac_runtime_since_last_filter_change:
|
|
|
source: sensor.upstairs_ac_runtime_raw
|
|
|
|
|
|
script:
|
|
|
reset_downstairs_filter:
|
|
|
alias: Reset Downstairs Filter
|
|
|
mode: queued
|
|
|
sequence:
|
|
|
- service: input_datetime.set_datetime
|
|
|
data:
|
|
|
entity_id: input_datetime.downstairs_last_filter_change
|
|
|
datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
|
|
|
- service: utility_meter.reset
|
|
|
target:
|
|
|
entity_id: sensor.downstairs_ac_runtime_since_last_filter_change
|
|
|
|
|
|
reset_upstairs_filter:
|
|
|
alias: Reset Upstairs Filter
|
|
|
mode: queued
|
|
|
sequence:
|
|
|
- service: input_datetime.set_datetime
|
|
|
data:
|
|
|
entity_id: input_datetime.upstairs_last_filter_change
|
|
|
datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
|
|
|
- service: utility_meter.reset
|
|
|
target:
|
|
|
entity_id: sensor.upstairs_ac_runtime_since_last_filter_change
|
|
|
|
|
|
set_downstairs_target_temp_based_on_conditions:
|
|
|
alias: Set Downstairs Target Temperature Based on Conditions
|
|
|
mode: single
|
|
|
sequence:
|
|
|
- choose:
|
|
|
- conditions:
|
|
|
- condition: state
|
|
|
entity_id: group.family
|
|
|
state: 'not_home'
|
|
|
sequence:
|
|
|
- service: script.send_to_logbook
|
|
|
data:
|
|
|
topic: "CLIMATE"
|
|
|
message: "Downstairs HVAC set to ECO (family not_home)."
|
|
|
- service: climate.set_preset_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
preset_mode: 'eco'
|
|
|
- conditions:
|
|
|
- condition: and
|
|
|
conditions:
|
|
|
- condition: state
|
|
|
entity_id: group.family
|
|
|
state: 'home'
|
|
|
- condition: numeric_state
|
|
|
entity_id: sensor.pirateweather_temperature
|
|
|
above: 92
|
|
|
sequence:
|
|
|
- service: script.send_to_logbook
|
|
|
data:
|
|
|
topic: "CLIMATE"
|
|
|
message: "Downstairs target set to 78F (family home, temp >92F)."
|
|
|
- service: climate.set_hvac_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
hvac_mode: cool
|
|
|
- service: climate.set_temperature
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
temperature: 78
|
|
|
- conditions:
|
|
|
- condition: state
|
|
|
entity_id: group.family
|
|
|
state: 'home'
|
|
|
sequence:
|
|
|
- service: script.send_to_logbook
|
|
|
data:
|
|
|
topic: "CLIMATE"
|
|
|
message: "Downstairs target set to 80F (family home)."
|
|
|
- service: climate.set_hvac_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
hvac_mode: cool
|
|
|
- service: climate.set_temperature
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
temperature: 80
|
|
|
|
|
|
##############################################################################
|
|
|
### AUTOMATIONS - Thermostat schedules, guardrails, and presence/weather logic
|
|
|
### Some shutoff automations are also in the ALARM.yaml package when windows/doors are left open.
|
|
|
### There are also some automations in the POWERWALL.yaml package when the grid is down.
|
|
|
##############################################################################
|
|
|
automation:
|
|
|
- alias: Notify Downstairs Filter Change Due
|
|
|
description: Notify when downstairs runtime exceeds threshold since last filter change
|
|
|
trigger:
|
|
|
- platform: numeric_state
|
|
|
entity_id: sensor.downstairs_ac_runtime_since_last_filter_change
|
|
|
above: 800 # hours
|
|
|
action:
|
|
|
- service: script.send_to_logbook
|
|
|
data:
|
|
|
topic: "MAINTENANCE"
|
|
|
message: >-
|
|
|
Downstairs AC filter due (runtime >800h). Last changed {{ ((now() - states.input_datetime.downstairs_last_filter_change.last_changed).total_seconds() / 86400) | round(0) }} days ago.
|
|
|
- service: script.notify_engine # <-- keep your existing notify helper
|
|
|
data:
|
|
|
title: "Home Maintenance Reminder"
|
|
|
value1: "It's time to change your Downstairs AC filter."
|
|
|
value2: >
|
|
|
Runtime has exceeded 800 h. Last changed {{ ((now() - states.input_datetime.downstairs_last_filter_change.last_changed).total_seconds() / 86400) | round(0) }} days ago.
|
|
|
who: "Carlo"
|
|
|
group: "maintenance"
|
|
|
level: "active"
|
|
|
|
|
|
- alias: Notify Upstairs Filter Change Due
|
|
|
description: Notify when upstairs runtime exceeds threshold since last filter change
|
|
|
trigger:
|
|
|
- platform: numeric_state
|
|
|
entity_id: sensor.upstairs_ac_runtime_since_last_filter_change
|
|
|
above: 450 # hours
|
|
|
action:
|
|
|
- service: script.send_to_logbook
|
|
|
data:
|
|
|
topic: "MAINTENANCE"
|
|
|
message: >-
|
|
|
Upstairs AC filter due (runtime >450h). Last changed {{ ((now() - states.input_datetime.upstairs_last_filter_change.last_changed).total_seconds() / 86400) | round(0) }} days ago.
|
|
|
- service: script.notify_engine
|
|
|
data:
|
|
|
title: "Home Maintenance Reminder"
|
|
|
value1: "It's time to change your Upstairs AC filter."
|
|
|
value2: >
|
|
|
Runtime has exceeded 450 h. Last changed {{ ((now() - states.input_datetime.upstairs_last_filter_change.last_changed).total_seconds() / 86400) | round(0) }} days ago.
|
|
|
who: "Carlo"
|
|
|
group: "maintenance"
|
|
|
|
|
|
- alias: 'AC Status Announcement'
|
|
|
id: 7812fdaf-a3f8-498b-8f07-28e977e528fe
|
|
|
trigger:
|
|
|
- platform: state
|
|
|
entity_id:
|
|
|
- climate.downstairs
|
|
|
- climate.upstairs
|
|
|
from: 'off'
|
|
|
- platform: state
|
|
|
entity_id:
|
|
|
- climate.downstairs
|
|
|
- climate.upstairs
|
|
|
to: 'off'
|
|
|
action:
|
|
|
- service: script.speech_engine
|
|
|
data:
|
|
|
NestStatus: "The {{ trigger.entity_id.split('.')[1].split('_')[0]}} {{ trigger.entity_id.split('.')[1].split('_')[1]}} has now been turned on for {{(trigger.to_state.state)}}."
|
|
|
call_window_check: 1
|
|
|
|
|
|
- alias: Prevent Upstairs Nest Below 76
|
|
|
id: 7812fdaf-a3f8-498b-8f07-28e977e528ff
|
|
|
trigger:
|
|
|
- platform: numeric_state
|
|
|
entity_id: climate.upstairs
|
|
|
attribute: temperature
|
|
|
below: 76
|
|
|
condition:
|
|
|
- condition: state
|
|
|
entity_id: binary_sensor.powerwall_grid_status
|
|
|
state: 'on'
|
|
|
action:
|
|
|
- delay: "00:03:00"
|
|
|
- service: climate.set_temperature
|
|
|
data:
|
|
|
entity_id: climate.upstairs
|
|
|
temperature: 78
|
|
|
- service: script.send_to_logbook
|
|
|
data:
|
|
|
topic: "CLIMATE"
|
|
|
message: "Upstairs target temp corrected to 78F (guardrail)."
|
|
|
|
|
|
- alias: Set Downstairs to 77 When Both in Bed
|
|
|
id: set_downstairs_nest_77_both_in_bed
|
|
|
trigger:
|
|
|
- platform: state
|
|
|
entity_id: group.bed
|
|
|
to: 'on'
|
|
|
condition:
|
|
|
- condition: and
|
|
|
conditions:
|
|
|
- condition: state
|
|
|
entity_id: binary_sensor.sleepnumber_carlo_carlo_is_in_bed
|
|
|
state: 'on'
|
|
|
- condition: state
|
|
|
entity_id: binary_sensor.sleepnumber_carlo_stacey_is_in_bed
|
|
|
state: 'on'
|
|
|
- condition: state
|
|
|
entity_id: binary_sensor.powerwall_grid_status
|
|
|
state: 'on'
|
|
|
- condition: state
|
|
|
entity_id: sun.sun
|
|
|
state: 'below_horizon'
|
|
|
action:
|
|
|
- service: climate.set_temperature
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
temperature: 77
|
|
|
|
|
|
- alias: 'Set Downstairs Thermostat Daytime Target'
|
|
|
id: set_downstairs_thermostat_daytime_target
|
|
|
mode: single
|
|
|
trigger:
|
|
|
- platform: state
|
|
|
entity_id: sun.sun
|
|
|
to: 'above_horizon'
|
|
|
- platform: time
|
|
|
at: "08:00:00"
|
|
|
- platform: numeric_state
|
|
|
entity_id: sensor.pirateweather_temperature
|
|
|
above: 92
|
|
|
- platform: state
|
|
|
entity_id: group.family
|
|
|
to: 'home'
|
|
|
condition:
|
|
|
- condition: and
|
|
|
conditions:
|
|
|
- condition: state
|
|
|
entity_id: sun.sun
|
|
|
state: 'above_horizon'
|
|
|
- condition: state
|
|
|
entity_id: input_boolean.guest_mode
|
|
|
state: 'off'
|
|
|
- condition: state
|
|
|
entity_id: binary_sensor.powerwall_grid_status
|
|
|
state: 'on'
|
|
|
action:
|
|
|
- service: climate.set_hvac_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
hvac_mode: cool
|
|
|
- service: script.set_downstairs_target_temp_based_on_conditions
|
|
|
|
|
|
# Set thermostats to eco mode when everyone is away
|
|
|
- alias: 'Set Thermostats to Eco When Away'
|
|
|
id: 1e2d3c4b-eco-thermostat-away
|
|
|
mode: single
|
|
|
trigger:
|
|
|
- platform: state
|
|
|
entity_id: group.family
|
|
|
to: 'not_home'
|
|
|
condition:
|
|
|
- condition: state
|
|
|
entity_id: group.family
|
|
|
state: 'not_home'
|
|
|
- condition: state
|
|
|
entity_id: input_boolean.guest_mode
|
|
|
state: 'off'
|
|
|
action:
|
|
|
- service: climate.set_preset_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
preset_mode: 'eco'
|
|
|
- service: climate.set_hvac_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
hvac_mode: cool
|
|
|
- service: climate.set_temperature
|
|
|
data:
|
|
|
entity_id: climate.upstairs
|
|
|
temperature: 83
|
|
|
|
|
|
# Automation: Set Thermostats Back to Cool Mode
|
|
|
- alias: 'Set Thermostats to Cool When Home'
|
|
|
id: 1e2d3c4b-cool-thermostat-home
|
|
|
mode: single
|
|
|
trigger:
|
|
|
- platform: state
|
|
|
entity_id: group.family
|
|
|
to: 'home'
|
|
|
condition:
|
|
|
- condition: or
|
|
|
conditions:
|
|
|
- condition: state
|
|
|
entity_id: group.family
|
|
|
state: 'home'
|
|
|
- condition: state
|
|
|
entity_id: input_boolean.guest_mode
|
|
|
state: 'off'
|
|
|
- condition: state
|
|
|
entity_id: binary_sensor.powerwall_grid_status
|
|
|
state: 'on'
|
|
|
action:
|
|
|
- service: climate.set_preset_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
preset_mode: 'none'
|
|
|
- service: climate.set_hvac_mode
|
|
|
data:
|
|
|
entity_id:
|
|
|
- climate.downstairs
|
|
|
- climate.upstairs
|
|
|
hvac_mode: cool
|
|
|
- service: script.set_downstairs_target_temp_based_on_conditions
|
|
|
- service: climate.set_temperature
|
|
|
data:
|
|
|
entity_id: climate.upstairs
|
|
|
temperature: 82
|
|
|
|
|
|
- alias: 'Reset Upstairs to 82 Each Night'
|
|
|
id: reset_upstairs_thermostat_nightly_82
|
|
|
mode: single
|
|
|
trigger:
|
|
|
- platform: time
|
|
|
at: "03:00:00"
|
|
|
condition:
|
|
|
- condition: state
|
|
|
entity_id: binary_sensor.powerwall_grid_status
|
|
|
state: 'on'
|
|
|
action:
|
|
|
- service: climate.set_hvac_mode
|
|
|
data:
|
|
|
entity_id: climate.upstairs
|
|
|
hvac_mode: cool
|
|
|
- service: climate.set_temperature
|
|
|
data:
|
|
|
entity_id: climate.upstairs
|
|
|
temperature: 82
|
|
|
|
|
|
- alias: 'Humidity Control'
|
|
|
id: AC_Humidity_Control
|
|
|
mode: single
|
|
|
trigger:
|
|
|
- platform: numeric_state
|
|
|
entity_id: sensor.downstairs_humidity
|
|
|
above: 60
|
|
|
- platform: time
|
|
|
at: "02:00:00"
|
|
|
condition:
|
|
|
- condition: time
|
|
|
after: "01:00:00"
|
|
|
before: "08:00:00"
|
|
|
- condition: numeric_state
|
|
|
entity_id: sensor.downstairs_humidity
|
|
|
above: 60
|
|
|
- condition: template #Only needed in the winter months
|
|
|
value_template: "{{ now().month in [10, 11, 12, 1, 2, 3] }}"
|
|
|
- condition: template # Only run if AC is idle (prevents fighting other automations)
|
|
|
value_template: "{{ state_attr('climate.downstairs', 'hvac_action') == 'idle' }}"
|
|
|
- condition: state # Never run if the grid is down and running on powerwall.
|
|
|
entity_id: binary_sensor.powerwall_grid_status
|
|
|
state: 'on'
|
|
|
action:
|
|
|
- service: climate.set_preset_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
preset_mode: 'none'
|
|
|
- service: climate.set_hvac_mode
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
hvac_mode: cool
|
|
|
- service: climate.set_temperature
|
|
|
data:
|
|
|
entity_id: climate.downstairs
|
|
|
temperature: 77
|
|
|
- delay: "00:20:00"
|
|
|
- service: script.set_downstairs_target_temp_based_on_conditions
|
|
|
- delay: "02:00:00" # stops it from being triggered again too soon.
|