环境
- ProtoForge main(protoforge/protocols/modbus/server.py),Python 3.13.5,Windows 11
- 复现版本:pymodbus 3.15.0(损坏);对照:pymodbus 3.12.1(正常)
- pyproject 声明
pymodbus>=3.6.0 无上界,新装环境默认拿到 3.15.0
现象(实机复现,截图见附件)
创建 Modbus TCP 设备:points = temperature(address="0", fixed 1234) + setpoint(address="1", fixed 42),监听 127.0.0.1:5020。
pymodbus 3.15.0(截图 repro-caseA-pymodbus-3.15.png)
READ HR[0..1] expect [1234, 42] -> registers=[0, 0] # 配置的初始值全部丢失
WRITE HR[1]=555 -> echo 正常 # 外部直写数据存储仍有效
READ HR[0..1] expect [1234, 555] -> registers=[0, 555]
外部客户端读写请求本身正常响应(无异常码),但 ProtoForge 配置的点位值从未进入数据存储;ProtoForge API 的 write_point -> _write_register 路径同样对数据存储无效果,且无任何 error 日志——_write_register 拿到 ExcCodes.DEVICE_BUSY 返回值但未检查,静默吞掉。外部客户端看到的数据与 ProtoForge 页面/API 报告的点位值不一致。
pymodbus 3.12.1 对照(截图 repro-caseB-pymodbus-3.12-baseline.png)
READ HR[0..1] expect [1234, 42] -> registers=[0, 1234] # 值能写入
(另注意到 3.12.1 下值出现在 protocol address+1 的位置——point address "0" 写到了地址 1,疑似 off-by-one,若属有意设计请忽略此条)
根因
- pymodbus 3.13.0 起(为 v4 迁移做的废弃处理):ModbusServerContext deprecated,其 async_getValues / async_setValues 对非 ModbusSimulatorContext 的 device 直接 return ExcCodes.DEVICE_BUSY,不执行任何读写(pymodbus/datastore/context.py L139-172;3.12.1 无此行为,已逐版本核对 3.11.4/3.12.1/3.13.1/3.14.0/3.15.0)
- ProtoForge 侧:_write_register / _read_register 调用 self._context.async_setValues/getValues(...) 后未检查返回值;except (ValueError, IndexError, KeyError, TypeError) 只能捕获旧式"签名变更抛异常",覆盖不了"返回错误码"这种新行为
- CI 的 integration-test 只断言 HTTP API 端点,没有真实 Modbus 客户端读写数据的用例,所以全绿通过
复现步骤
附件 repro-output.txt + server.py / client.py;或:
- pip install protoforge(装到 pymodbus 3.15.0)
- 创建含 fixed_value 点位的 Modbus TCP 设备并启动
- pymodbus 客户端 read_holding_registers(0, count=2, device_id=1) -> 全 0,而非配置值
修复建议
环境
pymodbus>=3.6.0无上界,新装环境默认拿到 3.15.0现象(实机复现,截图见附件)
创建 Modbus TCP 设备:points = temperature(address="0", fixed 1234) + setpoint(address="1", fixed 42),监听 127.0.0.1:5020。
pymodbus 3.15.0(截图 repro-caseA-pymodbus-3.15.png)
外部客户端读写请求本身正常响应(无异常码),但 ProtoForge 配置的点位值从未进入数据存储;ProtoForge API 的 write_point -> _write_register 路径同样对数据存储无效果,且无任何 error 日志——_write_register 拿到 ExcCodes.DEVICE_BUSY 返回值但未检查,静默吞掉。外部客户端看到的数据与 ProtoForge 页面/API 报告的点位值不一致。
pymodbus 3.12.1 对照(截图 repro-caseB-pymodbus-3.12-baseline.png)
(另注意到 3.12.1 下值出现在 protocol address+1 的位置——point address "0" 写到了地址 1,疑似 off-by-one,若属有意设计请忽略此条)
根因
复现步骤
附件 repro-output.txt + server.py / client.py;或:
修复建议