Controlling my heating with Home Assistant
My original post about home automation discussed the fact that one of my motivations was improving control over my central heating system. In the last few weeks I’ve finally brought enough pieces together to make that a reality. My boiler is controlled by a Siemens RCR10/433 thermostat. Ross Harper has a good write-up about decoding the Siemens RCR10/433 and I was able to extend my Energenie Atmel 433MHz transmitter to treat the boiler as another switch. Slightly different timing than the Energenie switches, but exactly the same principle. My TEMPer USB clone provides a reading of the living room temperature. Finally mqtt-arp lets me work out whether anyone is home or not.
Everything is tied together with Home Assistant. The configuration has ended up more involved than I expected, but it’s already better than the old 24 hour timer. There’s definitely still room for improvement in terms of behaviour as the weather starts to get colder and I collect further data. Presently it looks like this:
Top left is the control card; “Heating” is a climate control with a target temperature and a current temperature (from the living room sensor), an on/off state for the boiler (linked to the 433MHz transmitter), a switch to indicate if the timer is on or not and finally a slider to control what the target temperature should be when the heating is active.
Top right is a history card showing the various temperature sensors around the house as well as the target temperature state of the heating over the past 24 hours.
The bottom two cards show the timer times for week days and weekends. I did consider making a full 7 day timer, but this ends up good enough and I couldn’t find a better way to represent a set of start + end times that would have allowed a clean interface display of a full week. The times control when the “Heating timer” control in the top left is switched on + off.
These 4 cards provide the ability to see the current state of the heating, and tweak it, ideally meaning there’s no need to hand edit config files during normal operation. Rough theory of operation is:
- If the timer is on and someone is at home, raise the target temperature to the value set in the temperature slider.
- If the timer turns off or everyone leaves the house, lower the target temperature to 5°C.
The core is a generic thermostat:
climate:
- platform: generic_thermostat
name: Heating
heater: switch.gas_boiler
target_sensor: sensor.living_room_temperature
min_temp: 5
max_temp: 25
ac_mode: false
hot_tolerance: 0.5
cold_tolerance: 0.1
min_cycle_duration:
minutes: 5
keep_alive:
minutes: 30
initial_operation_mode: 'auto'
This is always active, and climate.set_temperature
used to control what the target temperature is.
The temperature control slider is a simple input_number
:
input_number:
heating_temperature:
name: Temperature
min: 5
max: 25
step: 0.5
icon: mdi:thermometer
The timer is where it gets complex. There are 8 input_datetime
entries to deal with the different start/stop times. It seems like there should be an easier way, but this is what I have:
Heating start/stop time inputs
input_datetime:
weekday_morning_start:
name: Week day morning start
has_time: true
has_date: false
weekday_morning_stop:
name: Week day morning stop
has_time: true
has_date: false
weekend_morning_start:
name: Weekend morning start
has_time: true
has_date: false
weekend_morning_stop:
name: Weekend morning stop
has_time: true
has_date: false
weekday_evening_start:
name: Week day evening start
has_time: true
has_date: false
weekday_evening_stop:
name: Week day evening stop
has_time: true
has_date: false
weekend_evening_start:
name: Weekend evening start
has_time: true
has_date: false
weekend_evening_stop:
name: Weekend evening stop
has_time: true
has_date: false
For the automations I also needed to add a time & date sensor:
sensor:
- platform: time_date
display_options:
- 'time'
And finally the output input_boolean
to represent if the timer is active or not:
input_boolean:
heating_timer:
name: Heating timer
icon: mdi:toggle-switch
These get tied together with a bunch of automations:
Automations for heating timer
automation:
- id: heating_morning_on_wd
alias: Turn heating on (weekday mornings)
trigger:
platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.weekday_morning_start.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
condition:
condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
action:
service: input_boolean.turn_on
data_template:
entity_id: input_boolean.heating_timer
- id: heating_morning_off_wd
alias: Turn heating off (weekday mornings)
trigger:
platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.weekday_morning_stop.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
condition:
condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
action:
service: input_boolean.turn_off
data_template:
entity_id: input_boolean.heating_timer
- id: heating_evening_on_wd
alias: Turn heating on (weekday evenings)
trigger:
platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.weekday_evening_start.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
condition:
condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
action:
service: input_boolean.turn_on
data_template:
entity_id: input_boolean.heating_timer
- id: heating_evening_off_wd
alias: Turn heating off (weekday evenings)
trigger:
platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.weekday_evening_stop.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
condition:
condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
action:
service: input_boolean.turn_off
data_template:
entity_id: input_boolean.heating_timer
- id: heating_morning_on_we
alias: Turn heating on (weekend mornings)
trigger:
platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.weekend_morning_start.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
condition:
condition: time
weekday:
- sat
- sun
action:
service: input_boolean.turn_on
data_template:
entity_id: input_boolean.heating_timer
- id: heating_morning_off_we
alias: Turn heating off (weekend mornings)
trigger:
platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.weekend_morning_stop.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
condition:
condition: time
weekday:
- sat
- sun
action:
service: input_boolean.turn_off
data_template:
entity_id: input_boolean.heating_timer
- id: heating_evening_on_we
alias: Turn heating on (weekend evenings)
trigger:
platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.weekend_evening_start.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
condition:
- condition: time
weekday:
- sat
- sun
action:
service: input_boolean.turn_on
data_template:
entity_id: input_boolean.heating_timer
- id: heating_evening_off_we
alias: Turn heating off (weekend evenings)
trigger:
platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.weekend_evening_stop.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
condition:
condition: time
weekday:
- sat
- sun
action:
service: input_boolean.turn_off
data_template:
entity_id: input_boolean.heating_timer
The timer boolean switch and the group.all_devices
presence information are then tied together to raise/lower the target temperature as appropriate. I’ve used 4 automations for this - one triggered for timer on, one for timer off, one for someone arriving at home, one for everyone leaving. Again, there might be a better way, but this does what I need:
Automations to raise/lower target temperature
automation:
- id: heating_timer_on
alias: Turn heating on based on timer
trigger:
platform: state
entity_id: input_boolean.heating_timer
to: 'on'
condition:
condition: state
entity_id: group.all_devices
state: 'home'
action:
service: climate.set_temperature
data_template:
entity_id: climate.heating
temperature: "{{ states('input_number.heating_temperature') }}"
- id: heating_timer_off
alias: Turn heating off based on timer
trigger:
platform: state
entity_id: input_boolean.heating_timer
to: 'off'
action:
service: climate.set_temperature
data:
entity_id: climate.heating
temperature: 5
- id: heating_on_when_get_home
alias: Turn heating on on arrival if timer on
trigger:
platform: state
entity_id: group.all_devices
from: "not_home"
to: "home"
condition:
condition: state
entity_id: input_boolean.heating_timer
state: 'on'
action:
service: climate.set_temperature
data_template:
entity_id: climate.heating
temperature: "{{ states('input_number.heating_temperature') }}"
- id: heating_off_when_leave_home
alias: Turn heating off when we leave home
trigger:
platform: state
entity_id: group.all_devices
from: "home"
to: "not_home"
action:
service: climate.set_temperature
data:
entity_id: climate.heating
temperature: 5
Finally there’s the UI configuration, which I’ve done using Lovelace. The use of ‘:’ as the name for the climate.heating
element is a kludge - I haven’t figured out yet how to name each individual data entry it adds to the history graph. I’m not particularly fond of the input method for controlling times - something closer to the Android analog clock with digits at the top would be nicer, but I’m not a UI guy and this works well enough.
Lovelace configuration for heating controls
views:
- title: Heating
cards:
- type: entities
title: Controls
show_header_toggle: false
entities:
- climate.heating
- switch.gas_boiler
- input_boolean.heating_timer
- input_number.heating_temperature
- type: history-graph
title: Temperatures
entities:
- entity: sensor.kitchen_temperature
name: Kitchen
- entity: sensor.living_room_temperature
name: Living Room
- entity: sensor.master_bedroom_temperature
name: Master Bedroom
- entity: sensor.outside
name: Outside
- entity: sensor.study_temperature
name: Study
- entity: climate.heating
name: ":"
- type: entities
title: Week day Timer
entities:
- input_datetime.weekday_morning_start
- input_datetime.weekday_morning_stop
- input_datetime.weekday_evening_start
- input_datetime.weekday_evening_stop
- type: entities
title: Weekend Timer
entities:
- input_datetime.weekend_morning_start
- input_datetime.weekend_morning_stop
- input_datetime.weekend_evening_start
- input_datetime.weekend_evening_stop