Search code examples
pythondictionarydebuggingmodbus

Python Modbus TCP read input_registers 0x4 get error with MBAP headers


Hi I have developed this code, using pymodbus 3.4.1 libs and pymodbustcp 0.2.0 libs to check who works better.

Python is the standard of Debian 11 and is versione 3.9.2

I activated the debug for both libs:

from pyModbusTCP.client import ModbusClient
c = ModbusClient(host="192.168.1.134", port=1024, unit_id=10, debug=True)

c.open()

if c.is_open == False:
    print('not connected')
else:
    print('connected')

print(c.unit_id)

c.read_input_registers(1,1)

c.close()

from pymodbus.client import ModbusTcpClient
from pymodbus.transaction import ModbusSocketFramer as ModbusFramer


import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

ip = "192.168.1.134"
port_num = 1024
unit_num = 10


client = ModbusTcpClient(ip, port=port_num, framer=ModbusFramer)
client.connect()
rr = client.read_input_registers(1,1, unit=unit_num)
print(rr)

The output of the two libs are that:

connected
10
Tx
[DD 02 00 00 00 06 0A] 04 00 01 00 01
Rx
[57 65 6C 63 6F 6D 65]
MBAP checking error


DEBUG:pymodbus.logging:Connection to Modbus server established. Socket ('192.168.1.125', 46270)
DEBUG:pymodbus.logging:Current transaction state - IDLE
DEBUG:pymodbus.logging:Running transaction 1
DEBUG:pymodbus.logging:SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x0 0x4 0x0 0x1 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 28531 bytes Received 19 bytes !!!!
DEBUG:pymodbus.logging:Changing transaction state from "WAITING FOR REPLY" to "PROCESSING REPLY"
DEBUG:pymodbus.logging:RECV: 0x57 0x65 0x6c 0x63 0x6f 0x6d 0x65 0x20 0x74 0x6f 0x20 0x54 0x63 0x70 0x53 0x72 0x76 0xd 0xa
DEBUG:pymodbus.logging:Processing: 0x57 0x65 0x6c 0x63 0x6f 0x6d 0x65 0x20 0x74 0x6f 0x20 0x54 0x63 0x70 0x53 0x72 0x76 0xd 0xa
DEBUG:pymodbus.logging:Frame check failed, ignoring!!
DEBUG:pymodbus.logging:Resetting frame - Current Frame in buffer - 0x57 0x65 0x6c 0x63 0x6f 0x6d 0x65 0x20 0x74 0x6f 0x20 0x54 0x63 0x70 0x53 0x72 0x76 0xd 0xa
DEBUG:pymodbus.logging:Getting transaction 1
DEBUG:pymodbus.logging:Changing transaction state from "PROCESSING REPLY" to "TRANSACTION_COMPLETE"
Modbus Error: [Input/Output] No Response received from the remote slave/Unable to decode response

Does someone have face off the same error with some software modbus server from some machine producers? All suggestions are welcome :)

Edit:

Hi! I try a session with mbpoll as u suggest and this is what I got:

mbpoll 192.168.1.134 -a 10 -p 1024 -t 3 -r 1
mbpoll 1.5-2 - ModBus(R) Master Simulator
Copyright (c) 2015-2023 Pascal JEAN, https://github.com/epsilonrt/mbpoll
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'mbpoll -w' for details.

Protocol configuration: ModBus TCP
Slave configuration...: address = [10]
                        start reference = 1, count = 1
Communication.........: 192.168.1.134, port 1024, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, input register table

-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
-- Polling slave 10... Ctrl-C to stop)
Read input register failed: Invalid data
^C--- 192.168.1.134 poll statistics ---
12 frames transmitted, 0 received, 12 errors, 100.0% frame loss

everything was closed.
Have a nice day !

with modpoll (with tcp and try rtu encapsulated in tcp):

./modpoll -m enc -a 10 -p 1024 -t 3 -r 1 192.168.1.134
modpoll 3.10 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright (c) 2002-2021 proconX Pty Ltd
Visit https://www.modbusdriver.com for Modbus libraries and tools.

