ESP32 Smart Thermostat with Home Assistant (Relay + Temperature + Schedule)

A simple boiler or electric heater can behave like a full smart thermostat using:

  • An ESP32
  • A temperature sensor (DS18B20 or SHT45)
  • A relay for on/off control
  • Home Assistant for schedules, modes and UI

This guide shows how to build a room or boiler thermostat with:

  • ESPHome “climate” entity
  • Hysteresis (to avoid rapid on/off cycling)
  • Manual & automatic modes
  • Time-based schedules in Home Assistant

Both DS18B20 (wired, accurate, great for pipes/tanks) and SHT45 (room temp/humidity) are covered.


1. Hardware Overview

Typical setup:

  • ESP32 DevKit
  • One of:
    • DS18B20 (waterproof probe for tank / pipe / floor)
    • SHT45 breakout (room air temperature + humidity)
  • Relay module (dry contact or contactor coil like in boiler article)
  • 4.7 kΩ resistor (for DS18B20 data pull-up)
  • 10 kΩ resistor (optional if using SHT45 breakout without onboard pull-ups)
  • USB power supply
  • DIN enclosure or wall box if installed permanently

2. Wiring

2.1 DS18B20 + Relay (Boiler or Electric Heater)

Temperature probe (1-Wire bus):

ESP32        DS18B20
3.3V   ----> VDD
GND    ----> GND
GPIO4  ----> DQ (data)

3.3V ---- 4.7kΩ ---- GPIO4

Relay control (example: GPIO26):

ESP32       Relay
3.3V  ----> VCC
GND   ----> GND
GPIO26 ----> IN

Relay COM/NO → boiler thermostat input or contactor coil circuit

2.2 SHT45 + Relay (Room Thermostat)

SHT45 on I²C:

ESP32        SHT45
3.3V   ----> VCC
GND    ----> GND
GPIO21 ----> SDA
GPIO22 ----> SCL

Relay wiring is identical (GPIO26 → IN).


METHOD 1 – ESPHome Climate-Based Thermostat

ESPHome can expose a full climate entity (thermostat) to Home Assistant.
The ESP32:

  • Reads the sensor
  • Applies hysteresis / min run time
  • Decides when to turn the relay on/off

Home Assistant only sees a thermostat card with setpoint and mode.


3. ESPHome Smart Thermostat (DS18B20 Example)

3.1 Base ESPHome YAML

esphome:
  name: esp32-smart-thermostat
  platform: ESP32
  board: esp32dev

wifi:
  ssid: "YOUR_WIFI"
  password: "YOUR_PASSWORD"

logger:
api:
ota:

3.2 DS18B20 Temperature Sensor

dallas:
  - pin: 4

sensor:
  - platform: dallas
    address: 0x1234567890ABCDEF
    name: "Boiler Temperature"
    id: boiler_temp
    filters:
      - median:
          window_size: 7
          send_every: 3
          send_first_at: 1
    update_interval: 10s

(Use dallas.read_sensors or omit address to auto-detect; you can let ESPHome print the address in logs.)

3.3 Relay Switch

switch:
  - platform: gpio
    id: boiler_relay
    pin: 26
    restore_mode: ALWAYS_OFF

3.4 Climate “Bang-Bang” Thermostat

climate:
  - platform: thermostat
    name: "Boiler Thermostat"
    sensor: boiler_temp
    default_target_temperature_low: 45 °C
    default_target_temperature_high: 50 °C

    # Single-stage heating control
    heat_action:
      - switch.turn_on: boiler_relay
    idle_action:
      - switch.turn_off: boiler_relay

    min_heating_off_time: 300s   # avoid rapid cycling
    min_heating_run_time: 300s
    min_idle_time: 120s

    visual:
      min_temperature: 30 °C
      max_temperature: 70 °C
      temperature_step: 1 °C

    # Optional: supported modes
    supported_modes:
      - HEAT
      - OFF

What this does:

  • Exposes climate.boiler_thermostat in Home Assistant
  • Uses hysteresis between target_temperature_low and target_temperature_high
  • Enforces minimum run/idle times to protect the heater

You can later adjust the target range directly from Home Assistant.


4. ESPHome Room Thermostat (SHT45)

For room air control (radiators, electric panel heater, underfloor):

4.1 SHT45 Sensor

i2c:
  sda: 21
  scl: 22
  scan: true

sensor:
  - platform: sht4x
    temperature:
      name: "Room Temperature"
      id: room_temp
    humidity:
      name: "Room Humidity"
    update_interval: 10s

4.2 Climate Config

switch:
  - platform: gpio
    id: room_heater_relay
    pin: 26
    restore_mode: ALWAYS_OFF

climate:
  - platform: thermostat
    name: "Room Thermostat"
    sensor: room_temp
    default_target_temperature_low: 20 °C
    default_target_temperature_high: 21 °C

    heat_action:
      - switch.turn_on: room_heater_relay
    idle_action:
      - switch.turn_off: room_heater_relay

    min_heating_off_time: 180s
    min_heating_run_time: 300s

    visual:
      min_temperature: 16 °C
      max_temperature: 26 °C
      temperature_step: 0.5 °C

    supported_modes:
      - HEAT
      - OFF

