ESPHome Underflooor heating Pump Switch – ET-PS01
Table of Contents
Introduction
As electricity is so damn expensive in Europe now and my (2) underfloor heating pumps are constantly consuming more than 40 Watt each, I wanted to find a smarter solution for that. While browsing the internet of course it turned out there are existing solutions to the problem that will simply switch of electricity to the pump when the measured temperature of the heating supply pipe falls below a certain temperature. The cost of such devices varies between €25,00 and €55,00 and these things have some serious disadvantages. For instance you won’t be able to connect them to Home Assistant. Well, that did it for me… I needed to come up with a smarter solution. 😉
Design parameters
My requirements were:
- Wemos D1 mini ESP8266 controlled (due to smaller size)
- Operating at 230V AC, so I can install it in-line with the pump.
- Temperature measurement and historic graphs.
- Must fit in a custom 3D-printable enclosure.
- Parts should be available at AliExpress or Amazon for affordable prices, making it as cheap as possible to build
- Firmware should be ESPhome (for use with Home Assistant)
Practical design
I talked to Paul and we agreed the design should be reliable but simple and cheap to build. After some measuring and testing he came up with this PCB design:

ET-PS01 PCB
It’s all fairly simple: You cut the power-supply cable of your underfloor heating pump in half. One end of the cable goes to ‘AC-in’, the other and to ‘Pump-out’. The PCB is powered by a small 230V AC to 5V DC power supply.
The internal Dallas temperature sensor on the bottom of the PCB will measure the heating supply pipe temperature and switch on/off the power to your underfloor heating pump using the on-board 10A relay.

Dallas temperature sensor
There is also an option to connect a (primary or secondary) external Dallas temperature sensor at JP2. For safety reasons we added a fuse. That’s about it.
We did not even bother building a prototype but ordered the PCB’s at PCBway. Waiting for the postman Paul designed a 3d-printable enclosure to go with the PCB. The Dallas temperature sensor sticks out the back, you simply fold it in the cavity and your done.


3d-printable case – Dallas sensor cavity
Finally we threw the ESPHome firmware on it. and the thing worked right away 🙂

Circuit diagram