Protocol configuration: Encapsulated RTU over TCP, FC4
Slave configuration...: address = 10, start reference = 1, count = 1
Communication.........: 192.168.1.134, port 1024, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, input register table

-- Polling slave... (Ctrl-C to stop)
Checksum error!
-- Polling slave... (Ctrl-C to stop)
Reply time-out!
-- Polling slave... (Ctrl-C to stop)
Checksum error!
^C

./modpoll -m tcp -a 10 -p 1024 -t 3 -r 1 192.168.1.134
modpoll 3.10 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright (c) 2002-2021 proconX Pty Ltd
Visit https://www.modbusdriver.com for Modbus libraries and tools.

Protocol configuration: MODBUS/TCP, FC4
Slave configuration...: address = 10, start reference = 1, count = 1
Communication.........: 192.168.1.134, port 1024, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, input register table

-- Polling slave... (Ctrl-C to stop)
Invalid MPAB identifier!
-- Polling slave... (Ctrl-C to stop)
Reply time-out!
-- Polling slave... (Ctrl-C to stop)
Invalid MPAB identifier!
-- Polling slave... (Ctrl-C to stop)
Reply time-out!
^C

This is the simple code of the nodes program that I try and works:

// create an empty modbus client
const ModbusRTU = require("modbus-serial");
const client = new ModbusRTU();

// open connection to a tcp line
client.connectTCP("192.168.1.134", { port: 1024 });
client.setID(10);

// read the values of 10 registers starting at address 0
// on device number 1. and log the values to the console.
setInterval(function() {
    client.readInputRegisters(0, 10, function(err, data) {
        console.log(data.data);
    });
}, 1000);

and this is the result:

node modbus.js
[
  3, 53, 2, 0, 0,
  0,  0, 0, 0, 0
]
[
  3, 53, 2, 0, 0,
  0,  0, 0, 0, 0
]
[
  3, 53, 2, 0, 0,
  0,  0, 0, 0, 0
]
[
  3, 53, 2, 0, 0,
  0,  0, 0, 0, 0
]
[
  3, 53, 2, 0, 0,
  0,  0, 0, 0, 0
]
[
  3, 53, 2, 0, 0,
  0,  0, 0, 0, 0
]
^C

Probably the nodes lib don't make some checks on the server and get the data rightly but probably is out of modbus standard standard.


Solution

  • If we take the response you received:

    0x57 0x65 0x6c 0x63 0x6f 0x6d 0x65 0x20 0x74 0x6f 0x20 0x54 0x63 0x70 0x53 0x72 0x76 0xd 0xa

    And render it as ASCII we get:

    Welcome to TcpSrv

    So it appears that whatever is listening on port 1024 at 192.168.1.134 is not a Modbus TCP server. As you don't provide any info on the server it's difficult to say more (but Modbus TCP generally runs on port 502 so it's possible you are using the wrong port).

    Update based on info added to the question

    So your tests with mbpoll and modpoll confirm that there is something non-standard about the server. However your node code appears to confirm that it is, in fact, a Modbus-TCP server. The difference is probably something in the implementation of modbus-serial so lets look at that.

    modbus-serial implements ModbusTCP in an interesting way - the TCP functions basically accept/return ModbusRTU data and convert to/from TCP PDU's (for example here it adds the CRC to received Modbus TCP packets). The way this code works to to receive a TCP packet and split it up into Modbus TCP responses (there is actually a bug in that it should not assume that the response will be in one TCP packet) then pass those on as Modbus-RTU packets for processing.

    Anyway the impact of the above, in your situation, is that the following happens:

    • You connect
    • The server sends "Welcome to TcpSrv"
    • The Client processes the packet (emitting a rubbish packet which is ignored)
    • The request is sent and the response processed

    In summary modbus-serial is tolerant of errors in the received data whereas other clients are not.

    Anyway this appears to confirm my initial thoughts; upon connection 192.168.1.134:1024 transmits Welcome to TcpSrv and then acts as a ModbusTCP server.

    One possible solution to this would be to open the connection yourself, read in the initial packet (or anything received in a second) and then pass the connection to the library (but I'm not sure if any python library supports this). Another option would be to start with a dummy transaction but, unfortunately, I suspect the libraries will drop the connection when the invalid response is received.