Hey, I’ve been trying to get a homemade HASS thermostat working for my apartment’s in-wall AC unit. I think I’m close, but there’s a problem where, whenever I switch rooms, the automation watching the temperature gets confused and will never shut off the AC.
Hardware details
The apartment does not have an actual thermostat wired up, just the in-wall AC unit, which I have control of using an IR blaster (Broadlink “RM mini 3”). This has been tested thoroughly and works fine.
I’ll implement heating later using IR and a space heater.
I have two BRUH Multisensors. One is in each main room of the apartment. They monitor temp, motion, humidity, and luminance. These work great.
Working Code (used by buggy code below)
My motion tracking is implemented via this forum thread.
My AC Thermostat temperature is set from an input_slider:
input_slider:
# https://home-assistant.io/components/input_slider/
thermostat:
name: Set Thermostat
min: 64
max: 80
initial: 75
step: 1.0
icon: mdi:snowflake
unit_of_measurement: '°F'
input_select:
thermostat_control:
name: "Thermostat Control"
options:
- True
- False
initial: False
thermostat_ai_mode:
name: "Temperature Control Mode"
options:
- Avg all rooms
- Last room with motion
initial: Avg all rooms
icon: mdi:AC
last_room_with_motion:
name: "Last room with motion"
options:
- Livingroom
- Bedroom
- Unknown
initial: Unknown
Buggy Code
This code pretty much works … except that if I change rooms after the AC turns on, then the AC never shuts off. Weirdly, if I move the temperature/thermostat slider all the way to max cold and then hot enough to where it should shut off, then it does shut off. That’s what I can’t figure out yet.
automation:
##Heating/cooling functions for Adaptive AC Mode
#(location-specific heating/cooling based on last motion)
#if indoor temp is 1 degree above thermostat slider setting (ex: indoor temp 76 and thermostat is 75), turn on AC.
- alias: 'A/C on if hot (livingroom temp)'
initial_state: True
trigger:
- platform: template
value_template: '{{ float(states.sensor.sn1_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) }}'
condition:
condition: and
conditions:
- condition: state
entity_id: switch.ac_power
state: 'off'
- condition: state
entity_id: input_select.thermostat_control
state: 'True'
- condition: state
entity_id: input_select.thermostat_ai_mode
state: 'Last room with motion'
- condition: state
entity_id: input_select.last_room_with_motion
state: 'Livingroom'
action:
service: switch.turn_on
entity_id: switch.ac_power
#if indoor temp is below thermostat slider setting (ex: indoor temp 74 and thermostat is 75), turn off AC.
- alias: 'A/C off if cool (livingroom temp)'
initial_state: True
trigger:
- platform: template
value_template: '{{ float(states.sensor.sn1_temperature.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) }}'
condition:
condition: and
conditions:
- condition: state
entity_id: switch.ac_power
state: 'on'
- condition: state
entity_id: input_select.thermostat_control
state: 'True'
- condition: state
entity_id: input_select.thermostat_ai_mode
state: 'Last room with motion'
- condition: state
entity_id: input_select.last_room_with_motion
state: 'Livingroom'
action:
service: switch.turn_off
entity_id: switch.ac_power
#I've duplicated the above automations for sensornode2 (sn2) watching the bedroom
To try to get the trigger to listen to multiple events, I tried this, but the AC never comes on or goes off at all with this code.
- alias: 'A/C on if hot (livingroom temp)'
initial_state: True
trigger:
- platform: template
value_template: >
'{{ float(states.sensor.sn1_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) }}'
AND
'{{ is_state('input_select.last_room_with_motion', 'Livingroom') }}
The AC also never comes on or off at all with this code
- alias: 'A/C on if hot (livingroom temp)'
initial_state: True
trigger:
- platform: template
value_template: >
"{% if
(float(states.sensor.sn1_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) )) and
(is_state('input_select.last_room_with_motion', 'Livingroom'))
%}true{% endif %}"
and also doesn’t come on/off at all with this either
- alias: 'A/C on if hot (livingroom temp)'
initial_state: True
trigger:
- platform: template
value_template: >
"{% if
( (states("sensor.sn1_temperature") | float) >= ( (states("input_slider.thermostat") | float) + float(1.0) )) and
(is_state('input_select.last_room_with_motion', 'Livingroom'))
%}true{% endif %}"
I’ve thought about nesting automations so I have multiple triggers listening at once, but I’d like a more elegant way. I feel like I’m missing something really obvious. I’m also not a Jinja2 guru. I’d be super grateful to anyone who had some ideas
I’ve started testing the automations by using input_sliders instead of the multisensor’s temperatures. I’m getting weird behavior.
The command to turn switch.ac_power on or off only fires if input_slider.thermostat changes FROM below value TO above value (if input_slider.thermostat BECOMES its logical condition, but not if it already was its logical condition)
(example:
Thermostat set to 75F, Livingroom is 80F, bedroom is 70F, last motion detected is Unknown.
Motion detected in Livingroom: No response from AC. (moving thermostat or livingroom temps up/down 1 has no effect).
Setting Livingroom to 75F, THEN to 76F turns on AC.
Setting Livingroom to 74F turns off AC.
Let’s try another condition
(turning the AC on again via setting Livingroom to 80F):
-AC is on. Livingroom is 80F, Bedroom is 70F, Thermostat is 75F. Last motion is Livingroom.
Motion fires in the bedroom
AC remains on.
Moving Bedroom slider up/down 1F or AC slider up/down 1F does nothing.
v0.21a code:
(AC cooling unit only, no heater so far but probably easy to implement. Requires air conditioner power switch, two motion sensors, two thermometer sensors)
Place the following code into your homeassistant\configuration.yaml file
Then copy and past the following code into a file named homeassistant\motion_thermostat_package.yaml and follow the directions in the code comments
### Motion Sensor Thermostat v0.21a by Wheezy ###
### How to modify this thermostat code for your own two room setup:
# Copy this code into a file named motion_thermostat_package.yaml. Rename the following variables to the names of your own sensors (find and replace with CTRL-H) inside that text file.
# Room 1 name: Livingroom <---- MATCH CASE! If doing CTRL-H / Find-And-Replace
# Motion sensor 1: sensor.sn1_pir
# Temperature sensor 1: sensor.sn1_temperature
# Room 2 name: Bedroom <---- MATCH CASE! If doing CTRL-H / Find-And-Replace
# Motion sensor 2: sensor.sn2_pir
# Temperature sensor 2: sensor.sn2_temperature
# AC unit off: script.ac_poweroff <---- You'll need to write a script in your configuration.yaml (or here) that turns off your ac power (or uncomment the ones I wrote below). You can also use a switch here if you like.
# AC unit on: script.ac_poweron <---- You'll need to write a script in your configuration.yaml (or here) that turns on your ac power (or uncomment the ones I wrote below). You can also use a switch here if you like.
#
# Then copy-paste the following code into your configuration.yaml under the homeassistant: heading
#
#homeassistant:
# packages:
# pack_1: !include motion_thermostat_package.yaml
#
### How to add more rooms:
# This thermostat is made for two temperature + two motion sensors (two rooms), but more rooms/sensors can be easily added by ...
# 1. Changing the "Inside temperature" sensor to average more than two sensors
# 2. Adding that extra room name to "input_select.last_room_with_motion"
# 3. Modifying the automation by copy-pasting another pair of Adaptive AC Mode "A/C on if hot" and "A/C off if cool" conditions for another room
# 4. Adding another "automation.store_motion_sensor_X" (and then hiding added automations from the main view to keep things looking pretty)
homeassistant:
customize:
input_boolean.thermostat_control:
friendly_name: Enable
sensor.last_room_with_motion:
icon: mdi:eye
input_select.last_room_with_motion:
hidden: true
# script.ac_poweroff:
# hidden: true
# script.ac_poweron:
# hidden: true
script.do_nothing:
hidden: true
automation.store_motion_sensor_1:
hidden: true
automation.store_motion_sensor_2:
hidden: true
automation.thermostat_ac_state_monitor:
hidden: true
sensor:
- platform: template
sensors:
indoor_temp:
value_template: >-
{{ ( ( float(states.sensor.sn1_temperature.state) + float(states.sensor.sn2_temperature.state) ) / 2 )|round(1) }}
friendly_name: "Inside"
unit_of_measurement: 'F'
- platform: template
sensors:
last_room_with_motion:
value_template: >-
{{ states.input_select.last_room_with_motion.state }}
friendly_name: "Last motion"
input_slider:
# https://home-assistant.io/components/input_slider/
thermostat:
name: "Setting (F)"
min: 64
max: 80
initial: 75
step: 1.0
icon: mdi:gauge
unit_of_measurement: 'F'
# For debugging
# Highlight automations below, then find-and-replace (CTRL-H) all states.sensor.sn1_temperature.state with states.input_slider.sn1_temperature.state
# find-and-replace all states.sensor.sn2_temperature.state with states.input_slider.sn2_temperature.state
# sn1_temperature:
# name: sn1_temperature
# min: 64
# max: 80
# initial: 75
# step: 1.0
# icon: mdi:snowflake
# unit_of_measurement: 'F'
# sn2_temperature:
# name: sn2_temperature
# min: 64
# max: 80
# initial: 75
# step: 1.0
# icon: mdi:snowflake
# unit_of_measurement: 'F'
input_boolean:
# https://home-assistant.io/components/input_boolean/
thermostat_control:
name: "Thermostat Control"
initial: off
#In case HASS gets rebooted on power-outage while user is away, ensure AC stays off.
icon: mdi:power
input_select:
thermostat_ai_mode:
name: "Temperature Control Mode"
options:
- Avg all rooms
- Last room with motion
initial: Avg all rooms
icon: mdi:settings-box
last_room_with_motion:
options:
- Livingroom
- Bedroom
- Unknown
initial: Unknown
icon: mdi:eye
script:
#These scripts are kludges for IR blasters since they will fire twice if "off" switch is triggered twice. This becomes a problem if the on and off signals for the hardware device are the same IR signal
do_nothing:
sequence:
# ac_poweroff:
# sequence:
# #activate turn_off only if switch.ac_power is 'on'
# - condition: template
# value_template: >
# {% if is_state('switch.ac_power', 'on') %}
# true
# {% elif is_state('switch.ac_power', 'off') %}
# false
# {% else %}
# false
# {% endif %}
# - service: switch.turn_off
# entity_id: switch.ac_power
# ac_poweron:
# sequence:
# #activate turn_on only if switch.ac_power is 'off'
# - condition: template
# value_template: >
# {% if is_state('switch.ac_power', 'off') %}
# true
# {% elif is_state('switch.ac_power', 'on') %}
# false
# {% else %}
# false
# {% endif %}
# - service: switch.turn_on
# entity_id: switch.ac_power
automation:
- alias: Store Motion Sensor 1
initial_state: True
trigger:
- platform: state
entity_id: sensor.sn1_pir
from: 'standby'
to: 'motion detected'
action:
service: input_select.select_option
entity_id: input_select.last_room_with_motion
data:
option: Livingroom
- alias: Store Motion Sensor 2
initial_state: True
trigger:
- platform: state
entity_id: sensor.sn2_pir
from: 'standby'
to: 'motion detected'
action:
service: input_select.select_option
entity_id: input_select.last_room_with_motion
data:
option: Bedroom
- alias: 'Thermostat A/C state monitor'
initial_state: True
trigger:
#Monitor temperature changes and any changes to thermostat input variables
- platform: state
entity_id: sensor.sn1_temperature
- platform: state
entity_id: sensor.sn2_temperature
- platform: state
entity_id: input_slider.thermostat
- platform: state
entity_id: input_select.thermostat_ai_mode
- platform: state
entity_id: input_boolean.thermostat_control
- platform: state
entity_id: input_select.last_room_with_motion
action:
#I would have done a "service_tempate:" for switch.turn_on/off, but it didn't work with my IR blaster hardware:
# This is because two "switch.turn_off" actions in a row on an IR blaster causes two IR signals to be sent. For IR devices with power toggle IR signals, this causes the device to turn off, then on.
# Scripts preventing repeated "off" (or repeated "on") IR signal fires allow IR devices to be used.
service: script.turn_on
data_template:
#Conditions are in this order:
# Heating/cooling functions for Classic AC Mode
# A/C on if hot (avg temp): If indoor temp is 1 degree above thermostat slider setting (ex: indoor temp 76 and thermostat is 75), turn on AC.
# A/C off if cool (avg temp): If indoor temp is 1 degree below thermostat slider setting (ex: indoor temp 74 and thermostat is 75), turn off AC.
# !Not implemented yet: heater functions!
# Heating/cooling functions for Adaptive AC Mode (location-specific heating/cooling based on last motion)
# A/C on if hot (livingroom temp)
# A/C off if cool (livingroom temp)
# A/C on if hot (bedroom temp)
# A/C off if cool (bedroom temp)
# !Not implemented yet: heater functions!
entity_id: >
{% if is_state("switch.ac_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Avg all rooms") and ( float(states.sensor.indoor_temp.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) )%}
script.ac_poweron
{% elif is_state("switch.ac_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Avg all rooms") and ( float(states.sensor.indoor_temp.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) )%}
script.ac_poweroff
{% elif is_state("switch.ac_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Livingroom") and ( float(states.sensor.sn1_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) )%}
script.ac_poweron
{% elif is_state("switch.ac_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Livingroom") and ( float(states.sensor.sn1_temperature.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) )%}
script.ac_poweroff
{% elif is_state("switch.ac_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Bedroom") and ( float(states.sensor.sn2_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) )%}
script.ac_poweron
{% elif is_state("switch.ac_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Bedroom") and ( float(states.sensor.sn2_temperature.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) )%}
script.ac_poweroff
{% else %}
script.do_nothing
{% endif %}
#OPTIONAL automations to turn off/on AC if leaving or arriving home (I use Locative for device_tracker / prescense detection)
# # When I leave, turn off everything inside and outside
# - alias: 'Powerdown on departure'
# initial_state: True
# trigger:
# - platform: state
# entity_id: device_tracker.XXXXXXXXXXXXXXXXXXXXXXXX
# to: not_home
# action:
# - service: homeassistant.turn_on
# entity_id: script.ac_poweroff
# - service: input_boolean.turn_off
# data:
# entity_id: input_boolean.thermostat_control
#
# # When I come home, turn on everything inside
# - alias: 'Powerup on arrival'
# initial_state: True
# trigger:
# platform: state
# entity_id: device_tracker.XXXXXXXXXXXXXXXXXXXXXXXX
# to: 'home'
# action:
# - service: input_boolean.turn_on
# data:
# entity_id: input_boolean.thermostat_control
group:
thermostat:
name: "Thermostat"
entities:
- input_boolean.thermostat_control
- input_slider.thermostat
- input_select.thermostat_ai_mode
- sensor.last_room_with_motion
Let me know if I forgot any components. There’s a ton of them
edits: Implemented package format for easier installation, cleaned up thermostat card, added picture, updated automation triggers for HASS 0.47.0, fixed bug in optional automations, consolidated automations into one automation. If someone wants to turn this into a python script, feel free to!
Cheers to these people for code ideas/examples/help:
v0.1a code
(old, but here just in case I broke something in the new version):
I got it working! Ok, so it turns out I did need the livingroom / bedroom tags on the turn off switch, but that was a great idea and it was really nice that you helped out. I think you gave me motivation to look at this again
It turns out I needed several triggers that were ALSO conditions at the same time. WEIRD! I don’t pretend to know how this works, but I’m glad that my test cases all work. Here’s the MEGA routine with code for all the components (except hardware switches) that it needs.
## How to modify this thermostat code for your own two room setup:
# Rename the following variables to your sensor variable names (find and replace with CTRL-H)
# Room 1 name: Livingroom <---- MATCH CASE! If doing CTRL-H / Find-And-Replace
# Motion sensor 1: sensor.sn1_pir
# Temperature sensor 1: sensor.sn1_temperature
# Room 2 name: Bedroom <---- MATCH CASE! If doing CTRL-H / Find-And-Replace
# Motion sensor 2: sensor.sn2_pir
# Temperature sensor 2: sensor.sn2_temperature
# AC unit on/off switch: switch.ac_power
#
# Then copy-paste the following lines into your setup under the appropraite headings
# (example:
# group:
# thermostat:
# name: "Thermostat"
# entities:
# - input_boolean.thermostat_control
# - input_slider.thermostat
# - input_select.thermostat_ai_mode
# - sensor.last_room_with_motion
# should go under your "group:" area, without copying the "group:" header part of the above code.)
## How to add more rooms:
# This thermostat is made for two temperatre + two motion sensors (two rooms), but more rooms/sensors can be easily added by ...
# 1. Changing the "Inside temperature" sensor to average more than two sensors
# 2. Adding that extra room name to "input_select.last_room_with_motion"
# 3. Copy-pasting/modifying another pair of Adaptive AC Mode "A/C on if hot" and "A/C off if cool" automations for another room
# 4. Adding another "automation.store_motion_sensor_X" (and then hiding added automations from the main view to keep things looking pretty)
homeassistant:
customize:
input_boolean.thermostat_control:
friendly_name: Enable
sensor.last_room_with_motion:
icon: mdi:eye
input_select.last_room_with_motion:
hidden: true
automation.store_motion_sensor_1:
hidden: true
automation.store_motion_sensor_2:
hidden: true
automation.ac_off_if_cool_avg_temp:
hidden: true
automation.ac_off_if_cool_bedroom_temp:
hidden: true
automation.ac_off_if_cool_livingroom_temp:
hidden: true
automation.ac_on_if_hot_avg_temp:
hidden: true
automation.ac_on_if_hot_bedroom_temp:
hidden: true
automation.ac_on_if_hot_livingroom_temp:
hidden: true
sensor:
- platform: template
sensors:
indoor_temp:
value_template: >-
{{ ( ( float(states.sensor.sn1_temperature.state) + float(states.sensor.sn2_temperature.state) ) / 2 )|round(1) }}
friendly_name: "Inside"
unit_of_measurement: '°F'
- platform: template
sensors:
last_room_with_motion:
value_template: >-
{{ states.input_select.last_room_with_motion.state }}
friendly_name: "Last motion"
input_slider:
# https://home-assistant.io/components/input_slider/
thermostat:
name: "Setting (°F)"
min: 64
max: 80
initial: 75
step: 1.0
icon: mdi:gauge
unit_of_measurement: '°F'
# For debugging
# Highlight automations below, then find-and-replace (CTRL-H) all states.sensor.sn1_temperature.state with states.input_slider.sn1_temperature.state
# find-and-replace all states.sensor.sn2_temperature.state with states.input_slider.sn2_temperature.state
# sn1_temperature:
# name: sn1_temperature
# min: 64
# max: 80
# initial: 75
# step: 1.0
# icon: mdi:snowflake
# unit_of_measurement: '°F'
# sn2_temperature:
# name: sn2_temperature
# min: 64
# max: 80
# initial: 75
# step: 1.0
# icon: mdi:snowflake
# unit_of_measurement: '°F'
input_boolean:
# https://home-assistant.io/components/input_boolean/
thermostat_control:
name: "Thermostat Control"
initial: off
#In case HASS gets rebooted on power-outage while user is away, ensure AC stays off.
icon: mdi:power
input_select:
thermostat_ai_mode:
name: "Temperature Control Mode"
options:
- Avg all rooms
- Last room with motion
initial: Avg all rooms
icon: mdi:settings-box
last_room_with_motion:
options:
- Livingroom
- Bedroom
- Unknown
initial: Unknown
#OPTIONAL script to ensure the AC unit shuts off if you use a Power Down On Departure automation and if you're using an IR transmitter (fire-and-forget signal)
#script:
# ac_poweroff:
# sequence:
# #activate turn_off only if switch.ac_power is 'on'
# - condition: template
# value_template: >
# {% if is_state('switch.ac_power', 'on') %}
# true
# {% elif is_state('switch.ac_power', 'off') %}
# false
# {% else %}
# false
# {% endif %}
# - service: switch.turn_off
# entity_id: switch.ac_power
automation:
- alias: Store Motion Sensor 1
trigger:
- platform: state
entity_id: sensor.sn1_pir
from: 'standby'
to: 'motion detected'
action:
service: input_select.select_option
entity_id: input_select.last_room_with_motion
data:
option: Livingroom
- alias: Store Motion Sensor 2
trigger:
- platform: state
entity_id: sensor.sn2_pir
from: 'standby'
to: 'motion detected'
action:
service: input_select.select_option
entity_id: input_select.last_room_with_motion
data:
option: Bedroom
##Heating/cooling functions for Classic AC Mode
#if indoor temp is 1 degree above thermostat slider setting (ex: indoor temp 76 and thermostat is 75), turn on AC.
- alias: 'A/C on if hot (avg temp)'
initial_state: True
trigger:
- platform: template
value_template: '{{ float(states.sensor.indoor_temp.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) }}'
#math operations note: Since we're working with floating point numbers, you must enter "1.0" for "float(1)" (without quotes). "1" alone is an integer, not a float, and will not work.
- platform: state
entity_id: input_select.thermostat_ai_mode
to: 'Avg all rooms'
- platform: state
entity_id: input_boolean.thermostat_control
to: 'on'
condition:
condition: and
conditions:
- condition: state
entity_id: switch.ac_power
state: 'off'
- condition: state
entity_id: input_boolean.thermostat_control
state: 'on'
- condition: state
entity_id: input_select.thermostat_ai_mode
state: 'Avg all rooms'
- condition: template
value_template: '{{ float(states.sensor.indoor_temp.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) }}'
action:
service: switch.turn_on
entity_id: switch.ac_power
#if indoor temp is below thermostat slider setting (ex: indoor temp 74 and thermostat is 75), turn off AC.
- alias: 'A/C off if cool (avg temp)'
initial_state: True
trigger:
- platform: template
value_template: '{{ float(states.sensor.indoor_temp.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) }}'
- platform: state
entity_id: input_select.thermostat_ai_mode
to: 'Avg all rooms'
- platform: state
entity_id: input_boolean.thermostat_control
to: 'on'
condition:
condition: and
conditions:
- condition: state
entity_id: switch.ac_power
state: 'on'
- condition: state
entity_id: input_boolean.thermostat_control
state: 'on'
- condition: state
entity_id: input_select.thermostat_ai_mode
state: 'Avg all rooms'
- condition: template
value_template: '{{ float(states.sensor.indoor_temp.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) }}'
action:
service: switch.turn_off
entity_id: switch.ac_power
##Heating/cooling functions for Adaptive AC Mode
#(location-specific heating/cooling based on last motion)
#if indoor temp is 1 degree above thermostat slider setting (ex: indoor temp 76 and thermostat is 75), turn on AC.
- alias: 'A/C on if hot (livingroom temp)'
initial_state: True
trigger:
- platform: template
value_template: '{{ float(states.sensor.sn1_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) }}'
- platform: state
entity_id: input_select.last_room_with_motion
to: 'Livingroom'
- platform: state
entity_id: input_select.thermostat_ai_mode
to: 'Last room with motion'
- platform: state
entity_id: input_boolean.thermostat_control
to: 'on'
condition:
condition: and
conditions:
- condition: state
entity_id: switch.ac_power
state: 'off'
- condition: state
entity_id: input_boolean.thermostat_control
state: 'on'
- condition: state
entity_id: input_select.thermostat_ai_mode
state: 'Last room with motion'
- condition: state
entity_id: input_select.last_room_with_motion
state: 'Livingroom'
- condition: template
value_template: '{{ float(states.sensor.sn1_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) }}'
action:
service: switch.turn_on
entity_id: switch.ac_power
#if indoor temp is below thermostat slider setting (ex: indoor temp 74 and thermostat is 75), turn off AC.
- alias: 'A/C off if cool (livingroom temp)'
initial_state: True
trigger:
- platform: template
value_template: '{{ float(states.sensor.sn1_temperature.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) }}'
- platform: state
entity_id: input_select.last_room_with_motion
to: 'Livingroom'
- platform: state
entity_id: input_select.thermostat_ai_mode
to: 'Last room with motion'
- platform: state
entity_id: input_boolean.thermostat_control
to: 'on'
condition:
condition: and
conditions:
- condition: state
entity_id: switch.ac_power
state: 'on'
- condition: state
entity_id: input_boolean.thermostat_control
state: 'on'
- condition: state
entity_id: input_select.thermostat_ai_mode
state: 'Last room with motion'
- condition: state
entity_id: input_select.last_room_with_motion
state: 'Livingroom'
- condition: template
value_template: '{{ float(states.sensor.sn1_temperature.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) }}'
action:
service: switch.turn_off
entity_id: switch.ac_power
- alias: 'A/C on if hot (bedroom temp)'
initial_state: True
trigger:
- platform: template
value_template: '{{ float(states.sensor.sn2_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) }}'
- platform: state
entity_id: input_select.last_room_with_motion
to: 'Bedroom'
- platform: state
entity_id: input_select.thermostat_ai_mode
to: 'Last room with motion'
- platform: state
entity_id: input_boolean.thermostat_control
to: 'on'
condition:
condition: and
conditions:
- condition: state
entity_id: switch.ac_power
state: 'off'
- condition: state
entity_id: input_boolean.thermostat_control
state: 'on'
- condition: state
entity_id: input_select.thermostat_ai_mode
state: 'Last room with motion'
- condition: state
entity_id: input_select.last_room_with_motion
state: 'Bedroom'
- condition: template
value_template: '{{ float(states.sensor.sn2_temperature.state) >= ( float(states.input_slider.thermostat.state) + float(1.0) ) }}'
action:
service: switch.turn_on
entity_id: switch.ac_power
- alias: 'A/C off if cool (bedroom temp)'
initial_state: True
trigger:
- platform: template
value_template: '{{ float(states.sensor.sn2_temperature.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) }}'
- platform: state
entity_id: input_select.last_room_with_motion
to: 'Bedroom'
- platform: state
entity_id: input_select.thermostat_ai_mode
to: 'Last room with motion'
- platform: state
entity_id: input_boolean.thermostat_control
to: 'on'
condition:
condition: and
conditions:
- condition: state
entity_id: switch.ac_power
state: 'on'
- condition: state
entity_id: input_boolean.thermostat_control
state: 'on'
- condition: state
entity_id: input_select.thermostat_ai_mode
state: 'Last room with motion'
- condition: state
entity_id: input_select.last_room_with_motion
state: 'Bedroom'
- condition: template
value_template: '{{ float(states.sensor.sn2_temperature.state) <= ( float(states.input_slider.thermostat.state) - float(1.0) ) }}'
action:
service: switch.turn_off
entity_id: switch.ac_power
#OPTIONAL automations to turn off/on AC if leaving or arriving home (I use Locative for device_tracker / prescense detection)
# # When I leave, turn off everything inside and outside
# # Add an OR statement when I get a button to trigger sleeping mode
# - alias: 'Powerdown on departure'
# initial_state: True
# trigger:
# - platform: state
# entity_id: device_tracker.XXXXXXXXXXXXXXXXXXXXXXXX
# to: not_home
# action:
# - service: homeassistant.turn_on
# entity_id: script.ac_poweroff
# - service: input_boolean.turn_off
# data:
# entity_id: input_boolean.thermostat_control
#
# # When I come home, turn on everything inside
# - alias: 'Powerup on arrival'
# initial_state: True
# trigger:
# platform: state
# entity_id: device_tracker.XXXXXXXXXXXXXXXXXXXXXXXX
# to: 'home'
# action:
# - service: input_boolean.turn_on
# data:
# entity_id: input_boolean.thermostat_control
group:
thermostat:
name: "Thermostat"
entities:
- input_boolean.thermostat_control
- input_slider.thermostat
- input_select.thermostat_ai_mode
- sensor.last_room_with_motion
I just upgraded to HASS v0.55.0 and ran into the problem of input_slider having been replaced by input_number. I can’t edit the previous post, so just letting y’all know in this post:
CTRL-H (find-and-replace text): Change all instances of input_slider to input_number to make the above code work again.
Updated code. I implemented space heaters for my apartment.
Edit: I was noticing funny behavior where my house would heat itself, then cool itself once it had heated itself, then repeat. I updated the code again by having the house ONLY heat if the outside temperature is colder than the thermostat temperature (and ONLY cool if outside is hotter than thermostat).
### Motion Sensor Thermostat v0.24a by Wheezy ###
### How to modify this thermostat code for your own two room setup:
# Copy this code into a file named motion_thermostat_package.yaml. Rename the following variables to the names of your own sensors (find and replace with CTRL-H) inside that text file.
# Room 1 name: Livingroom <---- MATCH CASE! If doing CTRL-H / Find-And-Replace
# Motion sensor 1: sensor.sn1_pir
# Temperature sensor 1: sensor.sn1_temperature
#
# Room 2 name: Bedroom <---- MATCH CASE! If doing CTRL-H / Find-And-Replace
# Motion sensor 2: sensor.sn2_pir
# Temperature sensor 2: sensor.sn2_temperature
#
# Outdoor temp sensor: sensor.pws_temp_f
#
# AC unit off: script.ac_poweroff <---- You'll need to write a script in your configuration.yaml (or here) that turns off your ac power (or uncomment the ones I wrote below). You can also use a switch here if you like.
# AC unit on: script.ac_poweron <---- You'll need to write a script in your configuration.yaml (or here) that turns on your ac power (or uncomment the ones I wrote below). You can also use a switch here if you like.
#
# Heater on: script.heater_poweron <--- ibid
# Heater off: script.heater_poweroff <--- ibid
#
#
# Then copy-paste the following code into your configuration.yaml under the homeassistant: heading
#
#homeassistant:
# packages:
# pack_1: !include motion_thermostat_package.yaml
#
### How to add more rooms:
# This thermostat is made for two temperature + two motion sensors (two rooms), but more rooms/sensors can be easily added by ...
# 1. Changing the "Inside temperature" sensor to average more than two sensors
# 2. Adding that extra room name to "input_select.last_room_with_motion"
# 3. Modifying the automation by copy-pasting another pair of Adaptive AC Mode "A/C on if hot" and "A/C off if cool" conditions for another room
# 4. Adding another "automation.store_motion_sensor_X" (and then hiding added automations from the main view to keep things looking pretty)
homeassistant:
customize:
input_boolean.thermostat_control:
friendly_name: Enable
sensor.last_room_with_motion:
icon: mdi:eye
input_select.last_room_with_motion:
hidden: true
script.ac_poweroff:
hidden: true
script.ac_poweron:
hidden: true
script.heater_poweroff:
hidden: true
script.heater_poweron:
hidden: true
script.do_nothing:
hidden: true
automation.store_motion_sensor_1:
hidden: true
automation.store_motion_sensor_2:
hidden: true
automation.thermostat_ac_state_monitor:
hidden: true
sensor:
- platform: template
sensors:
indoor_temp:
value_template: >-
{{ ( ( float(states.sensor.sn1_temperature.state) + float(states.sensor.sn2_temperature.state) ) / 2 )|round(1) }}
friendly_name: "Inside"
unit_of_measurement: 'F'
- platform: template
sensors:
last_room_with_motion:
value_template: >-
{{ states.input_select.last_room_with_motion.state }}
friendly_name: "Last motion"
#These last two sensors are here just in case someone anybody wants to use them to put on their homeassistant dashboard as status indicator widgets.
#sensor.livingroom_temp
- platform: template
sensors:
livingroom_temp:
value_template: >-
{{ float(states.sensor.sn1_temperature.state) }}
friendly_name: "Livingroom"
unit_of_measurement: 'F'
#sensor.bedroom_temp
- platform: template
sensors:
bedroom_temp:
value_template: >-
{{ float(states.sensor.sn2_temperature.state) }}
friendly_name: "Bedroom"
unit_of_measurement: 'F'
input_number:
# https://home-assistant.io/components/input_number/
thermostat:
name: "Setting (F)"
min: 64
max: 80
initial: 75
step: 1.0
icon: mdi:gauge
unit_of_measurement: 'F'
# For debugging
# Highlight automations below, then find-and-replace (CTRL-H) all states.sensor.sn1_temperature.state with states.input_number.sn1_temperature.state
# find-and-replace all states.sensor.sn2_temperature.state with states.input_number.sn2_temperature.state
# sn1_temperature:
# name: sn1_temperature
# min: 64
# max: 80
# initial: 75
# step: 1.0
# icon: mdi:snowflake
# unit_of_measurement: 'F'
# sn2_temperature:
# name: sn2_temperature
# min: 64
# max: 80
# initial: 75
# step: 1.0
# icon: mdi:snowflake
# unit_of_measurement: 'F'
input_boolean:
# https://home-assistant.io/components/input_boolean/
thermostat_control:
name: "Thermostat Control"
initial: off
#In case HASS gets rebooted on power-outage while user is away, ensure AC stays off.
icon: mdi:power
input_select:
thermostat_ai_mode:
name: "Temperature Control Mode"
options:
- Last room with motion
- Avg all rooms
initial: Last room with motion
icon: mdi:settings-box
last_room_with_motion:
options:
- Livingroom
- Bedroom
- Unknown
initial: Unknown
icon: mdi:eye
script:
#These scripts are kludges for IR blasters since they will fire twice if "off" switch is triggered twice. This becomes a problem if the on and off signals for the hardware device are the same IR signal
do_nothing:
sequence:
ac_poweroff:
sequence:
#activate turn_off only if switch.ac_power is 'on'
- condition: template
value_template: >
{% if is_state('switch.ac_power', 'on') %}
true
{% elif is_state('switch.ac_power', 'off') %}
false
{% else %}
false
{% endif %}
- service: switch.turn_off
entity_id: switch.ac_power
ac_poweron:
sequence:
#activate turn_on only if switch.ac_power is 'off'
- condition: template
value_template: >
{% if is_state('switch.ac_power', 'off') %}
true
{% elif is_state('switch.ac_power', 'on') %}
false
{% else %}
false
{% endif %}
- service: switch.turn_on
entity_id: switch.ac_power
heater_poweroff:
sequence:
#activate turn_off only if switch.heater_power is 'on'
- condition: template
value_template: >
{% if is_state('switch.heater_power', 'on') %}
true
{% elif is_state('switch.heater_power', 'off') %}
false
{% else %}
false
{% endif %}
- service: switch.turn_off
entity_id: switch.heater_power
heater_poweron:
sequence:
#activate turn_on only if switch.heater_power is 'off'
- condition: template
value_template: >
{% if is_state('switch.heater_power', 'off') %}
true
{% elif is_state('switch.heater_power', 'on') %}
false
{% else %}
false
{% endif %}
- service: switch.turn_on
entity_id: switch.heater_power
automation:
- alias: Store Motion Sensor 1
initial_state: True
trigger:
- platform: state
entity_id: sensor.sn1_pir
from: 'standby'
to: 'motion detected'
action:
service: input_select.select_option
entity_id: input_select.last_room_with_motion
data:
option: Livingroom
- alias: Store Motion Sensor 2
initial_state: True
trigger:
- platform: state
entity_id: sensor.sn2_pir
from: 'standby'
to: 'motion detected'
action:
service: input_select.select_option
entity_id: input_select.last_room_with_motion
data:
option: Bedroom
- alias: 'Thermostat A/C state monitor'
initial_state: True
trigger:
#Monitor temperature changes and any changes to thermostat input variables
- platform: state
entity_id: sensor.sn1_temperature
- platform: state
entity_id: sensor.sn2_temperature
- platform: state
entity_id: input_number.thermostat
- platform: state
entity_id: input_select.thermostat_ai_mode
- platform: state
entity_id: input_boolean.thermostat_control
- platform: state
entity_id: input_select.last_room_with_motion
action:
#I would have done a "service_tempate:" for switch.turn_on/off, but it didn't work with my IR blaster hardware:
# This is because two "switch.turn_off" actions in a row on an IR blaster causes two IR signals to be sent. For IR devices with power toggle IR signals, this causes the device to turn off, then on.
# Scripts preventing repeated "off" (or repeated "on") IR signal fires allow IR devices to be used.
service: script.turn_on
data_template:
#Conditions are in this order:
# Heating/cooling functions for Classic AC Mode
# A/C on if hot (avg temp): If indoor temp is 1 degree above thermostat slider setting (ex: indoor temp 76 and thermostat is 75), turn on AC.
# A/C off if cool (avg temp): If indoor temp is 0.25 degree below thermostat slider setting (ex: indoor temp 74.75 and thermostat is 75.00), turn off AC.
# Heater on if cold (avg temp): If indoor temp is 1 degree below thermostat slider setting, turn on heater.
# Heater off if warm (avg temp): If indoor temp is 0.25 degree above thermostat slider setting turn off heater.
# Heating/cooling functions for Adaptive AC Mode (location-specific heating/cooling based on last motion)
# A/C on if hot (livingroom temp)
# A/C off if cool (livingroom temp)
# Heater on if cold (livingroom temp)
# Heater off if warm (livingroom temp)
# A/C on if hot (bedroom temp)
# A/C off if cool (bedroom temp)
# Heater on if cold (bedroom temp)
# Heater off if warm (bedroom temp)
#
entity_id: >
{% if is_state("switch.ac_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Avg all rooms") and ( float(states.sensor.indoor_temp.state) >= ( float(states.input_number.thermostat.state) + float(1.0) ) ) and ( float(states.input_number.thermostat.state) <= ( float(states.sensor.pws_temp_f.state) ) )%}
script.ac_poweron
{% elif is_state("switch.ac_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Avg all rooms") and ( float(states.sensor.indoor_temp.state) <= ( float(states.input_number.thermostat.state) - float(0.25) ) ) and ( float(states.input_number.thermostat.state) <= ( float(states.sensor.pws_temp_f.state) ) )%}
script.ac_poweroff
{% elif is_state("switch.heater_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Avg all rooms") and ( float(states.sensor.indoor_temp.state) <= ( float(states.input_number.thermostat.state) - float(1.0) ) ) and ( float(states.input_number.thermostat.state) >= ( float(states.sensor.pws_temp_f.state) ) )%}
script.heater_poweron
{% elif is_state("switch.heater_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Avg all rooms") and ( float(states.sensor.indoor_temp.state) >= ( float(states.input_number.thermostat.state) + float(0.25) ) ) and ( float(states.input_number.thermostat.state) >= ( float(states.sensor.pws_temp_f.state) ) )%}
script.heater_poweroff
{% elif is_state("switch.ac_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Livingroom") and ( float(states.sensor.sn1_temperature.state) >= ( float(states.input_number.thermostat.state) + float(1.0) ) ) and ( float(states.sensor.sn1_temperature.state) <= ( float(states.sensor.pws_temp_f.state) ) )%}
script.ac_poweron
{% elif is_state("switch.ac_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Livingroom") and ( float(states.sensor.sn1_temperature.state) <= ( float(states.input_number.thermostat.state) - float(0.25) ) ) and ( float(states.input_number.thermostat.state) <= ( float(states.sensor.pws_temp_f.state) ) )%}
script.ac_poweroff
{% elif is_state("switch.heater_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Livingroom") and ( float(states.sensor.sn1_temperature.state) <= ( float(states.input_number.thermostat.state) - float(1.0) ) ) and ( float(states.input_number.thermostat.state) >= ( float(states.sensor.pws_temp_f.state) ) )%}
script.heater_poweron
{% elif is_state("switch.heater_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Livingroom") and ( float(states.sensor.sn1_temperature.state) >= ( float(states.input_number.thermostat.state) + float(0.25) ) ) and ( float(states.input_number.thermostat.state) >= ( float(states.sensor.pws_temp_f.state) ) )%}
script.heater_poweroff
{% elif is_state("switch.ac_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Bedroom") and ( float(states.sensor.sn2_temperature.state) >= ( float(states.input_number.thermostat.state) + float(1.0) ) ) and ( float(states.input_number.thermostat.state) <= ( float(states.sensor.pws_temp_f.state) ) )%}
script.ac_poweron
{% elif is_state("switch.ac_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Bedroom") and ( float(states.sensor.sn2_temperature.state) <= ( float(states.input_number.thermostat.state) - float(0.25) ) ) and ( float(states.input_number.thermostat.state) <= ( float(states.sensor.pws_temp_f.state) ) )%}
script.ac_poweroff
{% elif is_state("switch.heater_power", "off") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Bedroom") and ( float(states.sensor.sn2_temperature.state) <= ( float(states.input_number.thermostat.state) - float(1.0) ) ) and ( float(states.input_number.thermostat.state) >= ( float(states.sensor.pws_temp_f.state) ) )%}
script.heater_poweron
{% elif is_state("switch.heater_power", "on") and is_state("input_boolean.thermostat_control", "on") and is_state("input_select.thermostat_ai_mode", "Last room with motion") and is_state("input_select.last_room_with_motion", "Bedroom") and ( float(states.sensor.sn2_temperature.state) >= ( float(states.input_number.thermostat.state) + float(0.25) ) ) and ( float(states.input_number.thermostat.state) >= ( float(states.sensor.pws_temp_f.state) ) )%}
script.heater_poweroff
{% else %}
script.do_nothing
{% endif %}
#OPTIONAL automations to turn off/on AC if leaving or arriving home (I use Locative for device_tracker / prescense detection)
# # When I leave, turn off everything inside and outside
# - alias: 'Powerdown on departure'
# initial_state: True
# trigger:
# - platform: state
# entity_id: device_tracker.XXXXXXXXXXXXXXXXXXXXXXXX
# to: not_home
# action:
# - service: homeassistant.turn_on
# entity_id: script.ac_poweroff
# - service: input_boolean.turn_off
# data:
# entity_id: input_boolean.thermostat_control
#
# # When I come home, turn on everything inside
# - alias: 'Powerup on arrival'
# initial_state: True
# trigger:
# platform: state
# entity_id: device_tracker.XXXXXXXXXXXXXXXXXXXXXXXX
# to: 'home'
# action:
# - service: input_boolean.turn_on
# data:
# entity_id: input_boolean.thermostat_control
group:
thermostat:
name: "Thermostat"
entities:
- input_boolean.thermostat_control
- input_number.thermostat
- input_select.thermostat_ai_mode
- sensor.last_room_with_motion