无法连接Modbus RTU over TCP:modpoll正常但pymodbus失败求排查
Let's break down what's going on here—your modpoll command works perfectly, so the device is reachable and responding correctly. The problem almost certainly lies in mismatched configuration between your modpoll call and your pymodbus code. Let's go through the critical details step by step:
1. You're Using the Wrong Framer for RTU over TCP
Modbus RTU over TCP (encapsulated RTU) is different from standard Modbus TCP. Your modpoll uses -m enc to enable this mode, but pymodbus defaults to standard Modbus TCP framing. You need to explicitly use the RTU framer when creating your client.
For pymodbus v3.x:
from pymodbus.client import ModbusTcpClient from pymodbus.transaction import ModbusRtuFramer # Initialize client with RTU framer client = ModbusTcpClient( host="192.168.1.1", port=4660, framer=ModbusRtuFramer, timeout=5 # Match modpoll's timeout (adjust if needed) ) # Check connection status if client.connect(): print("Connected to device successfully") else: print("Failed to connect—verify IP/port and device status")
For pymodbus v2.x:
from pymodbus.client import ModbusClient from pymodbus.transaction import ModbusRtuFramer client = ModbusClient( method="tcp", host="192.168.1.1", port=4660, framer=ModbusRtuFramer, timeout=5 ) client.connect()
2. Register Address Mismatch (1-Based vs 0-Based)
This is the most common pitfall! Modpoll uses 1-based register addressing, but pymodbus uses 0-based addressing by default. Your modpoll command uses -r60 (starting at register 60), so in pymodbus you need to subtract 1 to get the correct 0-based address: 59.
Additionally, since you're reading a float (-t4:float), which occupies 2 consecutive 16-bit registers, you need to set count=2 in your read call.
3. Correct Register Type & Slave ID
Your modpoll specifies:
-t4: Input registers (Modbus function code 04)-a3: Slave ID (device address) 3
Make sure your pymodbus read call matches these:
# Read 2 input registers starting at 0-based address 59 (modpoll's 60) response = client.read_input_registers( address=59, count=2, slave=3 # Critical: match the -a3 parameter from modpoll ) # Check for errors if response.isError(): print(f"Modbus Error: {response}") else: # Decode the 2 registers into a float from pymodbus.payload import BinaryPayloadDecoder from pymodbus.constants import Endian decoder = BinaryPayloadDecoder.fromRegisters( response.registers, byteorder=Endian.Big, # Adjust based on your device's byte order wordorder=Endian.Big ) float_value = decoder.decode_32bit_float() print(f"Read float value: {float_value}")
4. Verify Byte Order
Modpoll's -t4:float uses a default byte/word order that might match your device, but if the decoded float is garbage, you may need to adjust the byteorder and wordorder in the decoder. Common alternatives are Endian.Little for either parameter—test both combinations if needed.
5. Clean Up the Connection
Don't forget to close the client when you're done to avoid hanging connections:
client.close()
Putting all this together should align your pymodbus code with the working modpoll configuration, and resolve your connection/response issues.
内容的提问来源于stack exchange,提问作者Gordio

