Fully automated luxury home climate with Home Assistant
If you live in a Home Assistant smart home, there's no need to remember to turn off the A/C or the heating, like a caveman.
If you're anything like me, you might have a lot on your mind... which leads you to forget doing trivial things. Like turning off the air conditioner when you leave home, or you open a window.
Do not despair. Here is a sample Home Assistant automation that does it all for you, complete with code.
Thanks to this setup (and the prior high-precision thermostat work) we no longer need to do anything with the A/C. When it needs to run, it runs. When it doesn't need to, it's off. And when it's running, the temperature is just perfect for us.
Of course, you can modify the automation as you see fit — perhaps you'd like your heaters to turn off when you leave... and you can do that too.
This is how my dashboard looks like when the automation has kicked in. I will soon share how this dashboard is set up:
Requisites
This automation depends on the following:
- A climate entity. In the sample below, it's called
climate.living_space
.- Note that you can modify the automation to govern your home heating climate entities as well.
- An input boolean that lets you suspend the A/C unit. In the sample below, it's called
input_boolean.air_conditioning_suspended
. - Some sensors for certain states at home, which will be inputs for the automation. In the sample below, they are:
binary_sensor.indoors_windows
- You will need to create this sensor by adding a group helper that includes all your indoor windows through which the air conditioner may escape.
- Flips to on after we open a window or a door that lets outside air in.
- Flips to off immediately after all windows and doors communicating with the outside are closed
- Use whatever makes sense for your home.
binary_sensor.natural_ventilation_active
- It's pretty much the same as the previous sensor, but with the following caveat: in this sensor, entranceway doors only cause the sensor to flip to on after thirty seconds.
- Copy/paste code below lets you implement this sensor, but you need to modify the code to include all your entranceway doors.
- The purpose of this sensor is to allow the air conditioner to run for a little longer than 5 seconds — well, half a minute — after a door has been opened. This gives us a bit of time between the A/C detecting us at home, and us walking in with the entranceway door open.
- The additional purpose for this complexity is that this sensor takes into account things like, Is the bedroom door closed? then it doesn't matter if the windows of the bedroom are open. You can implement your air flow logic in this sensor.
binary_sensor.no_ventilation_for_air_conditioner_compressor
- Copy/paste code below lets you implement this sensor, but you need to modify it to include any windows ventilating the area of your home that has the compressor. If you have no such windows, you can neuter the sensor by making its value equal to
true
always. - Flips to on if the windows where the compressor part of the air conditioner are closed. It's a safety mechanism to prevent that room from getting to 50 degrees Celsius.
- Copy/paste code below lets you implement this sensor, but you need to modify it to include any windows ventilating the area of your home that has the compressor. If you have no such windows, you can neuter the sensor by making its value equal to
binary_sensor.someone_home
- Flips to off when no one is home, and on back when someone is detected at home.
- You must create this sensor by using copy/paste code below, but you have to modify it to include all entities you want to track that indicate someone is present. In the example, we use the
zone.home
counter sensor, which is quite the sane default. - My sample here also uses a Home occupancy mode input select, with value Guest at home for when there are guests and we are not around.
input_boolean.vacation_mode
- This one is the simplest — we enable it when we go on vacation, and we turn it off (or, rather, an automation turns it off) when we return home.
- You will need to create this input boolean.
What does the automation do?
The tasks the automation makes itself responsible for are very straightforward:
- If any one of these sensor conditions flips to true1, then (depending on the condition, maybe after a few seconds, or maybe immediately) the
input_boolean.air_conditioning_suspended
is flipped to true. - If all of these sensor conditions flip to false1, then the
input_boolean.air_conditioning_suspended
is flipped to false. - Whenever the
input_boolean.air_conditioning_suspended
boolean is flipped to true, the air conditioner is commanded to turn off. - Whenever the
input_boolean.air_conditioning_suspended
boolean is flipped to false, the air conditioner is commanded to turn on. - If the air conditioner is turned on manually, the boolean is flipped to false — because, obviously, the user's intention was to run the unit anyway.
Code
Configuration file sensor additions
Here is the configuration you must add to your configuration.yaml
to implement the binary sensors mentioned above. You should of course replace the entities mentioned in the sensors with entities that make sense to you:
template: - name: Someone home unique_id: someone_home availability: "{{ is_state(\"input_select.home_occupancy_mode\", \"guest at home\") }}" delay_off: 0:00:05 device_class: occupancy icon: "{%\n if\n is_state(\"input_select.home_occupancy_mode\", \"guest at home\")\n%}mdi:home-floor-g{%\n \ else\n%}mdi:home-floor-{{ states(\"zone.home\") | int }}{%\n endif\n%}" state: "{%\n if\n is_state(\"input_select.home_occupancy_mode\", \"guest at home\")\n%}True{%\n else\n%}{{ (states(\"zone.home\") | int) > 0}}{%\n endif\n%}" # The following sensor you can dispense with by making it true always # if your air conditioner compressor is not in a room with windows. - binary_sensor: name: No ventilation for air conditioner compressor unique_id: no_ventilation_for_air_conditioner_compressor state: >- {{- is_state("binary_sensor.entranceway_northwest_window_opening", "off") or is_state("binary_sensor.entranceway_middle_window_opening", "off") -}} attributes: message: Open the two entranceway windows closest to the compressor. refers_to: climate availability: >- {{- has_value("binary_sensor.entranceway_northwest_window_opening") and has_value("binary_sensor.entranceway_middle_window_opening") -}} device_class: opening - binary_sensor: name: Natural ventilation active unique_id: natural_ventilation_active state: >- {%- if (is_state("binary_sensor.entranceway_sliding_door_opening", "off") or is_state("binary_sensor.office_door_opening", "off") or has_value("climate.novamatic_cl_1590")) and (is_state("binary_sensor.entranceway_door_opening", "off") or is_state("binary_sensor.entranceway_windows", "off")) and (is_state("binary_sensor.gym_door_opening", "off") or is_state("binary_sensor.gym_windows", "off")) and (is_state("binary_sensor.master_bedroom_door_opening", "off") or is_state("binary_sensor.master_bedroom_windows", "off")) and is_state("binary_sensor.loggia_sliding_door_opening", "off") and is_state("binary_sensor.dining_room_window_opening", "off") and is_state("binary_sensor.living_room_windows", "off") %}off{% else %}on{% endif -%} attributes: message: Close all windows and doors that let air into the home to resume air conditioning. refers_to: climate availability: >- {{ not expand([ "binary_sensor.entranceway_sliding_door_opening", "binary_sensor.office_door_opening", "binary_sensor.entranceway_door_opening", "binary_sensor.entranceway_windows", "binary_sensor.gym_door_opening", "binary_sensor.gym_windows", "binary_sensor.master_bedroom_door_opening", "binary_sensor.master_bedroom_windows", "binary_sensor.loggia_sliding_door_opening", "binary_sensor.dining_room_window_opening", "binary_sensor.living_room_windows", ]) | selectattr('state', 'in', ['unavailable', 'unknown']) | list }} device_class: opening
Automation
alias: "A/C: suspend or restore as needed" description: "" trigger: - platform: state entity_id: - binary_sensor.natural_ventilation_active to: "on" for: hours: 0 minutes: 0 seconds: 30 id: outdoor_access_open - platform: state entity_id: - binary_sensor.indoors_windows to: "on" for: hours: 0 minutes: 0 seconds: 5 id: windows_open - platform: state entity_id: - binary_sensor.no_ventilation_for_air_conditioner_compressor from: "on" to: "off" id: ventilation_on - platform: template value_template: >- {{ not (is_state("input_boolean.vacation_mode", "off") and is_state("binary_sensor.someone_home", "on")) }} id: away_or_vacay alias: No one home or vacay - platform: state entity_id: - binary_sensor.natural_ventilation_active for: hours: 0 minutes: 0 seconds: 5 to: "off" id: outdoor_access_closed - platform: state entity_id: - binary_sensor.indoors_windows to: "off" for: hours: 0 minutes: 0 seconds: 5 id: windows_closed - platform: state entity_id: - binary_sensor.no_ventilation_for_air_conditioner_compressor from: "off" to: "on" id: ventilation_off - platform: template value_template: >- {{ is_state("input_boolean.vacation_mode", "off") and is_state("binary_sensor.someone_home", "on") }} id: someone_home alias: Someone home without vacay - platform: state entity_id: - input_boolean.air_conditioning_suspended from: "off" to: "on" alias: suspended id: suspended - platform: state entity_id: - input_boolean.air_conditioning_suspended from: "on" to: "off" alias: unsuspended id: unsuspended - platform: state entity_id: - climate.living_space from: "off" to: cool id: turned_on condition: - condition: template value_template: "{{ has_value(\"climate.living_space\") }}" alias: A/C controller is available action: - choose: - conditions: - condition: or conditions: - condition: trigger id: - outdoor_access_open - away_or_vacay - condition: and conditions: - condition: trigger id: - windows_open - condition: state entity_id: binary_sensor.natural_ventilation_active state: "on" alias: Windows open with outside air access - condition: trigger id: - ventilation_off alias: Compressor ventilation off - condition: template value_template: >- {{ is_state("climate.living_space", "cool") or is_state("climate.living_space", "dry") or is_state("climate.living_space", "fan_only") }} alias: A/C on - condition: state entity_id: input_boolean.air_conditioning_suspended state: "off" sequence: - service: input_boolean.turn_on data: {} target: entity_id: input_boolean.air_conditioning_suspended - conditions: - condition: and conditions: - condition: trigger id: - outdoor_access_closed - windows_closed - ventilation_on - someone_home alias: >- Windows or outside access closed or return to home or ventilation for A/C restored - condition: state entity_id: binary_sensor.no_ventilation_for_air_conditioner_compressor state: "off" - condition: state entity_id: binary_sensor.natural_ventilation_active state: "off" - condition: state entity_id: binary_sensor.indoors_windows state: "off" - condition: state entity_id: binary_sensor.someone_home state: "on" - condition: state entity_id: input_boolean.air_conditioning_suspended state: "on" sequence: - service: input_boolean.turn_off data: {} target: entity_id: input_boolean.air_conditioning_suspended enabled: true - conditions: - condition: trigger id: - turned_on - condition: state entity_id: input_boolean.air_conditioning_suspended state: "on" sequence: - service: input_boolean.turn_off data: {} target: entity_id: input_boolean.air_conditioning_suspended - conditions: - condition: trigger id: - suspended - condition: state entity_id: climate.living_space state: cool sequence: - service: climate.turn_off data: {} target: entity_id: - climate.living_space - wait_for_trigger: - platform: state entity_id: - climate.living_space to: "off" for: hours: 0 minutes: 0 seconds: 0 timeout: hours: 0 minutes: 0 seconds: 10 milliseconds: 0 alias: Wait for living space to change to off - conditions: - condition: trigger id: - unsuspended - condition: state entity_id: climate.living_space state: "off" sequence: - service: climate.turn_on data: {} target: entity_id: - climate.living_space enabled: true - wait_for_trigger: - platform: state entity_id: - climate.living_space to: cool for: hours: 0 minutes: 0 seconds: 0 timeout: hours: 0 minutes: 0 seconds: 10 milliseconds: 0 alias: Wait for living space to change to cool mode: queued max: 10