Make a server 'timeout' instead of an replying an exception code #2848
-
|
I am writing a pymodbus 3.11.4 server to emulate the Modbus-TCP connection of a Marstek Venus 3 battery. In my pymodbus client, the behavior of is different when a illegal register is requested with
Returning a exception code is obviously a better behavior but since I want to emulate the behavior of the real battery, I wonder if it is possible to write a server that behaves like that. I am also wondering if that behavior could be caused by a bus in the Modbus implementation of the Marstek battery. Here is the debug log obtained when sending a single illegal The '0x0 0x4' is those Short frame responses looks suspicious to me. According to https://ipc2u.com/articles/knowledge-base/detailed-description-of-the-modbus-tcp-protocol-with-command-examples/ those 2 bytes should contains the size of the remaining data and so it should be '0x0 0x3' as shown in the table 'Sample request and response with error: ' on the same page. My own pymodbus server response for the same request is |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
|
You are correct the battery returns a wrong length (0x04) ! and yes that causes the framer to look for a non-existing byte, which leads to a retry and finally to a raised exception. As you can see your device do NOT send a modbus exception, and thus there is nothing that can be returned to the app. I am pretty sure your emulator returns a modbus exception, which you then receive. Returning an exception code would obviously be wrong, because returned exception codes are real messages coming from the device. Whenever something goes wrong in pymodbus itself an exception is raised ! This is an important distinction. A solution to your problem is to add a trace function that changes the 0x04 to 0x03, that is pretty simple to do, see documentation and examples. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks. That works fine. def marstek_bad_exception_response(sending: bool, data: bytes) -> bytes:
if sending:
if len(data)==9 and data[5]==3 and (data[7]&0x80)==0x80:
return data[0:5] + b'\x04' + data[6:]
return data
StartTcpServer(context, identity=identity, address=("", port), trace_packet=marstek_bad_exception_response )and in my client, I do the opposite operation to remove the timeout. |
Beta Was this translation helpful? Give feedback.
You are correct the battery returns a wrong length (0x04) ! and yes that causes the framer to look for a non-existing byte, which leads to a retry and finally to a raised exception.
As you can see your device do NOT send a modbus exception, and thus there is nothing that can be returned to the app. I am pretty sure your emulator returns a modbus exception, which you then receive.
Returning an exception code would obviously be wrong, because returned exception codes are real messages coming from the device. Whenever something goes wrong in pymodbus itself an exception is raised ! This is an important distinction.
A solution to your problem is to add a trace function that changes the 0x04 t…