You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Pymodbus调用read_input_registers触发TypeError(参数过多)及版本、环境适配问题求助

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

现在有两个疑问:

  1. 这还是Pymodbus版本冲突导致的问题吗?
  2. "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

火山引擎 最新活动