CTC GSi Heat pump modbus connection

This solution assumes there is a display/control unit. However, I have an EcoPart 400, which I control manually on/off using an esp32, so there is no display to connect to.

However the manual for connecting displays (i.e. EcoLogic) says they should be connected using Liycy-cable to ports G51-53.

Could it be possible to connect the esp directly to those instead of to a display? Or does the display do some “translation” of protocals between the pump and display?

image

I also have a GSi 12, but it’s not working out of the box. Would you be so kind to tell me what you have changed, so that it will work with the GSI 12?

did you get this to work so you can share your esp code?
Do you have the display with 2 or 3 ports?

Yes, I got it working! Been working well for about a year now.

I noticed that the registers in the pdfs does not fully match so I spent some time to try and figure out the settings/data I want.
I think I have two ports in the panel, the indoor unit is from ~2016

1 Like

Have a CTC Gsi 612 that I connected to home assistant via modbus. I have an outside sensor but no sensor inside.

Can you use my usual sensors around the house to adjust the heat (the curve I assume)? Thought of an average value that helps to adjust the heat up or down?

Will probably switch to electricity price per hour, so I’m thinking about if you can somehow get it to produce more heat, for example those hours the electricity price is low to produce less those hours it’s expensive.

With the hot water, I produce a little more when the solar panels provide good power.

Hi
I have an ecoparti612m and want to read data from it.

esphome:
  name: aa
  friendly_name: aa

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "Vs8FLUZTUKvZiib3DyNY9cvM10/pJ/RmbF595ucjo1o="

ota:
  password: "1683179a14b3194a946387d29c6b0389"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Aa Fallback Hotspot"
    password: "OxIwoSueKf7r"

captive_portal:
    

uart:
  id: mod_bus
  tx_pin: D7
  rx_pin: D5
  baud_rate: 9600
  parity: EVEN
  stop_bits: 1

modbus:
  #flow_control_pin: 12
  send_wait_time: 500ms
  id: modbus1
  

modbus_controller:
  - id: epever
    ## the Modbus device addr
    address: 1
    modbus_id: modbus1
    setup_priority: -10
    update_interval: 10s

sensor:
  

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Kompressor Status"
    id: compressor_status
    register_type: read
    #state_class: "measurement"
    address: 0x0000F241
    #unit_of_measurement: "°C"
    #device_class: "enum"
    accuracy_decimals: 0
    value_type: S_WORD

I connected the Esp8266 to the display with an RJ12 cable.
I can’t get any response from the pump.