Now the room thermostat:

  • Heats up to ~21 °C, cools down to ~20 °C (1 °C hysteresis)
  • Shows as a standard thermostat in Home Assistant (supports setpoint sliders, modes, graphs, etc.)

5. Home Assistant – Using the Climate Entity

Once flashed, ESPHome auto-registers the thermostat:

  • climate.boiler_thermostat or climate.room_thermostat
  • sensor.boiler_temperature or sensor.room_temperature

5.1 Thermostat Card in Dashboard

type: thermostat
entity: climate.room_thermostat

Or an entities card:

type: entities
entities:
  - climate.room_thermostat
  - sensor.room_temperature

From here you can:

  • Change the setpoint
  • Set mode to HEAT / OFF
  • See history of room temperature and relay state

6. Scheduling in Home Assistant

ESPHome handles hysteresis & relay control; Home Assistant handles schedules and modes.

6.1 Simple Time-Based Schedule (Comfort / Eco)

Example: daytime 21 °C, night-time 18 °C.

automation:
  - alias: "Room Thermostat – Daytime Comfort"
    trigger:
      - platform: time
        at: "07:00:00"
    action:
      - service: climate.set_temperature
        target:
          entity_id: climate.room_thermostat
        data:
          temperature: 21

  - alias: "Room Thermostat – Night Eco"
    trigger:
      - platform: time
        at: "23:00:00"
    action:
      - service: climate.set_temperature
        target:
          entity_id: climate.room_thermostat
        data:
          temperature: 18

ESPHome automatically uses that setpoint with its built-in hysteresis.

6.2 Presence-Based Control

Lower the setpoint when nobody is at home:

  - alias: "Room Thermostat – Away Mode"
    trigger:
      - platform: state
        entity_id: person.you
        to: "not_home"
    action:
      - service: climate.set_temperature
        target:
          entity_id: climate.room_thermostat
        data:
          temperature: 16

  - alias: "Room Thermostat – Back Home"
    trigger:
      - platform: state
        entity_id: person.you
        to: "home"
    action:
      - service: climate.set_temperature
        target:
          entity_id: climate.room_thermostat
        data:
          temperature: 21

METHOD 2 – MQTT + Home Assistant “Generic Thermostat”

If you prefer to keep the ESP32 simple, you can:

  • Publish temperature only from the ESP32
  • Let Home Assistant implement the thermostat logic using generic_thermostat

In this mode:

  • ESP32 is just:
    • One temperature sensor
    • One MQTT switch for the relay

Home Assistant handles hysteresis, modes, scheduling.


7. ESP32 MQTT Entities

7.1 Temperature Sensor Topic

ESP32 publishes:

{"temperature": 21.8}

to e.g. home/room/thermostat.

Home Assistant:

mqtt:
  sensor:
    - name: "Room Thermostat Temperature"
      state_topic: "home/room/thermostat"
      value_template: "{{ value_json.temperature }}"
      unit_of_measurement: "°C"
      device_class: temperature

7.2 Relay as MQTT Switch

mqtt:
  switch:
    - name: "Room Heater Relay"
      command_topic: "home/room/heater/set"
      state_topic: "home/room/heater/state"
      payload_on: "ON"
      payload_off: "OFF"
      retain: true

ESP32 listens on .../set, toggles relay, and reports to .../state.


8. Home Assistant Generic Thermostat

climate:
  - platform: generic_thermostat
    name: "Room Thermostat"
    heater: switch.room_heater_relay
    target_sensor: sensor.room_thermostat_temperature
    min_temp: 16
    max_temp: 26
    ac_mode: false
    cold_tolerance: 0.3     # hysteresis below setpoint
    heat_tolerance: 0.3     # hysteresis above setpoint
    min_cycle_duration:
      minutes: 5
    initial_hvac_mode: "heat"
    away_temp: 16

This:

  • Exposes a standard climate.room_thermostat
  • Uses built-in hysteresis defined by cold_tolerance / heat_tolerance
  • Ensures min 5 minutes per cycle

All scheduling / presence automations from section 6 apply here as well.


9. Optional Extras

  • Humidity-based boost: With SHT45, use high humidity as a trigger to raise temperature slightly in bathrooms.
  • Window sensor lockout: If a window is open, force the thermostat to OFF or reduce setpoint.
  • Energy monitoring: Combine the thermostat with a PZEM or smart plug to estimate heating cost and efficiency.

Summary

An ESP32, a single sensor (DS18B20 or SHT45) and a relay are enough to build a full-featured smart thermostat:

  • ESPHome approach: the thermostat logic runs entirely on the ESP32, exposed as a climate entity.
  • MQTT + generic_thermostat: ESP32 stays dumb; Home Assistant does all the logic.

Both support:

  • Modes (heat/off)
  • Hysteresis & minimum runtime to protect equipment
  • Time & presence-based schedules via Home Assistant automations

This makes it easy to upgrade boilers, electric heaters or room panels into fully integrated, centrally managed heating zones.

Newsletter Updates

Enter your email address below and subscribe to our newsletter

Leave a Reply

Your email address will not be published. Required fields are marked *