Browsing the list of ESPHome components I noticed a picture that looked very familiar. In my house I have this device Joule DeltaSol BS HE branded as "Joule" and labeled "DeltaSolⓇ BS HE" and on ESPHome site they show "Resol DeltaSolⓇ BS Plus": Resol DeltaSol BS Plus

Two devices look very similar and apparently Resol OEMs its devices to other brands. These devices are solar panel controller. Not for the photovoltaic solar panels that I would usually have in mind but instead for solar thermal collectors, which harness solar heat and in my case use it to heat hot water.

The ESPHome component I noticed is called VBus. It does not explicitly list my device (labeled "DeltaSol BS HE" on the outside and "DeltaSol BS/2 HE" inside) as supported. However it provides some guidance in connecting pretty much arbitrary devices that speak VBus protocol.

Connecting VBus device to UART requires adjustment of electrical levels. ESPHome component mentions two schemes. I first tried building an electrically isolated version with an opto-coupler because this should provide better protection of ESP8266/ESP32 device. But it didn't work. I could see adjusted signal levels but neither ESP nor simple TTL-UART USB converter was picking them up.

My second attempt with a more traditional scheme (the first one listed on ESPHome component page) worked and ESP8266 I was using in this case indicated that it was receiving some data.

Prototype on a breadboard:

To decoded the data I had to specify the address of my controller and describe how to extract interesting data from the packet.

Identifying the address is covered in Supported Models section. I just had to enable verbose logging to get the address which in my case was 0x4720.

To extract values from packets I had to define custom VBus sensors. The location of specific values in the packet can be found in VBus Specification - search for specific device and switch to "bytes" mode.

My controller was sending data every second which I think is way too often and is both not useful and unhealthy for the performance of Home Assistant so I applied some throttling.

My Home Assistant widget:

Home Assistant widget

The "Heat quantity" sensor is 0 because my hardware configuration does not count the amount of energy. It would require a sensor on the return flow of the heat-transfer fluid which is not installed.

Here's my configuration of VBus sensor:

# https://esphome.io/components/vbus.html
# http://danielwippermann.github.io/resol-vbus/#/vsf/bytes/00_0010_4720_10_0100
# DeltaSol BS/2 HE
sensor:
  - platform: vbus
    model: custom
    dest: 0x10
    source: 0x4720
    command: 0x100
    sensors:
      - id: temperature_1
        name: Temperature 1
        device_class: temperature
        state_class: measurement
        unit_of_measurement: "°C"
        accuracy_decimals: 1
        lambda: |-
          unsigned lsb = x[4];
          unsigned msb = x[5];
          if (msb > 127) {
            return (65536 - msb * 256 - lsb) * -0.1f;
          }
          return (msb * 256 + lsb) * 0.1f;
        filters:
          - sliding_window_moving_average:
              window_size: 30
              send_every: 30

      - id: temperature_2
        name: Temperature 2
        device_class: temperature
        state_class: measurement
        unit_of_measurement: "°C"
        accuracy_decimals: 1
        lambda: return ((x[7] << 8) + x[6]) * 0.1f;
        filters:
          - sliding_window_moving_average:
              window_size: 30
              send_every: 30

      - id: temperature_3
        name: Temperature 3
        device_class: temperature
        state_class: measurement
        unit_of_measurement: "°C"
        accuracy_decimals: 1
        lambda: return ((x[9] << 8) + x[8]) * 0.1f;
        filters:
          - sliding_window_moving_average:
              window_size: 30
              send_every: 30

      - id: pump_speed
        name: Pump speed
        device_class: power_factor
        state_class: measurement
        unit_of_measurement: "%"
        accuracy_decimals: 0
        lambda: return x[16];
        filters:
          - or:
            - throttle: 30s
            - delta: 1

      - id: heat_quantity
        name: Heat quantity
        device_class: energy
        state_class: total_increasing
        unit_of_measurement: "Wh"
        accuracy_decimals: 0
        lambda: return ((x[23] << 24) + (x[22] << 16) + (x[21] << 8) + x[20]);
        filters:
          - or:
            - throttle: 30s
            - delta: 1

      - id: software_version
        name: Software version
        entity_category: diagnostic
        accuracy_decimals: 2
        lambda: return ((x[25] << 8) + x[24]) * 0.01f;
        filters:
          - or:
            - throttle: 30s
            - delta: 0.01

      - id: operating_hours
        name: Operating hours
        device_class: duration
        state_class: total_increasing
        unit_of_measurement: "h"
        accuracy_decimals: 0
        lambda: return ((x[31] << 24) + (x[30] << 16) + (x[29] << 8) + x[28]);
        filters:
          - or:
            - throttle: 30s
            - delta: 1

      - id: error_mask
        name: Error mask
        entity_category: diagnostic
        lambda: return ((x[71] << 24) + (x[70] << 16) + (x[69] << 8) + x[68]);
        filters:
          - or:
            - throttle: 30s
            - delta: 1

Update 2023-12-02: The configuration of temperature_1 sensor has been updated to correctly report negative temperatures. This sensor is in (or on) the panel itself and so can report negative temperatures when it gets cold outside.