INFO ESPHome 2023.9.3
INFO Reading configuration /config/esphome/aa.yaml...
INFO Starting log output from aa.local using esphome API
INFO Successfully connected to aa.local
[12:52:08][I][app:102]: ESPHome version 2023.9.3 compiled on Sep  1 2024, 12:32:14
[12:52:08][C][wifi:546]: WiFi:
[12:52:08][C][wifi:382]:   Local MAC: XX:XX:XX:XX:XX:XX
[12:52:08][C][wifi:383]:   SSID: 'XXXX'[redacted]
[12:52:08][C][wifi:384]:   IP Address: XXX.XXX.XXX.XXX
[12:52:08][C][wifi:385]:   BSSID: XX:XX:XX:XX:XX:XX[redacted]
[12:52:08][C][wifi:387]:   Hostname: 'aa'
[12:52:08][C][wifi:389]:   Signal strength: -69 dB ▂▄▆█
[12:52:08][C][wifi:393]:   Channel: 10
[12:52:08][C][wifi:394]:   Subnet: XX.xx.xx.xx
[12:52:08][C][wifi:395]:   Gateway: x.x.x.x
[12:52:08][C][wifi:396]:   DNS1: x.x.x.x
[12:52:08][C][wifi:397]:   DNS2: 0.0.0.0
[12:52:08][C][logger:357]: Logger:
[12:52:08][C][logger:358]:   Level: DEBUG
[12:52:08][C][logger:359]:   Log Baud Rate: 115200
[12:52:08][C][logger:361]:   Hardware UART: UART0
[12:52:08][C][uart.arduino_esp8266:102]: UART Bus:
[12:52:08][C][uart.arduino_esp8266:103]:   TX Pin: GPIO13
[12:52:08][C][uart.arduino_esp8266:104]:   RX Pin: GPIO14
[12:52:08][C][uart.arduino_esp8266:106]:   RX Buffer Size: 256
[12:52:08][C][uart.arduino_esp8266:108]:   Baud Rate: 9600 baud
[12:52:08][C][uart.arduino_esp8266:109]:   Data Bits: 8
[12:52:08][C][uart.arduino_esp8266:110]:   Parity: EVEN
[12:52:08][C][uart.arduino_esp8266:111]:   Stop bits: 1
[12:52:08][C][uart.arduino_esp8266:115]:   Using software serial
[12:52:08][C][modbus:143]: Modbus:
[12:52:08][C][modbus:145]:   Send Wait Time: 500 ms
[12:52:08][C][modbus:146]:   CRC Disabled: NO
[12:52:08][C][modbus_controller.sensor:010]: modbus_controller.sensorModbus Controller Sensor 'Kompressor Status'
[12:52:08][C][modbus_controller.sensor:010]: modbus_controller.sensor  State Class: ''
[12:52:08][C][modbus_controller.sensor:010]: modbus_controller.sensor  Unit of Measurement: ''
[12:52:08][C][modbus_controller.sensor:010]: modbus_controller.sensor  Accuracy Decimals: 0
[12:52:08][C][captive_portal:088]: Captive Portal:
[12:52:08][C][mdns:115]: mDNS:
[12:52:08][C][mdns:116]:   Hostname: aa
[12:52:08][C][ota:097]: Over-The-Air Updates:
[12:52:08][C][ota:098]:   Address: aa.local:8266
[12:52:08][C][ota:101]:   Using Password.
[12:52:08][C][api:138]: API Server:
[12:52:08][C][api:139]:   Address: aa.local:6053
[12:52:08][C][api:141]:   Using noise encryption: YES
[12:52:08][C][modbus_controller:298]: ModbusController:
[12:52:08][C][modbus_controller:299]:   Address: 0x01
[12:52:18][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:52:28][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:52:38][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:52:48][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:52:58][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:53:08][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:53:18][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:53:28][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:53:38][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue
[12:53:48][D][modbus_controller:040]: Modbus command to device=1 register=0xF241 countdown=0 no response received - removed from send queue

What am I doing wrong?

Hi!
I’m trying to find a nice solution how to connect my CTC GSI 16 to HomeAssistant. Is this project still up to date or has anyone tried to make HW on Wemos D1 ?
I have the 587057301 Display that has 2 RJ12 connnections in the back and only one connected to the Boiler/heatpump. This is not the display with ethernet/internet support.
Is this project the preferred solution to connect CTC Modbus to Home Assistant ?
Is the second RJ21 connection on the dislpay “modbus-out port” ?
Are there other HW solutions/projects available, either Wemos D1 or even simple Modbus to Ethernet if that’s easier.

I have my router next to the CTC GSi, so cable or Wifi doesn’t really matter.
Why I’m asking for Wemos project is because I have 2 free Wemos D1 boards available.

I know this thread is a bit old, but I’d appricate any reccommendations or help in getting data from my GSI into Home Assistant.

Hi,

My application have been working super for a long time, but after the latest update of the application and the ESP board, my application have stopped working.
Do some you user have the same problem, is the application not valid any longer?

I’m a bit confused about this github project. The thread and project seemed to be for CTC GSI but the parameter list is made for Ecoheat .
In the thread it’s comments about updated parameter list to make it work for GSI.
Anyone that has any updated code/config or parameterlist to share for GSI? I have a GSI16
@Beeny @Orikson @linesrg
I guess the code in Kaspars github project won’t work…

Any tips to share? I have everything connected to my EcoZenith i255 but I just keep getting the following error:

[08:03:06][D][modbus_controller:040]: Modbus command to device=1 register=0xF2CD no response received - removed from send queue

Did you mannage to solve this? I have the same problem.

Unfortunately, I was not able to solve this problem. I don’t know where the mistake is.

Did you manage to do it, buddy?

Nothing more than to make sure everything is hooked up correctly. My guess would be that data pins are wrong (tx/Rx swapped perhaps) or pins with some kind of special function is used. What esp are you using?

I tried to get my CTC GSi 12 to work but could not figure out the registers. I haven’t tried anymore to be honest.

But it’s true that the second port on the display is the modbus out port, at least on my older display (firmware 20200124). I also have the CTC internet module that connects to that port. I tried to connect this module in parallel to a Wemos D1 but this did not work. This is obvious because the CTC internet module acts as a Modbus master, just like the ESP32 would do. But on a modbus only one master is allowed.

Hi! Got pretty much the same response. Could also not see any values in HA device. I ditched the USB cable and connected power from the RJ12 connector instead (I did not dare to power it up with both USB and RJ12) and the readouts appeared directly in HA device info. Not sure why but maybe the modbus doesn’t work when the reference voltages do not match. But I am a happy imbecile rigth now :smile:

This topic might get very important very soon, as CTC will discontinue the internet module for the old displays and the according CTC connect+ app at the end of 2025.

After that one might need to replace the display to a newer version, that includes a RJ-45 connector for network connection. Scroll down a bit to the “Get your heat pump ready for the latest software!” section

But as far as I know this only workes with the myUplink-App, which is even worse that the CTC connect+ app.

I did some testing today and now it works, at least the basic structure! I had to switch the RX and TX of the RJ-11 connector on the D1 mini. Propably because the TX of the display needs to be connected to the RX on the ESP32 (and the same for RX on the display and TX on the ESP32). But the configuration in ESP Home differs from that, so I really don’t know. Maybe there is an error in my wiring that I was unable to figure out until now…

Strangely I need to supply my D1 mini via the USB connector. I’m using the USB connector on the display to supply the D1 mini. The 5 V of the RJ-11 connector do nothing when connected to the D1, even though I can measure +5V on those pins?! I kept this connection still. So my connection looks like this:

RJ-11 Pin1 D1 Mini Pin
1 (GND) G (GND)
2 (5V) VUSB (5V)
3 (not used) not connected
4 (RX) TX (GPIO1)
5 (Flow control) D1 (GPIO5)
6 (TX) RX (GPIO3)

This are the relevant settings in ESP Home:

# Enable logging
logger:
  baud_rate: 0

uart:
  id: mod_bus
  tx_pin: GPIO3
  rx_pin: GPIO1
  baud_rate: 9600
  parity: EVEN
  stop_bits: 1

modbus:
  flow_control_pin: GPIO5
  send_wait_time: 500 ms
  id: modbus1

Next problem I had was a strange value for the outdoor temperatur. I found out that there is an error in the code of kasper. value_type has to be S_WORD instead of U_WORD.

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Outdoor temperature"
    id: outdoor_temp
    register_type: read
    address: 0x025E
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 2
    value_type: U_WORD
    filters:
      - multiply: 0.1

Now I need to add all the available registers for my GSi 12. Luckily this document has all the registers listed on the last pages including on which devices those values are available.

EDIT: I exported this ugly table in the PDF file containing the register mapping to a real table. Of course it’s still work in progress, but if you have any comments feel free to add those: CTC Modbus address register/complete BMS list - Google Sheets

2 Likes

Hi! I also have a GSi12 and are very interested in how to get this working. Is it something that you can share? Jesper, Sweden

Hi there,

This is my current config. It’s still a pretty big mess and some of the registers contain not usable values whereas other registers are still missing. But many important measurements are already available

esphome config
  name: heizung-ctc-gsi-12
  friendly_name: Heizung CTC GSi 12

esp8266:
  board: d1_mini

# Enable logging
logger:
  baud_rate: 0

# Enable Home Assistant API
api:
  encryption:
    key: "abc"

ota:
  - platform: esphome
    password: "abc"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Heizung-Ctc-Gsi-12"
    password: "abc"

captive_portal:

# Enable Web server
web_server:
  port: 80

uart:
  id: mod_bus
  tx_pin: GPIO3 # works!
  rx_pin: GPIO1 # works!
  baud_rate: 9600
  parity: EVEN
  stop_bits: 1

modbus:
  flow_control_pin: GPIO5
  send_wait_time: 500 ms
  id: modbus1

modbus_controller:
  - id: epever
    ## the Modbus device addr
    address: 1
    modbus_id: modbus1
    setup_priority: -10
 
# Read-only registers
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 


sensor:

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Ext buffer tank upper B41"
    id: Ext_buffer_tank_upper_temp
    register_type: read
    address: 0x0000F32A
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Ext buffer tank lower B42"
    id: Ext_buffer_tank_lower_temp
    register_type: read
    address: 0x0000F32B
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Ext DHW buffer tank B43"
    id: DHW_Ext_buffer_temp
    register_type: read
    address: 0x0000F32C
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Actual temperature tank solar coil"
    id: solar_coil_temp
    register_type: read
    address: 0x0000F345
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "SolarTankSelection"
    id: SolarTankSelect_id_F374
    register_type: read
    address: 0x0000F374
    accuracy_decimals: 0
    value_type: U_WORD

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "SolarBedrockSelection"
    id: SolarBedrockSel_id_F375
    register_type: read
    address: 0x0000F375
    accuracy_decimals: 0
    value_type: U_WORD

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Outdoor temperature"
    id: outdoor_temp
    register_type: read
    address: 0x0000F230 # Works
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Return temp"
    id: Return_temp
    register_type: read
    address: 0x0000F23F
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump 1 (A1) primary system flow"
    id: Heat_pump_1_prim_flow_temp
    register_type: read
    address: 0x0000F353
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Radiator return"
    id: radiator_retur
    register_type: read
    address: 0x027A  # reasonable values, but needs further clarification ??????
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.2

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Radiator Vorlauf"
    id: radiator_frem
    register_type: read
    address: 0x0278 # reasonable values, but needs further clarification ??????
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.2

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Primary Flow Temp"
    id: pri_flo_temp
    register_type: read
    address: 0x025F  # reasonable values, but needs further clarification ??????
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump in"
    id: heat_pump_in_temp
    register_type: read
    address: 0x0000F24B # testing
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump out"
    id: heat_pump_out_temp
    register_type: read
    address: 0x0000F255 # testing
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Condenser in"
    id: con_in
    register_type: read
    address: 0x025D # reasonable values, but unknown what this is ??????
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.2

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Condenser out"
    id: con_out
    register_type: read
    address: 0x025C # reasonable values, but unknown what this is ??????
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.2

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Radiator pump setting %"
    id: Radiator_pump_percent
    register_type: read
    address: 0x0000F082
    unit_of_measurement: "%"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: S_WORD

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "EHS: Temperature"
    id: EHS_temp
    register_type: read
    address: 0x0000F2E0 # strange values
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "EHS: open shunt degrees"
    id: EHS_open_shunt_degrees
    register_type: read
    address: 0x0000F094
    unit_of_measurement: "°"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heating system 1: Heating on time"
    id: Heating_system1_heating_time
    register_type: read
    address: 0x0000F11D
    unit_of_measurement: "min"
    device_class: "duration"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    
  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Stop temperature"
    id: Stop_DHW_temp
    register_type: read
    address: 0x0000F231
    unit_of_measurement: "°C"
    device_class: "temperature"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "24h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Upper tank temperature"
    id: upper_tank_temp
    register_type: read
    address: 0x0259 # reasonable values, but needs further clarification ??????
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "2h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Upper temperature"
    id: Actual_DHW_temp
    register_type: read
    address: 0x0000F344
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "2h"
        - delta: 0.5
  
  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Lower temperature"
    id: Actual_DHW_lower_temp
    register_type: read
    address: 0x0000F343
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "2h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Current capacity"
    id: Current_DHW_capacity_percent
    register_type: read
    address: 0x0000F347
    unit_of_measurement: "%"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "2h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Setpoint outlet temperature"
    id: Setpoint_DHW_outlet_temp
    register_type: read
    address: 0x0000F232
    unit_of_measurement: "°C"
    device_class: "temperature"
    accuracy_decimals: 0
    value_type: S_WORD
    filters: 
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Hot water temperature"
    id: hot_water_temp
    register_type: read
    address: 0x0000F233
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - filter_out: 9999
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Pump"
    id: DHW_pump_percent
    register_type: read
    address: 0x0000F373
    unit_of_measurement: "%"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: U_WORD
    filters:
      - or:
        - throttle: "2h"
        #- delta: 0.1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Circulation"
    id: DHW_circulation
    register_type: read
    address: 0x0000F240
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "2h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Hot Water Valve"
    id: Hot_Water_Valve
    register_type: read
    address: 0x0000F369
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: U_WORD


  - platform: modbus_controller
    modbus_controller_id: epever
    name: "DHW: Extra hot water"
    id: extra_hot_water
    register_type: read
    address: 0x0000F03F
    state_class: "measurement"
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
      - or:
        - throttle: "12h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Radiator Pump 1"
    id: Radiator_Pump_1_percent
    register_type: read
    address: 0x0000F360
    unit_of_measurement: "%"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: U_WORD

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Radiator Pump 2"
    id: Radiator_Pump_2_percent
    register_type: read
    address: 0x0000F361
    unit_of_measurement: "%"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: U_WORD

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Power kW immersion heater"
    id: immersion_heater_kW
    register_type: read
    address: 0x0000F399
    unit_of_measurement: "kW"
    device_class: "power"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: U_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 0.2

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "HP1 Power consumption kW"
    id: HP1_power_kW
    register_type: read
    address: 0x0000F37B
    unit_of_measurement: "kW"
    device_class: "power"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: U_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 0.2

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump discharge"
    id: heat_pump_discharge_temp
    register_type: read
    address: 0x0000F25F # testing
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump suction gas"
    id: heat_pump_suction_gas_temp
    register_type: read
    address: 0x0000F269 # testing
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump high pressure"
    id: heat_pump_high_pressure
    register_type: read
    address: 0x0000F273 # testing
    #unit_of_measurement: "°C"
    device_class: "pressure"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump low pressure"
    id: heat_pump_low_pressure
    register_type: read
    address: 0x0000F27D # testing
    #unit_of_measurement: "°C"
    device_class: "pressure"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Diff thermostat"
    id: diff_thermostat_temp
    register_type: read
    address: 0x0000F2DF # testing
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Solar out"
    id: solar_out_temp
    register_type: read
    address: 0x0000F2E6 # testing
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Solar in"
    id: solar_in_temp
    register_type: read
    address: 0x0000F2E7 # testing
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.5


  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Tank timer"
    id: tank_timer
    register_type: read
    address: 0x0000F2E9 # testing
    #unit_of_measurement: "°C"
    device_class: "duration"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: S_WORD


  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump Current RPS"
    id: heat_pump_current_RPS
    register_type: read
    address: 0x0000F2F1 # testing
    device_class: "frequency"
    state_class: "measurement"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Brine in"
    id: brine_ind
    register_type: read
    address: 0x0000F287
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: U_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.2

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Brine out"
    id: brine_ud
    register_type: read
    address: 0x0000F291
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    value_type: U_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 0.2

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Degree minute"
    id: degree_minute
    register_type: read
    address: 0x0000F2D7 # Working
    unit_of_measurement: "°C min"
    device_class: "temperature"
    state_class: "measurement"
    entity_category: DIAGNOSTIC
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "1h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Start at degree minute"
    id: Start_at_degree
    register_type: read
    address: 0x0000F083
    unit_of_measurement: "°C min"
    device_class: "temperature"
    accuracy_decimals: 0
    value_type: S_WORD
    entity_category: DIAGNOSTIC
    filters:
      - or:
        - throttle: "12h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Adjustment °C"
    id: adjustment_sensor
    register_type: read
    address: 0x0000F04D # Working
    unit_of_measurement: "°C"
    device_class: "temperature"
    entity_category: DIAGNOSTIC
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 0.5

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Alarm 1"
    id: alarm_1
    register_type: read
    address: 0x0226
    entity_category: DIAGNOSTIC
    accuracy_decimals: 0
    value_type: U_WORD
    filters:
      - or:
        - throttle: "12h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Alarm 2"
    id: alarm_2
    register_type: read
    address: 0x0227
    entity_category: DIAGNOSTIC
    accuracy_decimals: 0
    value_type: U_WORD
    filters:
      - or:
        - throttle: "12h"
        - delta: 1


  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Present alarms/info"
    id: alarm_info_overview
    register_type: read
    address: 0x0000FE6D
    entity_category: DIAGNOSTIC
    accuracy_decimals: 0
    value_type: U_WORD


  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump 1 (A1): Max RPS"
    id: Heat_pump_1_max_RPS
    register_type: read
    address: 0x0000F084
    unit_of_measurement: "RPS"
    device_class: "frequency"
    accuracy_decimals: 0
    value_type: S_WORD
    entity_category: DIAGNOSTIC
    filters:
      - or:
        - throttle: "12h"
        - delta: 1
      - multiply: 0.1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Solar: EHS‐tank charge temp"
    id: Solar_EHS_tank_charge_temp
    register_type: read
    address: 0x0000F0CD
    entity_category: DIAGNOSTIC
    unit_of_measurement: "°C"
    device_class: "temperature"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - or:
        - throttle: "12h"
        - delta: 1
      - multiply: 0.1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Solar: X‐tank charge temp"
    id: Solar_X_tank_charge_temp
    register_type: read
    address: 0x0000F0CE
    entity_category: DIAGNOSTIC
    unit_of_measurement: "°C"
    device_class: "temperature"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - or:
        - throttle: "12h"
        - delta: 1
      - multiply: 0.1


  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Solar: Eco‐tank charge temp"
    id: Solar_Eco_tank_charge_temp
    register_type: read
    address: 0x0000F0CF
    entity_category: DIAGNOSTIC
    unit_of_measurement: "°C"
    device_class: "temperature"
    accuracy_decimals: 0
    value_type: S_WORD
    filters:
      - or:
        - throttle: "12h"
        - delta: 1
      - multiply: 0.1


  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Software version"
    id: software_version
    register_type: read
    address: 0x0000F2CD
    entity_category: DIAGNOSTIC
    value_type: S_WORD # was U_WORD
    accuracy_decimals: 0
    filters:
      - or:
        - throttle: "48h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heatpump type"
    id: heat_pump_type
    register_type: read
    address: 0x0000F32E
    entity_category: DIAGNOSTIC
    value_type: U_WORD
    filters:
      - or:
        - throttle: "48h"
        - delta: 1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Register 214"
    id: reg214
    register_type: read
    address: 0x000000D6
    entity_category: DIAGNOSTIC
    accuracy_decimals: 1
    value_type: S_WORD
    filters:
      - multiply: 0.1
      - or:
        - throttle: "12h"
        - delta: 0.5

text_sensor:
  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heat pump Status"
    id: heat_pump_status_text
    register_type: read
    address: 0x0000F241 # working
    entity_category: DIAGNOSTIC
    lambda: !lambda |-
      uint16_t int_mode = (data[item->offset] << 8) + data[item->offset+1];
      ESP_LOGD("main","Parsed operation mode int : %d", int_mode);
      std::string mode_str;
      switch (int_mode) {
        case 0:  mode_str = "Compressor off, start delay"; break;
        case 1:  mode_str = "Compressor off, ready to start"; break;
        case 2:  mode_str = "Compressor wait until flow"; break;
        case 3:  mode_str = "Compressor on, heating"; break;
        case 4:  mode_str = "Defrost active"; break;
        case 5:  mode_str = "Compressor on, cooling"; break;
        case 6:  mode_str = "Compressor off, blocked"; break;
        case 7:  mode_str = "Compressor off, alarm"; break;
        case 8:  mode_str = "Function test"; break;
        case 30: mode_str = "HP not defined"; break;
        case 31: mode_str = "Compressor not enabled"; break;
        case 32: mode_str = "Communication error"; break;
        case 33: mode_str = "Charge DHW"; break;
        default: mode_str = "Unknown (" + std::to_string(int_mode) +")"; break;
      }
      return mode_str;

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Status ???"
    id: any_status_text
    register_type: read
    address: 0x0000F235
    entity_category: DIAGNOSTIC
    lambda: !lambda |-
      uint16_t int_mode = (data[item->offset] << 8) + data[item->offset+1];
      ESP_LOGD("main","Parsed operation mode int : %d", int_mode);
      std::string mode_str;
      switch (int_mode) {
        case 0:  mode_str = "HP upper"; break;
        case 1:  mode_str = "HP lower"; break;
        case 2:  mode_str = "Add"; break;
        case 3:  mode_str = "HP + Add"; break;
        case 4:  mode_str = "HC"; break;
        case 5:  mode_str = "DHW"; break;
        case 6:  mode_str = "Pool"; break;
        case 7:  mode_str = "Off"; break;
        case 8:  mode_str = "Heating mix"; break;
        case 9:  mode_str = "Wood"; break;
        case 10:  mode_str = "DHW/HC"; break;
        case 11:  mode_str = "Cooling"; break;
        case 12:  mode_str = "Swap"; break;
        default: mode_str = "Unknown (" + std::to_string(int_mode) +")"; break;
      }
      return mode_str;

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heating system 1 status"
    id: heat_system1_status_text
    register_type: read
    address: 0x0000F326
    entity_category: DIAGNOSTIC
    filters:
    lambda: !lambda |-
      uint16_t int_mode = (data[item->offset] << 8) + data[item->offset+1];
      ESP_LOGD("main","Parsed operation mode int : %d", int_mode);
      std::string mode_str;
      switch (int_mode) {
        case 0:  mode_str = "Heating off"; break;
        case 1:  mode_str = "Vacation"; break;
        case 2:  mode_str = "Night reduction"; break;
        case 3:  mode_str = "On (normal mode)"; break;
        default: mode_str = "Unknown (" + std::to_string(int_mode) +")"; break;
      }
      return mode_str;

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Heating mode"
    register_type: read
    address: 0x0000F066
    entity_category: DIAGNOSTIC
    lambda: !lambda |-
      uint16_t int_mode = (data[item->offset] << 8) + data[item->offset+1];
      ESP_LOGD("main","Parsed operation mode int : %d", int_mode);
      std::string mode_str;
      switch (int_mode) {
        case 0:  mode_str = "Auto"; break;
        case 1:  mode_str = "On"; break;
        case 2:  mode_str = "Off"; break;
        default: mode_str = "Unknown (" + std::to_string(int_mode) +")"; break;
      }
      return mode_str;

binary_sensor:
  - platform: modbus_controller
    modbus_controller_id: epever
    id: charge_pump
    name: "Charge pump"
    register_type: read
    address: 0x0000F29B

  - platform: modbus_controller
    modbus_controller_id: epever
    id: brine_pump
    name: "Brine pump"
    register_type: read
    address: 0x0000F2A5

  - platform: modbus_controller
    modbus_controller_id: epever
    id: compressor_blocked
    name: "Compressor blocked" # 0 = Blocked 1 = Allowed
    register_type: read
    address: 0x0000F051
    filters:
      - invert:

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Pump Diff thermostat"
    id: pump_diff_thermostat
    register_type: read
    address: 0x0000F2DE # testing

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "EHS: Primary flow Mode" # 0 = not used 1 = EHS used for heating
    id: EHS_Primary_flow_mode
    register_type: read
    address: 0x0000F2E1

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Solar Mode"
    id: solar_mode
    register_type: read
    address: 0x0000F2E5 # testing

  - platform: modbus_controller
    modbus_controller_id: epever
    name: "Solar Pump panel"
    id: solar_pump_panel
    register_type: read
    address: 0x0000F2E8 # testing

This are some of the writable registers. Be aware that the CTC manual warns from writing those registers too often, as it will destroy the display. Propably because of the limited write cycles of the EEPROMS used to store those values.

There are also other registers that can be written without the issue of destroying the display, as you can see in this sheet. But I did not yet included those in my config. CTC Modbus address register/complete BMS list - Google Sheets

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
# Commented out as it is not good to write those registers too often

# number:
#   - platform: modbus_controller
#     modbus_controller_id: epever
#     id: extra_hot_water_timer
#     name: "Extra hot water timer"
#     address: 0x0000F03F
#     value_type: U_WORD
#     min_value: 0
#     max_value: 20
#     step: 0.5
#     mode: box
#     lambda: "return  x * 1.;"
#     write_lambda: |-
#       ESP_LOGD("main","Modbus Number incoming value = %f",x);
#       uint16_t b_capacity = x;
#       payload.push_back(b_capacity);
#       return x * 1.0 ;
#     ## multiply is ignored because lamdba is used
#     multiply: 1.0

#   - platform: modbus_controller
#     modbus_controller_id: epever
#     id: inclination_number
#     name: "Inclination"
#     address: 0x0000F049
#     value_type: U_WORD
#     min_value: 25
#     max_value: 85
#     mode: box
#     step: 1
#     lambda: "return  x * 0.1;"
#     write_lambda: |-
#       ESP_LOGD("main","Modbus Number incoming value = %f",x);
#       uint16_t c_capacity = x * 10;
#       payload.push_back(c_capacity);
#       return x * 1.0 ;
#     ## multiply is ignored because lamdba is used
#     multiply: 1
    
#   - platform: modbus_controller
#     modbus_controller_id: epever
#     id: adjustment_number
#     name: "Adjustment °C"
#     address: 0x0000F04D
#     value_type: S_WORD
#     min_value: -20
#     max_value: 20
#     mode: box
#     step: 1
#     lambda: "return  x * 0.1;"
#     write_lambda: |-
#       ESP_LOGD("main","Modbus Number incoming value = %f",x);
#       uint16_t c_capacity = x * 10;
#       payload.push_back(c_capacity);
#       return x * 1.0 ;
#     ## multiply is ignored because lamdba is used
#     multiply: 1

#   - platform: modbus_controller
#     modbus_controller_id: epever
#     id: Radiator_pump_setting_percent
#     name: "Radiator pump setting %"
#     address: 0x0000F066
#     value_type: S_WORD
#     min_value: 0
#     max_value: 100
#     mode: box
#     step: 1
#     lambda: "return  x * 1;"
#     write_lambda: |-
#       ESP_LOGD("main","Modbus Number incoming value = %f",x);
#       uint16_t c_capacity = x * 1;
#       payload.push_back(c_capacity);
#       return x * 1; 
#     ## verify calculation
#     ## multiply is ignored because lamdba is used
#     multiply: 1

#   - platform: modbus_controller
#     modbus_controller_id: epever
#     id: degree_minute_start
#     name: "Degree minute start"
#     address: 0x0000F083
#     value_type: S_WORD
#     min_value: -900
#     max_value: -30
#     mode: box
#     step: 1
#     lambda: "return  x * 1;"
#     write_lambda: |-
#       ESP_LOGD("main","Modbus Number incoming value = %f",x);
#       uint16_t c_capacity = x * 1;
#       payload.push_back(c_capacity);
#       return x * 1; 
#     ## verify calculation
#     ## multiply is ignored because lamdba is used
#     multiply: 1

#   - platform: modbus_controller
#     modbus_controller_id: epever
#     id: compressor_max_RPS
#     name: "Compressor max RPS"
#     address: 0x0000F084
#     value_type: S_WORD
#     min_value: 50
#     max_value: 100
#     mode: box
#     step: 1
#     lambda: "return  x * 0.1;"
#     write_lambda: |-
#       ESP_LOGD("main","Modbus Number incoming value = %f",x);
#       uint16_t c_capacity = x * 10;
#       payload.push_back(c_capacity);
#       return x * 1;
#     ## verify calculation
#     ## multiply is ignored because lamdba is used
#     multiply: 1

# select:
#   - platform: modbus_controller
#     name: "Heating mode"
#     id: heating_status
#     address: 0x0000F066
#     value_type: U_WORD
#     optionsmap:
#       "Auto": 0
#       "On": 1
#       "Off": 2