Build it!
Bill of materials
See below the list with the components you will need to build the ET-PS01 controller. A number of these items will not be sold in smaller quantities at AliExpress. We will try to use the same components as much as possible in future projects.
We would really appreciate it if you will use the links below to buy the components, since it will give a little bit of commission to us without any additional cost for yourself. These commissions will be used to cover some of the costs involved in the development of the design.
| Reference | Qty | Description | Link |
| WEMOS1 | 1 | Wemos Mini D1 ESP8266* | AliExpress |
| D1 | 1 | 1N4148 | AliExpress |
| C1 | 1 | 470µF / 16V 6mm diameter, 2.54mm pitch | AliExpress |
| T1 | 1 | S8050 TO-92 Triode Transistor | Aliexpress |
| R1 | 1 | Resistor 220 ohm | AliExpress |
| R2 | 1 | Resistor 3k3 | AliExpress |
| R3 | 1 | Resistor 4k7 | Aliexpress |
| X1, X2 | 2 | 9 pole terminal, or 3x 2 pole + 1x 3 pole. 5.00mm pitch | Aliexpress |
| SENSOR | 1 | DS18b20 Dallas temperature sensor | Aliexpress |
| F1 | 1 | 0,2-0,5A self resetting fuse 230V | Aliexpress |
| K1 | 5V relay 230V/10A (5VDC SRD-05VDC-SL-C) | Aliexpress | |
| X3 | 1 | AC-DC 5V 700mA power supply (Vertical-5V 700MA) | Aliexpress |
| LED | 1 | 5mm Red LED | Aliexpress |
| Enclosure | 1 | 3d-print | Thingiverse |
| PCB | 1 | A 5-pack is the smallest order at PCBway, enough for you and your friends 😉 | PCBway |
Putting it together
Like with all other projects, it is the easiest to start with identifying the components purchased as discussed in the blog post. After sorting the components and cleaning the PCB, start with the lowest components first. For this project, we advise to work in this order:
- Resistors
- Transistor
- Fuse
- Screw terminals
- ESP module headers (Use the hints in the soldering blog post!)
- Electrolytic capacitor
- Relay
- Power supply
- Dallas sensor
- Led
Once all components are soldered in place, perform a good visual check of all joints, and pay particular attention to possible solder bridges (unwanted solder connections between pins). Do not forget to clean the excess solder flux from the PCB using alcohol!
Software configuration
# Underfloor Heating Pump Controller
# ESPHome - with Dallas temperature sensor
#
# Controls a underfloor heating-pump. When warm water is received from the
# central heater, warm water is entering the pump via its pipes. This is
# detected by the temperature sensor and the pump will be switched on.
# When the heater stops (requested temperature is reached) the flow of water
# will cool down. The temperature sensor will detect this and will shut
# down the pump.
#
# The RED LED light indicates the mode. In automatic mode (default) flashes
# slowly.
#
# In case the controller is unable to connect with Home Assistant for 5 minutes,
# the controller switches over to automatic mode.
#
# Manny thanks to Martin for the initial configuration!
# https://github.com/Martinvdm/underfloor_heating_pump_controller
substitutions:
devicename: "espthings-et-ps01-002"
upper_devicename: "Vloerverwarming boven"
esphome:
name: "$devicename"
platform: ESP8266
board: d1_mini
esp8266_restore_from_flash: yes
comment: "$upper_devicename"
on_boot:
then:
- script.execute: led_signaling
- script.execute: controller
wifi:
ssid: !secret esphome_wifi_ssid
password: !secret esphome_wifi_password
ap:
ssid: "$devicename"
password: "qwe12345"
logger:
web_server:
port: 80
ota:
password: !secret esphome_ota_password
api:
encryption:
key: !secret esphome_api_key
services:
- service: threshold_off
variables:
value: float
then:
- lambda: |-
if (value < 0.0f){
return;
}
if (value > 48.0f){
value = 48.0;
}
id(g_threshold_temp_off) = value;
auto d = id(g_threshold_temp_on) - id(g_threshold_temp_off);
if (d < 2.0){
id(g_threshold_temp_on) = value + 2.0;
}
- script.execute: controller
- service: threshold_on
variables:
value: float
then:
- lambda: |-
if (value > 50.0f){
return;
}
if (value < 2.0) {
value = 2.0;
}
id(g_threshold_temp_on) = value;
auto d = id(g_threshold_temp_on) - id(g_threshold_temp_off);
if (d < 2.0){
id(g_threshold_temp_off) = value - 2.0;
}
- script.execute: controller
globals:
# true when in automatic mode
# false when in manual mode
- id: g_automatic_mode
type: bool
restore_value: no
initial_value: "true"
# if water temperature below this threshold
# pump demand automatic will be 'off' (false)
- id: g_threshold_temp_off
type: float
restore_value: no
initial_value: "34.0"
# if water temperature above this threshold
# pump demand automatic will be 'on' (true)
- id: g_threshold_temp_on
type: float
restore_value: no
initial_value: "36.0"
# manual demand pump
- id: g_pump_demand_manual
type: bool
restore_value: no
initial_value: "false"
# demand based on water temperature
- id: g_pump_demand_automatic
type: boolean
restore_value: no
initial_value: "false"
dallas:
- pin: D5
update_interval: 60s
sensor:
- platform: dallas
id: sensor_water_temperature
name: "$upper_devicename temperature"
address: 0x803c01d075271728
unit_of_measurement: "°C"
device_class: temperature
accuracy_decimals: 1
filters:
- delta: 0.1
on_value:
then:
# the controller is notified when the water temperature crosses
# one of the thresholds
- lambda: |-
/* only useful when in automatic mode */
if(!id(g_automatic_mode)){
return;
}
/* only submit when something has changed */
auto water_temperature = id(sensor_water_temperature).state;
if (
water_temperature < id(g_threshold_temp_off)
&& id(g_pump_demand_automatic)){
id(g_pump_demand_automatic) = false;
id(controller).execute();
}
else if (
water_temperature > id(g_threshold_temp_on)
&& !id(g_pump_demand_automatic)){
id(g_pump_demand_automatic) = true;
id(controller).execute();
}
- platform: template
name: "$upper_devicename Threshold off"
id: sensor_threshold_temp_off
unit_of_measurement: "°C"
accuracy_decimals: 1
lambda: return id(g_threshold_temp_off);
update_interval: 1ms
filters:
- delta: 0.1
- platform: template
id: sensor_threshold_temp_on
name: "$upper_devicename Threshold on"
unit_of_measurement: "°C"
accuracy_decimals: 1
lambda: return id(g_threshold_temp_on);
update_interval: 1ms
filters:
- delta: 0.1
- platform: wifi_signal
name: "$upper_devicename WiFi Signal"
update_interval: 60s
- platform: uptime
name: "$upper_devicename Uptime"
id: uptime_sensor
update_interval: 60s
on_raw_value:
then:
- text_sensor.template.publish:
id: uptime_human
state: !lambda |-
int seconds = round(id(uptime_sensor).raw_state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
return (
(days ? to_string(days) + "d " : "") +
(hours ? to_string(hours) + "h " : "") +
(minutes ? to_string(minutes) + "m " : "") +
(to_string(seconds) + "s")
).c_str();
text_sensor:
- platform: template
name: "$upper_devicename Uptime Human Readable"
id: uptime_human
icon: mdi:clock-start
binary_sensor:
# In case the API connection is lost, the controller will change
# to automatic mode.
- platform: template
id: sensor_api_connected
lambda: return global_api_server->is_connected();
filters:
- delayed_off: 5min
on_release:
then:
- logger.log: Lost API connection, selecting automatic mode
- switch.turn_on: sw_automatic_mode
# template sensor to publish pump state
- platform: template
name: "$upper_devicename Pump"
id: sensor_pump_state
lambda: return id(ps01_relay).state;
switch:
# relay, switches pump on and off
- platform: gpio
pin:
number: GPIO12
inverted: true
id: ps01_relay
# Boolean input to toggle between manual or automatic mode
- platform: template
name: "$upper_devicename Manual/Automatic"
id: sw_automatic_mode
lambda: return id(g_automatic_mode);
turn_on_action:
- globals.set:
id: g_automatic_mode
value: "true"
- script.execute: controller
- script.execute: led_signaling
turn_off_action:
- globals.set:
id: g_automatic_mode
value: "false"
- script.execute: controller
- script.execute: led_signaling
# Boolean input to control manual demand
- platform: template
name: "$upper_devicename On/Off"
id: sw_on_off
lambda: return id(g_pump_demand_manual);
turn_on_action:
- globals.set:
id: g_pump_demand_manual
value: "true"
- script.execute: controller
turn_off_action:
- globals.set:
id: g_pump_demand_manual
value: "false"
- script.execute: controller
script:
# script for calculating the demand for the pump. Should
# it run or not. Applies the changes to the relay.
- id: controller
then:
- lambda: |-
/* calculate if pump should be on or not */
bool demand = false;
if (!id(g_automatic_mode)){
/* manual mode */
demand = id(g_pump_demand_manual);
}
else{
/* automatic mode */
demand = id(g_pump_demand_automatic);
}
/* only send commands when needed */
if (demand && !id(ps01_relay).state) {
id(ps01_relay).turn_on();
} else if (!demand && id(ps01_relay).state){
id(ps01_relay).turn_off();
}
- id: led_signaling
then:
# The green led is used to show the mode of operation:
# - manual mode, led is on
# - automatic mode, led blinks
- lambda: |-
if (id(g_automatic_mode)){
auto call = id(ps01_led_light).turn_on();
call.set_effect("auto_effect");
call.perform();
} else {
auto call = id(ps01_led_light).turn_on();
call.set_effect("none");
call.perform();
}
output:
- platform: esp8266_pwm
id: ps01_led
pin:
number: GPIO13
inverted: True
light:
- platform: monochromatic
output: ps01_led
id: ps01_led_light
effects:
- strobe:
name: auto_effect
colors:
- brightness: 100%
duration: 1s
- brightness: 0%
duration: 2s
Home Assistant
This is what it looks like in Home Assistant:

Final thoughts
We have this running for about 3 months now and it works great. On stand-by the pump (including the ET-PS01) consumes about 0.6w, which is 39,4 Watt less than before 😉
If you want to save some electricity and monitor your underfloor heating supply temperature in Home Assistant, then build this thing yourself! If you do, please let us know in the comments 🙂
If you run into issues during the construction, or you have any question regarding this controller, please leave a comment below. We will try to reply as soon as possible!
Make sure to subscribe to our YouTube channel so you won’t miss any of our upcoming project videos!
Please subscribe to our newsletter!


Next month, I am going to install floor heating in my home. As a Home Assistant/esphome user, this project might just be exactly what I am looking for. Pretty sure I will built this, if I get some confirmation the pump that will be installed can handle the frequent on/off switching.
Thanks!