Modbus - iSaver+ Pool Pump Inverter - Custom Commands Issue - Response mising bytes

Hello, I am currently trying to create a module that will connect to my iSaver+ Pool Pump inverter and allow me to read the current state of the pool pump from the unit.

Pool pump regulator manual: [Manual (page 8) ]

I have set up an ESP-32 with a TTL to RS485 converter and have managed to send a custom command and see a response from the unit.

The iSaver+ uses non-standard Modbus protocol commands which are detailed in this document here: RS485 Protocol.

The issue I have is that when receviing the standard response code from the unit ESP Home does not seem to receive the last byte of data which means the CRC check fails and I cannot read the response.

You can see in the logs here that only 8 bytes of data are received whereas the protocal calls for a response of 9 bytes. Here are the expected frames for query and response.
The query is working fine and the unit accepts the 8 byte custom command i can send.

You can see in the logs below that only 8 bytes are received as opposed to the 9 bytes expected in the Request Frame table above. Modbus received Byte 252 (0Xfc) is the first byte of the CRC Vericiation Code and then the last byte of that code is always missing. Hence CRC Checksum fails.

[13:33:33][V][modbus_controller:047]: Sending next modbus command to device 170 register 0x19C6 count 1
[13:33:33][VV][uart.arduino_esp32:180]:     Flushing...
[13:33:33][V][modbus:220]: Modbus write raw: AA.C3.07.D1.00.00 (6)
[13:33:33][V][modbus_controller:509]: Command sent 0 0x19C6 1
[13:33:33][W][component:214]: Component modbus_controller took a long time for an operation (0.08 s).
[13:33:33][W][component:215]: Components should block for at most 20-30ms.
[13:33:33][C][ota:096]: Over-The-Air Updates:
[13:33:33][C][ota:097]:   Address: swimming-pool-pump-temporary.local:3232
[13:33:33][C][ota:100]:   Using Password.
[13:33:33][C][ota:103]:   OTA version: 2.
[13:33:33][D][uart_debug:114]: >>> AA:C3:07:D1:00:00:0D:4D
[13:33:33][C][api:139]: API Server:
[13:33:33][C][api:140]:   Address: swimming-pool-pump-temporary.local:6053
[13:33:33][C][api:142]:   Using noise encryption: YES
[13:33:33][C][wifi_info:009]: WifiInfo IPAddress 'Swimming Pool Pump Temporary IP Address'
[13:33:33][V][wifi_info:009]:   Unique ID: 'e465b876e55c-wifiinfo-ip'
[13:33:33][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=8054 (now=9069)
[13:33:33][V][modbus:042]: Modbus received Byte  170 (0Xaa)
[13:33:33][V][modbus:042]: Modbus received Byte  195 (0Xc3)
[13:33:33][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:33][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:33][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:33][W][modbus:108]: Modbus CRC Check failed! 1001!=00
[13:33:33][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:33][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:33][V][modbus:042]: Modbus received Byte  252 (0Xfc)
[13:33:33][C][wifi_info:011]: WifiInfo SSID 'Swimming Pool Pump Temporary WiFi'
[13:33:33][V][wifi_info:011]:   Unique ID: 'e465b876e55c-wifiinfo-ssid'
[13:33:33][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=8093 (now=9145)
[13:33:33][C][wifi_info:012]: WifiInfo BSSID 'Swimming Pool Pump Temporary MAC'
[13:33:33][V][wifi_info:012]:   Unique ID: 'e465b876e55c-wifiinfo-bssid'
[13:33:33][C][wifi_signal.sensor:009]: WiFi Signal 'Swimming Pool Pump Temporary WiFi Signal'
[13:33:33][C][wifi_signal.sensor:009]:   Device Class: 'signal_strength'
[13:33:33][C][wifi_signal.sensor:009]:   State Class: 'measurement'
[13:33:33][C][wifi_signal.sensor:009]:   Unit of Measurement: 'dBm'
[13:33:33][C][wifi_signal.sensor:009]:   Accuracy Decimals: 0
[13:33:33][V][wifi_signal.sensor:009]:   Unique ID: 'e465b876e55c-wifisignal'
[13:33:33][D][uart_debug:114]: <<< AA:C3:00:00:00:00:00:FC
[13:33:33][C][modbus_controller:298]: ModbusController:
[13:33:33][C][modbus_controller:299]:   Address: 0xAA
[13:33:33][C][modbus_controller:301]: sensormap
[13:33:34][C][modbus_controller:305]:  Sensor type=0 start=0x19C6 offset=0x0 count=1 size=9
[13:33:34][C][modbus_controller:307]: ranges
[13:33:34][C][modbus_controller:310]:   Range type=0 start=0x19C6 count=1 skip_updates=0
[13:33:34][V][modbus_controller:047]: Sending next modbus command to device 170 register 0x19C6 count 1
[13:33:34][VV][uart.arduino_esp32:180]:     Flushing...
[13:33:34][V][modbus:220]: Modbus write raw: AA.C3.07.D1.00.00 (6)
[13:33:34][V][modbus_controller:509]: Command sent 0 0x19C6 1
[13:33:34][W][component:214]: Component modbus_controller took a long time for an operation (0.08 s).
[13:33:34][W][component:215]: Components should block for at most 20-30ms.
[13:33:34][D][uart_debug:114]: >>> AA:C3:07:D1:00:00:0D:4D
[13:33:34][V][modbus:042]: Modbus received Byte  170 (0Xaa)
[13:33:34][V][modbus:042]: Modbus received Byte  195 (0Xc3)
[13:33:34][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:34][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:34][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:34][W][modbus:108]: Modbus CRC Check failed! 1001!=00
[13:33:34][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:34][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:34][V][modbus:042]: Modbus received Byte  254 (0Xfe)
[13:33:34][D][uart_debug:114]: <<< AA:C3:00:00:00:00:00:FE
[13:33:34][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=8847 (now=9848)
[13:33:34][V][modbus_controller:047]: Sending next modbus command to device 170 register 0x19C6 count 1
[13:33:34][VV][uart.arduino_esp32:180]:     Flushing...
[13:33:34][V][modbus:220]: Modbus write raw: AA.C3.07.D1.00.00 (6)
[13:33:34][V][modbus_controller:509]: Command sent 0 0x19C6 1
[13:33:34][W][component:214]: Component modbus_controller took a long time for an operation (0.08 s).
[13:33:34][W][component:215]: Components should block for at most 20-30ms.
[13:33:34][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=9054 (now=10144)
[13:33:34][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=9093 (now=10144)
[13:33:34][D][uart_debug:114]: >>> AA:C3:07:D1:00:00:0D:4D
[13:33:34][V][modbus:042]: Modbus received Byte  170 (0Xaa)
[13:33:34][V][modbus:042]: Modbus received Byte  195 (0Xc3)
[13:33:34][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:34][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:34][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:35][W][modbus:108]: Modbus CRC Check failed! 1001!=00
[13:33:35][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:35][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:35][V][modbus:042]: Modbus received Byte  252 (0Xfc)
[13:33:35][D][uart_debug:114]: <<< AA:C3:00:00:00:00:00:FC
[13:33:35][W][modbus_controller:030]: Modbus device=170 set offline
[13:33:35][D][modbus_controller:043]: Modbus command to device=170 register=0x19C6 countdown=0 no response received - removed from send queue
[13:33:35][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=9847 (now=10848)
[13:33:35][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=10054 (now=11055)
[13:33:35][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=10093 (now=11094)
[13:33:36][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=10847 (now=11855)
[13:33:36][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=11054 (now=12058)
[13:33:36][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=11093 (now=12094)
[13:33:37][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=11847 (now=12847)
[13:33:37][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=12054 (now=13055)
[13:33:37][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=12093 (now=13094)
[13:33:38][VV][scheduler:226]: Running interval 'update' with interval=10000 last_execution=3361 (now=13364)
[13:33:38][V][modbus_controller:181]: Updating modbus component
[13:33:38][VV][modbus_controller:185]: Updating range 0x19C6
[13:33:38][V][modbus_controller:148]: Range : 19C6 Size: 1 (0) skip: 0
[13:33:38][V][modbus_controller:047]: Sending next modbus command to device 170 register 0x19C6 count 1
[13:33:38][VV][uart.arduino_esp32:180]:     Flushing...
[13:33:38][V][modbus:220]: Modbus write raw: AA.C3.07.D1.00.00 (6)
[13:33:38][V][modbus_controller:509]: Command sent 0 0x19C6 1
[13:33:38][W][component:214]: Component modbus_controller took a long time for an operation (0.09 s).
[13:33:38][W][component:215]: Components should block for at most 20-30ms.
[13:33:38][D][uart_debug:114]: >>> AA:C3:07:D1:00:00:0D:4D
[13:33:38][V][modbus:042]: Modbus received Byte  170 (0Xaa)
[13:33:38][V][modbus:042]: Modbus received Byte  195 (0Xc3)
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][W][modbus:108]: Modbus CRC Check failed! 1001!=00
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][V][modbus:042]: Modbus received Byte  252 (0Xfc)
[13:33:38][D][uart_debug:114]: <<< AA:C3:00:00:00:00:00:FC
[13:33:38][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=12847 (now=13854)
[13:33:38][V][modbus_controller:047]: Sending next modbus command to device 170 register 0x19C6 count 1
[13:33:38][VV][uart.arduino_esp32:180]:     Flushing...
[13:33:38][V][modbus:220]: Modbus write raw: AA.C3.07.D1.00.00 (6)
[13:33:38][V][modbus_controller:509]: Command sent 0 0x19C6 1
[13:33:38][W][component:214]: Component modbus_controller took a long time for an operation (0.08 s).
[13:33:38][W][component:215]: Components should block for at most 20-30ms.
[13:33:38][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=13054 (now=14099)
[13:33:38][VV][scheduler:226]: Running interval 'update' with interval=1000 last_execution=13093 (now=14099)
[13:33:38][D][uart_debug:114]: >>> AA:C3:07:D1:00:00:0D:4D
[13:33:38][V][modbus:042]: Modbus received Byte  170 (0Xaa)
[13:33:38][V][modbus:042]: Modbus received Byte  195 (0Xc3)
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][W][modbus:108]: Modbus CRC Check failed! 1001!=00
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][V][modbus:042]: Modbus received Byte  0 (0X0)
[13:33:38][V][modbus:042]: Modbus received Byte  252 (0Xfc)
[13:33:39][D][uart_debug:114]: <<< AA:C3:00:00:00:00:00:FC
[13:33:39][V][modbus_controller:047]: Sending next modbus command to device 170 register 0x19C6 count 1
[13:33:39][VV][uart.arduino_esp32:180]:     Flushing...

Setting “disable_crc: TRUE” is not help here.

Any help on how to help resolve this would be greatly appreciated.

NB also tried the the MAX485 RS485 converter (with an actual flow control pin and this also yields the same behviour exactly.)

Here is my YAML:

esphome:
  name: swimming-pool-pump-temporary

substitutions:
  hostname: 'Swimming Pool Pump Temporary'
  sensor_prefix: "Swimming Pool Pump"

esp32:
  board: esp32dev
  framework:
    type: arduino

wifi:
  power_save_mode: none
  ssid: !secret WIFI_SID
  password: !secret WIFI_PSWD

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: Swimpool Temp Htspt
    password: !secret ESPHOME_PSWD

captive_portal:

# Enable logging
logger:
  #level: INFO
  #level: DEBUG
  level: VERY_VERBOSE
  hardware_uart: UART0

# Enable Home Assistant API
api:
  encryption:
    key: !secret ESPHOME_KEY 
#  password: !secret ESPHOME_PSWD

ota:
  password: !secret ESPHOME_PSWD

time:
  - platform: homeassistant
    id: homeassistant_time

# Set up UART for the TTL485 controller
uart:
  tx_pin: GPIO17
  rx_pin: GPIO16
  baud_rate: 1200
  stop_bits: 1
  data_bits: 8
  parity: NONE
  id: modbus_uart
  debug:
    after:
      delimiter: "\n"

modbus:
  flow_control_pin: GPIO5
  id: modbusMaster
  send_wait_time: 500ms
  uart_id: modbus_uart
  disable_crc: false

modbus_controller:
- id: modbusDevice
  address: 0xAA  # Modbus slave address (AAH in hexadecimal)
  command_throttle: 500ms  # Minimum time between requests to the device
  setup_priority: -10
  update_interval: 10s  # Interval for checking sensors (adjust as needed)
  modbus_id: modbusMaster

# Text sensors with general information
text_sensor:
  - platform: version
    name: $hostname ESPHome Version
  - platform: wifi_info
    ip_address:
      name: $hostname IP Address
    ssid:
      name: $hostname WiFi
    bssid:
      name: $hostname MAC

sensor:
  # Uptime sensor
  - platform: uptime
    name: $hostname Uptime
    update_interval: 600s
  # WiFi Signal sensor
  - platform: wifi_signal
    name: $hostname WiFi Signal
    update_interval: 60s

  - platform: modbus_controller
    modbus_controller_id: modbusDevice
    name: "Test Modbus"
    id: test_modbus
    custom_command: [ 0xAA, 0xC3, 0x07, 0xD1, 0x0, 0x0] #MSB first
    value_type: S_WORD
    register_count: 1
    force_new_range: true
    response_size: 9
    lambda: |-
      ESP_LOGV("Modbus Sensor Lambda","Got new data" );
      union {
        float float_value;
        uint16_t raw;
      } raw_to_float;
      if (data.size() < 4 ) {
        ESP_LOGE("Modbus Sensor Lambda", "invalid data size %d",data.size());
        return NAN;
      }
      raw_to_float.raw =   data[6] << 8 | data[7];
      ESP_LOGV("Modbus Sensor Lambda", "FP32 = 0x%08X => %f", raw_to_float.raw, raw_to_float.float_value);
      return raw_to_float.raw;

binary_sensor:
  - platform: status
    name: $hostname Status

web_server:
  port: 80
1 Like

Great project!
Wonder if you’ve got any further on this?
I’m in the planning phase and am currently building the pool machine-room. Today I spent a few hours looking at different scenarios ant think I’ll go with the iSaver inverter and connect RS485 modbus via USB, ESPHome or Ethernet. Only got started so haven’t learned anything on the programming bit yet. Only done a few projects with Modbus communication in Node-Red but hopefully I’ll create a setup with the pump inverter soon.

… a few minutes later. I think that I will go with the Ethernet solution as I will have a POE hub in the machine room for the Pool.
I will pick a unit with a built in TCP IP Gateway Server communicating directly over the internal network with Node-red and/or HA. Both the regular and PoE units are on Amazon for under £50.

Waveshare RS485 to Ehternet

Found a guy who made YouTube video on the Waveshare gateway.

So now dive into understanding the RS485 Modbus addressing and function codes. Looks like its RTU… oh found your update on the protocol.

Will follow your thread and will be back when i have the hardware and can get started.

Keep up the good work and keep us in the loop.
Cheers
Per

Nice Project. Also interested in your updates :slight_smile:

I’ve managed some basic communication with the iSaver through rs485. Unfortunately the modbus protocol used by the unit is very bespoke so the esphome modbus module wont work with the isaver.

Unfortunately it is way beyond my programming skills to work out how to program this properly into esphome.

I did find an incorrect part of the protocol the manufacturer sent me. The return message only ever supplies 1byte for the crc checksum. So all responses will only ever be 8byte responses total not the 9byte expected in the instructions.

Really need to find someone with much better programming skills to sort this out for esphome.

For the moment I am using the relay connections on the board that give high, med and low speed controlled through a sonoff 4ch pro flashed with esphome.

The other thing I learned was that to control the rpm and on/off theough modbus you need to go through this order:
1- turn on the isaver through the control panel.
2- turn off the isaver through rs485

If the panel is off from the control panel (or turned off/on through the relay switches) the rs485 control won’t do anything. To put it into rs485 priority mode you need to have turned the unit on by the front panel first and then start the rs485 control

Do you know, if the iSaver does have a 120 Ohm resistor over A and B?

I did find an incorrect part of the protocol the manufacturer sent me.

Which Part do you mean?

I am not sure about the 120ohm resistor but I tried with and without the resistor and it did not make any difference to the behaviour of the unit. It works both with and without the resistor.
I’ll post the updated isaver protocol document here tomorrow. But the only change in it is just that the response CRC code is 1 byte instead of 2 bytes indicated in the previous doc I posted.

Which production date do you have? I have a 2020 model. Aquagem said, that this models does not support rs458. But I got also the same Information on the bus as you (also with the CRC failure). Maybe this is our problem?

Where do you find the production date?
Can you post your logs? Can you see the raw modbus response? If it is total 8bytes then that is the correct expected response which will have a CRC failure

I think you have a lot of misunderstandings here.
First of all, that datasheet is total garbage, I don’t see one single line correct.
For example “Function code: 0xC3 (user grade)”
Modbus doesn’t have that kind of function code… Should be 0x03.

Secondly, you are suspecting that crc error is coming from 9bytes responses.
I don’t think so. It’s coming from bad wiring or wrong parameters.
If you send 8 bytes request starting with slave adress and function code, for example
0x01, 0x03
the response has to begin with those same bytes independently if your response or crc code is correct or not. (or with an exception response)

[19:39:38][V][modbus:199]: Modbus write: 01.03.00.00.00.01.84.0A (8)
[19:39:38][V][modbus_controller:509]: Command sent 3 0x0 1
[19:39:38][V][modbus:042]: Modbus received Byte  1 (0X1)
[19:39:38][V][modbus:042]: Modbus received Byte  3 (0X3)

That response should be total of 7 bytes.
If you receive random value bytes and/or crc errors, control your wiring, baud rate, flow control settings etc.