Pymodbus调用read_input_registers触发TypeError(参数过多)及版本、环境适配问题求助
大家好,我在尝试用Python通过Modbus-RTU协议和PZEM-004T(v3)交流电力模块通信时,遇到了参数错误、版本适配和环境配置的一系列问题,想请大家帮忙排查一下。
硬件与开发背景
- 开发环境:Python3 + VS Code
- 操作系统:Linux Mint 21.3 (Cinnamon)
- 通信方式:PZEM-004T通过Prolific® PL2303 TTL转USB转换器实现RS-485通信,已通过Windows平台的Docklight®工具确认设备地址为0x01
问题起源
我一开始用了一份GitHub上的PZEM-004T Python代码作为起点,但原代码的初始化部分会报和"preamble"相关的错误。于是我替换了原代码的初始化段,其他部分保持不变。修改后的代码能启动,但运行到读寄存器时触发了TypeError。
问题代码
from pymodbus.client.sync import ModbusSerialClient # configure the serial port client = ModbusSerialClient( method='rtu', port='/dev/ttyUSB0', baudrate=9600, #timeout=3, parity='N', stopbits=1, bytesize=8 ) #device default address is 0x01. However you can change the address by modifying the register that sets the address device_address = 0x01 # connect to the PZEM-004T client.connect() # read the voltage value result = client.read_input_registers(0x0000, 1, device_address) voltage = float(result.registers[0] / 10.0) # read the current value result = client.read_input_registers(0x0001, 2, device_address) current = float(result.registers[0] / 1000.0) # read the power value result = client.read_input_registers(0x0003, 2, device_address) power = float(result.registers[0]) # read energy value result = client.read_input_registers(0x0005, 2, device_address) energy = float(result.registers[0]) # read the frequency value result = client.read_input_registers(0x0007, 1, device_address) frequency = float(result.registers[0] / 10.0) #read the power factor value result = client.read_input_registers(0x0008, 1, device_address) power_factor = float(result.registers[0] / 100.0) # print the values print(f"Voltage: {voltage} V") print(f"Current: {current} A") print(f"Power: {power} W") print(f"Energy: {energy} Wh") print(f"Frequency: {frequency} Hz") print(f"Power Factor: {power_factor} ") # disconnect from the PZEM-004T client.close()
触发的错误信息
Traceback (most recent call last): File "/home/username/Documents/Python_PZEM_Module/another_PZEM_test", line 22, in <module> result = client.read_input_registers(0x0000, 1, 0x01) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: ModbusClientMixin.read_input_registers() takes from 2 to 3 positional arguments but 4 were given
后续排查过程与新问题
2025-02-04 更新:尝试修改初始化代码
根据建议修改了代码的导入和初始化部分:
import asyncio import time from pymodbus import FramerType from pymodbus.client import AsyncModbusSerialClient, ModbusSerialClient # configure the serial port client = ModbusClient.ModbusSerialClient( "/dev/ttyUSB0", framer=FramerType.RTU, baudrate=9600, bytesize=8, parity="N", stopbits=1, )
但运行时触发了导入错误:
username@userplatform:~/Documents/Python_PZEM_Module$ cd /home/username/Documents/Python_PZEM_Module ; /usr/bin/env /bin/python3.11 /home/username/.vscode/extensions/ms-python.debugpy-2024.14.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher 39645 -- /home/username/Documents/Python_PZEM_Module/another_PZEM_test Traceback (most recent call last): File "/home/username/Documents/Python_PZEM_Module/another_PZEM_test", line 3, in <module> from pymodbus import FramerType ImportError: cannot import name 'FramerType' from 'pymodbus' (/usr/lib/python3/dist-packages/pymodbus/__init__.py)
2025-02-05 更新:版本适配问题排查
我用的是Linux Mint 21.3自带的Python3(通过Synaptic包管理器安装的系统版本),发现系统软件源里只有Pymodbus 2.1.0版本:
/var/cache/apt/archives/python3-pymodbus_2.1.0+dfsg-2_all.deb
于是我先通过包管理器卸载了2.1.0版本,再用pip install pymodbus安装了3.8.3版本,但pip把它安装到了用户目录下的路径:/home/myusername/.local/lib/python3.10/site-packages/pymodbus-3.8.3.dist-info,和系统Python的路径不统一。
现在用VS Code运行代码时会触发模块找不到的错误:
ModuleNotFoundError: No module named 'pymodbus'
我尝试修改.bashrc的环境变量但没成功,已经恢复了修改避免更多问题。这里想问一下:是不是应该完全卸载系统的Python,全部用pip重新安装?
2025-02-08 更新:虚拟环境配置后仍有问题
在Mint论坛得到建议后,我弄明白了Python虚拟环境的用法,清理了之前的pip安装痕迹,在虚拟环境里安装了Pymodbus 3.8.3,并且在VS Code里指定了这个虚拟环境。但代码运行时还是触发了同样的TypeError错误:
TypeError: ModbusClientMixin.read_input_registers() takes from 2 to 3 positional arguments but 4 were given
现在有两个疑问:
- 这还是Pymodbus版本冲突导致的问题吗?
- "positional arguments"(位置参数)具体指什么?
2025-02-08 补充:位置参数问题的发现
对比了原GitHub代码和Pymodbus 3.8.3的官方用法,我终于找到了问题的关键点:
- 原GitHub代码(适配旧版Pymodbus)的位置传参写法:
result = client.read_input_registers(0x0000, 1, 0x0001)
- Pymodbus 3.8.3的正确写法必须显式指定关键字参数:
result = client.read_input_registers(0x0000,count=1, slave=1)
也就是必须用count=和slave=来明确参数的含义,不能只用位置传参。
同时,初始化部分的导入语句也要对应修改:
- 原导入语句(适配旧版):
from pymodbus.client.sync import ModbusSerialClient # configure the serial port
- 正确导入语句(适配Pymodbus 3.x):
from pymodbus.client import ModbusSerialClient as ModbusClient
当然,必须在装有Pymodbus 3.x的虚拟环境中运行代码。
现在虽然找到了参数写法的问题,但还是想确认下之前的版本和环境配置的坑有没有完全踩平,也希望能给遇到同样问题的人提个醒。
备注:内容来源于stack exchange,提问作者Birdman




