olegtarasov / esphome-opentherm

Create your own smart modulating thermostat using the OpenTherm component for ESPHome
BSD 2-Clause "Simplified" License
38 stars 6 forks source link

❗ OpenTherm in ESPHome core

Starting with ESPHome 2024.11 this component is included in core! 🎉 There is no need to reference this repository for normal usage scenarios. Use official documentation to configure your OpenTherm bridge.

If you want to test bleeding edge features and fixes, read the Usage section below.

OpenTherm Component for ESPHome

OpenTherm (OT) is a standard communications protocol used in central heating systems for the communication between central heating appliances and a thermostatic controller. As a standard, OpenTherm is independent of any single manufacturer. A controller from manufacturer A can in principle be used to control a boiler from manufacturer B.

Since OpenTherm doesn't operate in a standard voltage range, special hardware is required. You can choose from several ready-made adapters or roll your own:

‼️ As of now, this component acts only as an OpenTherm master (for example, a thermostat or controller) and not as a slave or gateway. Your existing thermostat is not usable while you use ESPHome with this component to control your boiler.

There are plans to add support for a gateway mode, but I don't have any timeline to share at the moment.

Quick glossary

Usage

As I've mentioned before, this component is now part of ESPHome core. Most users don't need this repository. Just follow the official documentation to setup your bridge.

Testing unstable versions

If you want to test unstable versions of the code, choose your branch first:

After you've chosen your branch, or individual commit, add this repository as external component to your config:

external_components:
  source: github://olegtarasov/esphome-opentherm[@<branch or tag>]

Declaring the OpenTherm hub

You need to declare the OpenTherm hub in your configuration. Note that most OpenTherm adapters label in and out pins relative to themselves; this component labels its in and out pins relative to the microcontroller ESPHome runs on. As such, your bridge's in pin becomes the hub's out pin and vice versa.

opentherm:
  in_pin: GPIOXX
  out_pin: GPIOXX

Configuration variables:

Note abut sync mode

The use of some components (like Dallas temperature sensors) may result in lost frames and protocol warnings from OpenTherm. Since OpenTherm is resilient by design and transmits its messages in a constant loop, these dropped frames don't usually cause any problems. Still, if you want to decrease the number of protocol warnings in your logs, you can enable sync_mode which will block ESPHome's main application loop until a single conversation with the boiler is complete. This can greatly reduce the number of dropped frames, but usually won't eliminate them entirely. With sync_mode enabled, in some cases, ESPHome's main application loop may be blocked for longer than is recommended, resulting in warnings in the logs. If this bothers you, you can adjust ESPHome's log level by adding the following to your configuration:

logger:
  logs:
    component: ERROR

Usage as a thermostat

The most important function for a thermostat is to set the boiler temperature setpoint. This component has three ways to provide this input: using a Home Assistant sensor from which the setpoint can be read, using a number, or defining an output to which other components can write. For most users, the last option is the most useful one, as it can be combined with the PID component to create a thermostat that works as you would expect a thermostat to work. See thermostat example further in this readme.

Numerical input

There are three ways to set an input value:

For the output and number variants, there are four more properties you can configure beyond those included in the output and number components by default:

The following inputs are available:

Switch

Switches are available to allow manual toggling of any of the following seven status codes:

If you do not wish to have switches, the same values can be permanently set in the hub configuration, like so:

opentherm:
  ch_enable: true
  dhw_enable: true

This is useful when you'd never want to toggle it after the initial configuration.

The default values for these configuration variables are listed below.

To enable central heating and cooling, the flag is only sent to the boiler if the following conditions are met:

For domestic hot water and outside temperature compensation, only the first two conditions are necessary.

The last point ensures that central heating is not enabled if no heating is requested as indicated by a setpoint of 0. If you use a number as the setpoint input and use a minimum value higher than 0, you must use the ch_enable switch to turn off your central heating. In such a case, the flag will be set to true in the hub configuration and the setpoint is always larger than 0, so including a switch is the only way you can turn off central heating. (This also holds for cooling and CH2.)

Binary sensor

