Modbus Oddness

Recently I posted about discovering that our hot water system had a modbus connection available. I spent some time checking the registers and have a small python script that can retrieve and make sense of the data. It was working well using the USB to modbus adapter but that was never intended to be a permanent solution.

Max485

I had a MAX485 module and so with a bit of research I coupled it to an ESP8266, fired up ESPHome and installed some firmware. Having already done the hard work figuring out the registers and having data from a few weeks I sat and waited for data to start appearing in HomeAssistant. And I waited...

After a few minutes it was apparent all was not well so a quick check of the ESPHome logs was in order.

[D][uart_debug:114]: >>> 14:04:00:4F:00:01:02:D8
[D][uart_debug:114]: <<< 00:14:04:02:01:FE:34:E3
[D][modbus_controller:029]: Modbus command to device=20 register=0x4F countdown=0 no response received - removed from send queue

Hmm, so the request is being sent and a response is being received, albeit the response appears to be invalid. In fact in a previous debug log it said the CRC was incorrect, so lets check with an online validator...

    Slave ID:               20 (decimal) |   14 (hexadecimal)
    Function:                4 (decimal) |   04 (hexadecimal)
    Register Offset:        79 (decimal) | 004F (hexadecimal)
    Number Of Registers:     1 (decimal) | 0001 (hexadecimal)

    CRC:                 55298 (decimal) | 02D8 (hexadecimal)
    CRC Should Be:       55298 (decimal) | 02D8 (hexadecimal)

    Request: [14] [04] [004F] [0001] [02D8]
             |    |    |      |      |-> CRC16 (55298)
             |    |    |      |-> Number Of Registers (1)
             |    |    |-> Register Offset (79 = 30080)
             |    |-> Function Code (4)
             |-> Slave ID (20)

Request looks good. What about the response?

    Slave ID:                0 (decimal) |   00 (hexadecimal)
    Function:               20 (decimal) |   14 (hexadecimal)
    Number of Bytes:         4 (decimal) |   04 (hexadecimal)

    CRC:                       (decimal) |   E3 (hexadecimal)
    CRC Should Be:        7160 (decimal) | F81B (hexadecimal)
    One Register Size:    4Byte - 32bit

    Request: [00] [14] [04] [DATA] [E3]
             |    |    |    |      |-> CRC16 ()
             |    |    |    |->  0201FE34
             |    |    |-> Byte Count (4)
             |    |-> Function Code (20)
             |-> Slave ID (0)

    Data: Row Format: Data Type, Signed, Unsigned

        (0) (long32) 889061634  889061634  
             (float) -5.9817861029353E+37

Straight away this looks wrong. The slave should be 0x14 not 0 and the expected response is a 16-bit register not a 32-bit. However, lets try removing the first byte.

    Slave ID:               20 (decimal) |   14 (hexadecimal)
    Function:                4 (decimal) |   04 (hexadecimal)
    Number of Bytes:         2 (decimal) |   02 (hexadecimal)

    CRC:                 58164 (decimal) | 34E3 (hexadecimal)
    CRC Should Be:       58164 (decimal) | 34E3 (hexadecimal)
    One Register Size:    2Byte - 16bit

    Request: [14] [04] [02] [DATA] [34E3]
             |    |    |    |      |-> CRC16 (58164)
             |    |    |    |->  01FE
             |    |    |-> Byte Count (2)
             |    |-> Function Code (4)
             |-> Slave ID (20)

    Data: Row Format: Data Type, Signed, Unsigned

        (0)  (short)      510       510  

Now we have correct data. The value returned is also correct as the 510 is factored to the hot water target temperature of 51.0. But why is there an additional byte?

Wiring?

I have double checked the wiring and given the very short length of cable (less than a metre) I don't imagine there will be much of a noise issue. In fact the fact that the extra byte is ALWAYS present suggests it's not a noise issue.

As a precaution, I have rewired the cable but it made no difference.

Adding a 120ohm terminator hasn't changed anything.

MAX485 vs USB?

As this worked flawlessly with the USB adapater I can only imagine it's related to the setup for the MAX485. The ESPHome configuration is as follows...

uart:
  id: sp1
  tx_pin: GPIO1
  rx_pin: GPIO3
  baud_rate: 19200
  stop_bits: 1
  parity: even
  debug:
    direction: BOTH

modbus:
  flow_control_pin: D4
  id: modbus1

modbus_controller:
  - id: hpw300
    address: 20
    modbus_id: modbus1
    setup_priority: -10

The log entries related to the setup are

[C][uart.arduino_esp8266:102]: UART Bus:
[C][uart.arduino_esp8266:103]:   TX Pin: GPIO1
[C][uart.arduino_esp8266:104]:   RX Pin: GPIO3
[C][uart.arduino_esp8266:106]:   RX Buffer Size: 256
[C][uart.arduino_esp8266:108]:   Baud Rate: 19200 baud
[C][uart.arduino_esp8266:109]:   Data Bits: 8
[C][uart.arduino_esp8266:110]:   Parity: EVEN
[C][uart.arduino_esp8266:111]:   Stop bits: 1
[C][uart.arduino_esp8266:113]:   Using hardware serial interface.
[C][modbus:139]: Modbus:
[C][modbus:140]:   Flow Control Pin: GPIO2
[C][modbus:141]:   Send Wait Time: 250 ms

Does anyone have any suggestions? It's all a bit odd!