Python读取Modbus寄存器报错:ModbusIOException无registers属性,求原因
之前正常运行的电能表寄存器读取脚本,今日执行时报错:
AttributeError: 'ModbusIOException' object has no attribute 'registers'
设备可正常ping通,核心代码片段如下:
from pymodbus.client import ModbusTcpClient IP = "192.168.X.X" client = ModbusTcpClient(IP) reg = client.read_holding_registers(23322, 2) calc = round((reg.registers[0] * pow(2, 16) + reg.registers[1]) * 0.01 / 1000, 2) print(calc)
核心原因
ModbusIOException说明Modbus TCP请求未成功完成——虽然设备网络层可达(能ping通),但应用层的Modbus通信出现异常,此时read_holding_registers返回的是异常对象而非正常响应,自然没有registers属性。
可能的问题及解决方法
未建立有效连接:代码仅创建了客户端对象,未显式调用
connect()建立连接,或连接因超时、设备重启断开。
解决:添加连接检查逻辑:client = ModbusTcpClient(IP) if not client.connect(): print("无法连接到Modbus设备") exit(1)寄存器地址错误:寄存器地址23322可能是十进制,但部分设备采用偏移地址规则(比如地址需减1,即23321),或地址超出设备支持范围。
解决:核对电能表的Modbus协议文档,确认寄存器的正确地址(注意区分0偏移/1偏移)。Modbus端口不匹配:默认Modbus TCP端口为502,若设备修改过端口,需在创建客户端时指定:
client = ModbusTcpClient(IP, port=5020) # 替换为设备实际端口设备Modbus服务异常:设备的Modbus TCP服务可能因重启、配置变更或故障停止运行,虽能ping通但服务未响应。
解决:登录设备管理界面,检查Modbus TCP服务是否启用,或重启设备尝试恢复。请求参数违规:单次读取的寄存器数量(2个)超出设备允许范围,或读保持寄存器的功能码(0x03)被设备禁用。
解决:核对协议文档,调整read_holding_registers的第二个参数;确认设备是否允许使用0x03功能码。防火墙/路由拦截:网络防火墙可能拦截了Modbus端口(默认502)的流量,导致请求无法到达设备。
解决:检查设备与脚本运行主机间的防火墙规则,确保对应端口的TCP流量双向通行。
代码优化建议
添加错误检查逻辑,避免直接访问registers导致崩溃:
from pymodbus.client import ModbusTcpClient IP = "192.168.X.X" client = ModbusTcpClient(IP) if not client.connect(): print("无法连接到Modbus设备") exit(1) reg = client.read_holding_registers(23322, 2) if reg.isError(): print(f"Modbus读取错误: {reg}") client.close() exit(1) calc = round((reg.registers[0] * pow(2, 16) + reg.registers[1]) * 0.01 / 1000, 2) print(calc) client.close()
内容的提问来源于stack exchange,提问作者user13592259