The component can report boiler status on several binary sensors. The Status sensors are updated in each message cycle, while the others are only set during initialization, as they are unlikely to change without restarting the boiler.

Sensor

The boiler can also report several numerical values, which are available through sensors. Your boiler may not support all of these values, in which case there won't be any value published to that sensor. The following sensors are available:

Fan speed sensor

An issue was raised about fan_speed sensor giving wonky values: https://github.com/olegtarasov/esphome-opentherm/issues/12. It turned out that originally this library was using unsigned 16-bit integer to interpret fan speed, and it didn't work for some boilers. OpenTherm specification suggests that 8-bit integer should be used, with another 8 bits being a separate sensor, fan_speed_setpoint. Tests have also shown that for those boilers value interpreted as 8-bit integer should be further multiplied by 60 to obtain final RPM value.

I decided to modify fan_speed sensor to work as 8-bit integer, performing the multiplication automatically, because it's closer to OpenTherm specification.

Obviously, this breaks fan_speed sensor for boilers that encode values as 16-bit integers. In order to fix this, we added data_type property which allows to override sensor data type.

So if you configured a fan_speed sensor, but suspect that it gives the wrong values, try to reconfigure it as follows:

sensor:
  - platform: opentherm
    fan_speed:
      name: "Boiler fan speed"
      data_type: "u16" # overrides the default u8_lb_60 message

Examples

Minimal example with numeric input

# An extremely minimal configuration which only enables you to set the boiler's
# water temperature setpoint as a number.

opentherm:
  in_pin: GPIOXX
  out_pin: GPIOXX
  ch_enable: true

number:
  - platform: opentherm
    t_set:
      name: "Boiler Control setpoint"

Basic PID thermostat

# A basic thremostat for a boiler with a single central heating circuit and
# domestic hot water. It reports the flame, CH and DHW status, similar to what
# you would expect to see on a thermostat and also reports the internal boiler
# temperatures and the current modulation level. The temperature is regulated
# through a PID Climate controller and the current room temperature is retrieved
# from a sensor in Home Asisstant.

# This configuration should meet most needs and is the recommended starting
# point if you just want a thermostat with an external temperature sensor.

opentherm:
  in_pin: GPIOXX
  out_pin: GPIOXX
  dhw_enable: true    # Note that when we specify an input in hub config with a static value, it can't be
                      # changed without uploading new firmware. If you want to be able to turn things on or off,
                      # use a switch (see the ch_enable switch below).
                      # Also note that when we define an input as a switch (or use other platform), we don't need
                      # to set it at hub level.

output:
  - platform: opentherm
    t_set:
      id: t_set
      min_value: 20
      max_value: 65
      zero_means_zero: true

sensor:
  - platform: opentherm
    rel_mod_level:
      name: "Boiler Relative modulation level"
    t_boiler:
      name: "Boiler water temperature"
    t_ret:
      name: "Boiler Return water temperature"

  - platform: homeassistant
    id: ch_room_temperature
    entity_id: sensor.temperature
    filters:
      # Push room temperature every second to update PID parameters
      - heartbeat: 1s

binary_sensor:
  - platform: opentherm
    ch_active:
      name: "Boiler Central Heating active"
    dhw_active:
      name: "Boiler Domestic Hot Water active"
    flame_on:
      name: "Boiler Flame on"
    fault_indication:
      name: "Boiler Fault indication"
      entity_category: diagnostic
    diagnostic_indication:
      name: "Boiler Diagnostic event"
      entity_category: diagnostic

switch:
  - platform: opentherm
    ch_enable:
      name: "Boiler Central Heating enabled"
      restore_mode: RESTORE_DEFAULT_ON

climate:
  - platform: pid
    name: "Central heating"
    heat_output: t_set
    default_target_temperature: 20
    sensor: ch_room_temperature
    control_parameters:
      kp: 0.4
      ki: 0.004

References

This component was forked from Arthur Rump's esphome-opentherm component, which now seems to be abandoned. I replaced the underlying OpenTherm library with code form Jiří Praus. I also did a lot of refactoring to bring the code closer to ESPHome coding standard.

There is also my blog post with more background details and reasoning for automating an OpenTherm boiler with ESPHome: