pymodbus-dev/pymodbus

Unable to decode response Modbus Error

k-sartor opened this issue · 10 comments

  • Python: 3.10.5 or 3.6.8
  • OS: Windows or Centos
  • Pymodbus: 3.7.2
  • Modbus Hardware (if used): GW-7838-M CR

Pymodbus Specific

  • Client: tcp- sync

Description

When i try to read register by this simple code it does not work while it seems some data missing.
However another software (ModBus Doctor) can read the register and retreive the correct data

Code and Logs

# code and logs here.

# please use the following to format logs when posting them here
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient('10.15.xx.xx')   # Create client object
client.connect()                           # connect to device, reconnect automatically
response = client.read_holding_registers(10,2,slave=1)
client.close()                             # Disconnect device```

#LOGS
2024-08-29 20:58:01,013 DEBUG logging:103 Connection to Modbus server established. Socket ('10.27.254.82', 64136)
2024-08-29 20:58:01,014 DEBUG logging:103 Current transaction state - IDLE
2024-08-29 20:58:01,015 DEBUG logging:103 Running transaction 1
2024-08-29 20:58:01,016 DEBUG logging:103 SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x0 0xa 0x0 0x2
2024-08-29 20:58:01,016 DEBUG logging:103 New Transaction state "SENDING"
2024-08-29 20:58:01,017 DEBUG logging:103 Changing transaction state from "SENDING" to "WAITING FOR REPLY"
2024-08-29 20:58:01,035 DEBUG logging:103 Changing transaction state from "WAITING FOR REPLY" to "PROCESSING REPLY"
2024-08-29 20:58:01,036 DEBUG logging:103 RECV: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x4 0x0 0x1 0xbe
2024-08-29 20:58:01,037 DEBUG logging:103 Processing: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x4 0x0 0x1 0xbe
2024-08-29 20:58:01,038 DEBUG logging:103 Factory Response[ReadHoldingRegistersResponse': 3]
2024-08-29 20:58:01,038 ERROR logging:115 Unable to decode response Modbus Error: [Input/Output] Invalid response b'\x04\x00\x01\xbe' has byte count of 4
2024-08-29 20:58:01,039 DEBUG logging:103 Resetting frame - Current Frame in buffer - 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x4 0x0 0x1 0xbe
2024-08-29 20:58:01,040 ERROR logging:115 Modbus IO exception Modbus Error: [Input/Output] Unable to decode request
Modbus Error: [Input/Output] Unable to decode request

You request 2 registers == 4 bytes, however your device responds with 3 bytes.

0x1 0x3 0x4 0x0 0x1 0xbe

Which is slave = 0x01
function code = 0x3
byte count = 0x4

which is all ok, but there are only 3 bytes of data.

It is however a bit strange that pymodbus does not try a second read, I will investigate that,

Just controlled the pymodbus code, and your device is sending a valid packet, but with a length that causes the modbus message to be 1 byte short.

0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x4 0x0 0x1 0xbe

Byte 6 is the length (Number of following bytes) it is 0x6, and as you can see there are 6 bytes following but it should be 7.

Closing as this is not a pymodbus problem.

Thank you
It is strange while others programs (Modbus Doctor f.e.) can read the holding registers without any issues.
Is there any capability to say pymodbus to wait another bit?

It will wait automatically. But according to the length field it has received all data.

I have no idea what other programs do, they might disregard the length field and wait for another byte (if your device sends that) or they might assume the last byte is zero (which is a very false assumption).

You can always try and patch framers/old_framer_socket.py by adding 1 to the length and see if your device simply calculates the length wrongly.

Just controlled the pymodbus code, and your device is sending a valid packet, but with a length that causes the modbus message to be 1 byte short.

0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x4 0x0 0x1 0xbe

Byte 6 is the length (Number of following bytes) it is 0x6, and as you can see there are 6 bytes following but it should be 7.

Is it not the 4 for 4 bytes according to https://www.fernhillsoftware.com/help/drivers/modbus/modbus-protocol.html#readHoldingRegs and therefore it lack one bit?

Here is another behaviour similar when i asked only 1 holding register
DEBUG:pymodbus.logging:Connection to Modbus server established. Socket ('10.27.254.242', 63681) DEBUG:pymodbus.logging:Current transaction state - IDLE DEBUG:pymodbus.logging:Running transaction 1 DEBUG:pymodbus.logging:SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x0 0x2 0x0 0x1 DEBUG:pymodbus.logging:New Transaction state "SENDING" DEBUG:pymodbus.logging:Changing transaction state from "SENDING" to "WAITING FOR REPLY" DEBUG:pymodbus.logging:Incomplete message received, Expected 12 bytes Received 11 bytes !!!! DEBUG:pymodbus.logging:Changing transaction state from "WAITING FOR REPLY" to "PROCESSING REPLY" DEBUG:pymodbus.logging:RECV: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x2 0x39 0x2 DEBUG:pymodbus.logging:Processing: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 **0x2** 0x39 0x2 DEBUG:pymodbus.logging:Short frame: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x2 0x39 0x2 wait for more data DEBUG:pymodbus.logging:Getting transaction 1 DEBUG:pymodbus.logging:Changing transaction state from "PROCESSING REPLY" to "TRANSACTION_COMPLETE"

Here is the number is two (in bold) and i have two bytes 0x39 0x2 that are correct. So why do i have an error 'short frame'
=> i can't get bitsin the result and can't use them (but this time it would be), no?

The 4 is the number of data in the modbus message, which is also 1 short (there are only 3 data bytes, in the first example)

When running on sockets, you have a transmission header called MBAP which are the first 6 bytes with additional information. Byte 6 of that header is the "number of bytes that follow", so it is the length of the whole modbus message and not just the data part.

your example highlights the problem:

0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x2 0x39 0x2

The header tells that the whole modbus message is 6 bytes, but the device only transmits 5 bytes. In this case the DATA count = 2 is correct, so the MBAP length should have been 5.

This example shows clearly that your device do not manage the MBAP header correctly,

please see the official documentation: https://www.modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf read chapter "3.1.3 MBAP Header description" on page 5, on how the length field is defined...then you will see the documentation you forwarded is not conforming with the modbus standard.

Similar issue here, below code reads the slave ID of the hardware with slave ID = 2. Code works perfect, the output is correct and also I can confirm with cutecom (sent and recieved same with pymodbus).

import pymodbus
from pymodbus.client import ModbusSerialClient

pymodbus.pymodbus_apply_logging_config("DEBUG")

client = ModbusSerialClient(
    framer=pymodbus.FramerType.RTU,
    port='/dev/ttyUSB0',
    baudrate=9600,
    parity='N',
    stopbits=1,
    bytesize=8,
    timeout=1
)
client.connect()
result = client.read_holding_registers(address=0x4000, slave=2) # according to data sheet reading slave ID for slave = 2.
print(result)
client.close()
#LOGS
2024-09-03 17:10:30,975 DEBUG logging:103 Current transaction state - IDLE
2024-09-03 17:10:30,975 DEBUG logging:103 Running transaction 1
2024-09-03 17:10:30,975 DEBUG logging:103 SEND: 0x2 0x3 0x40 0x0 0x0 0x1 0x91 0xf9
2024-09-03 17:10:30,975 DEBUG logging:103 Resetting frame - Current Frame in buffer - 
2024-09-03 17:10:30,975 DEBUG logging:103 New Transaction state "SENDING"
2024-09-03 17:10:30,975 DEBUG logging:103 Changing transaction state from "SENDING" to "WAITING FOR REPLY"
2024-09-03 17:10:31,001 DEBUG logging:103 Changing transaction state from "WAITING FOR REPLY" to "PROCESSING REPLY"
2024-09-03 17:10:31,001 DEBUG logging:103 RECV: 0x2 0x3 0x2 0x0 0x2 0x7d 0x85
2024-09-03 17:10:31,001 DEBUG logging:103 Processing: 0x2 0x3 0x2 0x0 0x2 0x7d 0x85
2024-09-03 17:10:31,001 DEBUG logging:103 Getting Frame - 0x3 0x2 0x0 0x2
2024-09-03 17:10:31,001 DEBUG logging:103 Factory Response[ReadHoldingRegistersResponse': 3]
2024-09-03 17:10:31,001 DEBUG logging:103 Frame advanced, resetting header!!
2024-09-03 17:10:31,002 DEBUG logging:103 Adding transaction 0
2024-09-03 17:10:31,002 DEBUG logging:103 Getting transaction 0
2024-09-03 17:10:31,002 DEBUG logging:103 Changing transaction state from "PROCESSING REPLY" to "TRANSACTION_COMPLETE"
ReadHoldingRegistersResponse (1)

Screenshot from 2024-09-03 16-52-24

HOWEVER, If I change slave = 2 to slave = 0 (which is not supposed to be a problem according to datasheet of used hardware) I recieve no data, I can recieve same data with prev one if I sent same hexes as pymodbus sent.

import pymodbus
from pymodbus.client import ModbusSerialClient

pymodbus.pymodbus_apply_logging_config("DEBUG")

client = ModbusSerialClient(
    framer=pymodbus.FramerType.RTU,
    port='/dev/ttyUSB0',
    baudrate=9600,
    parity='N',
    stopbits=1,
    bytesize=8,
    timeout=1
)
client.connect()
result = client.read_holding_registers(address=0x4000, slave=0) # according to data sheet reading slave ID for slave = 2.
print(result)
client.close()
#LOGS
2024-09-03 17:16:53,964 DEBUG logging:103 Current transaction state - IDLE
2024-09-03 17:16:53,964 DEBUG logging:103 Running transaction 1
2024-09-03 17:16:53,964 DEBUG logging:103 SEND: 0x0 0x3 0x40 0x0 0x0 0x1 0x90 0x1b
2024-09-03 17:16:53,964 DEBUG logging:103 Resetting frame - Current Frame in buffer - 
2024-09-03 17:16:53,964 DEBUG logging:103 New Transaction state "SENDING"
2024-09-03 17:16:53,964 DEBUG logging:103 Changing transaction state from "SENDING" to "TRANSACTION_COMPLETE"
2024-09-03 17:16:53,964 DEBUG logging:103 Processing: 
2024-09-03 17:16:53,964 DEBUG logging:103 Getting transaction 0
2024-09-03 17:16:53,970 DEBUG logging:103 Changing transaction state from "PROCESSING REPLY" to "TRANSACTION_COMPLETE"
Modbus Error: [Input/Output] No Response received from the remote slave/Unable to decode response

Screenshot from 2024-09-03 16-51-09

I encountered this issue when I have used pymodbus 3.7.2. But with 3.6.9 everything works perfect. Also I can write registers with slave ID = 0 as well as slave ID = 2 (this also confirms slaveID = 0 works for any slave ID).

Slave = 0 is pr modbus definition broadcast, and no response is expected with the standard API calls (mainly because there will be n responses, and we cannot know which one you want).

On dev, we have changed it slightly, so that if there are only one response it will be delivered back.