Two years ago I started to need controlling my home heating system while I’m not at home. I could go the easy way and buy a couple Nest thermostats, but I preferred the DIY way.
ESP32 board with ESPHome
I connected the boiler to a ESP-WROOM-32 board via a relay module. The box and the cables were more expensive than the board (~10 EUR) and the relay module (~5 EUR).
The ESP32 board is running ESPHome: https://esphome.io/. I think it is a very nice project and very easy to setup. All the configuration is done via YAML files. The board is connected to the home WiFi and it has a fallback hotspot.
My home heating system has two radiating floor zones with two independent pumps. I also decided to automate the boiler’s “Winter mode”, in this mode the boiler heats the water for the heating, and I wanted to disable it when the heating is not working.
In my case I needed to activate the winter mode when any pump is working and keep it working for a period of time after the pump is off.
This is my ESPHome YAML config:
substitutions:
devicename: heating
friendly_name: Heating
esphome:
name: ${devicename}
friendly_name: ${friendly_name}
platform: ESP32
board: nodemcu-32s
logger:
api:
password: ""
ota:
platform: esphome
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
reboot_timeout: 90s
ap:
ssid: ${friendly_name} Fallback Hotspot
password: !secret wifi_password
captive_portal:
web_server:
port: 80
debug:
time:
- platform: homeassistant
id: homeassistant_time
sensor:
- platform: uptime
name: Uptime
filters:
- lambda: return x / 60.0;
unit_of_measurement: minutes
- platform: wifi_signal
name: Wifi Signal
update_interval: 60s
script:
- id: keep_winter_mode_on
mode: restart
then:
- logger.log: "Keep Winter mode start"
- if:
condition:
and:
- switch.is_off: zone1_pump
- switch.is_off: zone2_pump
then:
- logger.log: "Keep Winter mode will stop"
- delay: 15min
- switch.turn_off: winter_mode
- logger.log: "Keep Winter mode stopped"
- id: zone1_pump_security
mode: restart
then:
- logger.log: "Zone 1 security start"
- delay: 60min
- switch.turn_off: zone1_pump
- logger.log: "Zone 1 security stop"
- id: zone2_pump_security
mode: restart
then:
- logger.log: "Zone 2 security start"
- delay: 60min
- switch.turn_off: zone2_pump
- logger.log: "Zone 2 security stop"
switch:
- platform: gpio
pin: GPIO16
name: "Winter mode"
id: winter_mode
inverted: true
restore_mode: ALWAYS_OFF
- platform: gpio
pin: GPIO17
name: "Zone 1 pump"
id: zone1_pump
inverted: true
restore_mode: ALWAYS_OFF
on_turn_on:
then:
- script.stop: keep_winter_mode_on
- switch.turn_on: winter_mode
- script.execute: zone1_pump_security
on_turn_off:
then:
- script.stop: zone1_pump_security
- script.execute: keep_winter_mode_on
- platform: gpio
pin: GPIO18
name: "Zone 2 pump"
id: zone2_pump
inverted: true
restore_mode: ALWAYS_OFF
on_turn_on:
then:
- script.stop: keep_winter_mode_on
- switch.turn_on: winter_mode
- script.execute: zone2_pump_security
on_turn_off:
then:
- script.stop: zone2_pump_security
- script.execute: keep_winter_mode_on
Thermometers
To measure the temperature in the rooms, I used two Xiaomi Mi Home Bluetooth Thermometer 2 (~6 EUR each). They transmit the temperature via BLE (Bluetooth Low Energy) beacons.
Their LCD display is very convenient and, as they are battery powered, you can place them in the better part of the room. I flashed them with this custom firmware:
https://github.com/pvvx/ATC_MiThermometer
I’m still surprised by these small beasts, there are now firmwares to transform them in Zigbee:
https://devbis.github.io/telink-zigbee/.
Home Assistant
The control, reading the thermometers and activating the pumps, is done via a Home Assistant (HA) running in an old X86 tablet with Ubuntu (this is usually run in a Raspberry Pi or similar…).
I installed HA in a Docker container, this is my script to update and start the container:
#!/bin/bash
cd $(dirname $(readlink -f $0))
docker stop homeassistant
docker rm homeassistant
docker pull ghcr.io/home-assistant/home-assistant:stable
docker run -d \
--name homeassistant \
--privileged \
--restart=unless-stopped \
-e TZ=Europe/Madrid \
-v ./config:/config \
-v /etc/letsencrypt:/etc/letsencrypt \
--network=host \
ghcr.io/home-assistant/home-assistant:stable
docker image prune --all
Home assistant reads the thermometers via the Passive BLE monitor integration: https://github.com/custom-components/ble_monitor that can be easily installed via HACS (the Home Assistant Community Store). I needed a Bluetooth 5 USB adapter.
Then, I needed to setup two thermostats in HA via the config/configuration.yaml file:
climate:
- platform: generic_thermostat
name: "Living Room"
unique_id: zone_1_thermostat
heater: switch.zone_1_pump
target_sensor: sensor.ble_temperature_living_room_thermometer
min_temp: 15
max_temp: 20
ac_mode: false
target_temp: 17
cold_tolerance: 0.5
hot_tolerance: 0
min_cycle_duration:
minutes: 30
keep_alive:
minutes: 5
initial_hvac_mode: "off"
away_temp: 15
precision: 0.1
- platform: generic_thermostat
name: "Bedrooms"
unique_id: zone_2_thermostat
heater: switch.zone_2_pump
target_sensor: sensor.ble_temperature_bedrooms_thermometer
min_temp: 15
max_temp: 20
ac_mode: false
target_temp: 17
cold_tolerance: 0.5
hot_tolerance: 0
min_cycle_duration:
minutes: 3
keep_alive:
minutes: 5
initial_hvac_mode: "off"
away_temp: 15
precision: 0.1
Home Assistant doubles as temperature and humidity logger, and its easy to configure dashboards:
And, of course, now I’m using HA to control many other things at home.
Another complex parts were:
- Making HA accessible via internet setting up a couple port redirections (one for HA and another for certbot) and a dynamic DNS service
- Setup nginx and certbot for HTTPS
- Connecting it to Google Home to allow receiving voice commands from my Nest Minis
But that is another long story…