Pymodbus TCP `read_holding_registers` 返回陈旧/旧数据
Posted
技术标签:
【中文标题】Pymodbus TCP `read_holding_registers` 返回陈旧/旧数据【英文标题】:Pymodbus TCP `read_holding_registers` returns stale/old data 【发布时间】:2019-01-24 18:53:34 【问题描述】:我已经开始使用pymodbus
从 modbus 读取值以存储在异地数据库中。我一直在努力解决一个问题,即响应中收到的值与我在 Jace 上看到的值不同。
我也尝试过modbus-tk
,但我得到了同样的错误响应,所以它一定是我的 Python 代码中的某些东西导致了这个问题。从我们的遗留系统 (VB.Net) 检索到的读数与我在 Jace 上看到的输出相同。
这是从 modbus 检索数据的简单函数。我们在40160
和40162
有两个寄存器,第一个是366
,这是正确的,第二个是367
(这是我遇到的问题)。我也看到了与其他寄存器相同的问题,即使我可以在 Jace 上看到值增加了,读数也不会更新。
# -*- coding: utf-8 -*-
from __future__ import division, print_function, unicode_literals
from pymodbus.client.sync import ModbusTcpClient
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
def get_modbus_register_data(ip_address, register, device, count=2):
"""
Retrieve modbus data.
"""
client = ModbusTcpClient(ip_address, timeout=10)
client.connect()
# Read registers
response = client.read_holding_registers(
address=register, # 40162
count=count, # 2
unit=device) # 4
decoder = BinaryPayloadDecoder.fromRegisters(
registers=response.registers,
byteorder=Endian.Big,
wordorder=Endian.Little)
value = decoder.decode_32bit_float()
client.close()
return value # 366 and it should be 367
Pymodbus 调试日志
DEBUG:pymodbus.transaction:Current transaction state - IDLE
DEBUG:pymodbus.transaction:Running transaction 1
DEBUG:pymodbus.transaction:SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x4 0x3 0x0 0xa0 0x0 0x2
DEBUG:pymodbus.client.sync:New Transaction state 'SENDING'
DEBUG:pymodbus.transaction:Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x0 0x1 0x0 0x0 0x0 0x7 0x4 0x3 0x4 0x0 0x0 0x43 0xb7
DEBUG:pymodbus.framer.socket_framer:Processing: 0x0 0x1 0x0 0x0 0x0 0x7 0x4 0x3 0x4 0x0 0x0 0x43 0xb7
DEBUG:pymodbus.factory:Factory Response[ReadHoldingRegistersResponse: 3]
DEBUG:pymodbus.transaction:Adding transaction 1
DEBUG:pymodbus.transaction:Getting transaction 1
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
更新
在 Sanju 的帮助下,有人向我指出我使用的偏移量可能不正确。情况确实如此,通过将偏移量更改为 1 (40162 - 40001 = 161),我能够从寄存器中检索正确的值,wordorder
需要更改为 Endian.Big
。
更新代码
def get_modbus_register_data(ip_address, register, device, count=2):
"""
Retrieve modbus data.
"""
client = ModbusTcpClient(ip_address, timeout=10)
client.connect()
# Read registers
response = client.read_holding_registers(
address=register, # 40161
count=count, # 2
unit=device) # 4
decoder = BinaryPayloadDecoder.fromRegisters(
registers=response.registers,
byteorder=Endian.Big,
wordorder=Endian.Big)
value = decoder.decode_32bit_float()
client.close()
return value # 367
【问题讨论】:
这可能是因为您远程站点上的 modbus 从站需要一些时间来更新其寄存器,您是否尝试过在循环中读取相同的寄存器并且中间有一些睡眠时间?我的猜测是你应该至少在一些迭代之后看到你期望的值。 Pymodbus 只是一个促进者,它不存储值,您的日志显示从站正在返回寄存器[0, 17335]
,它被解码为 366。
@Sanju 我试过你提到的,在添加延迟后,我仍然得到两个寄存器相同的结果(366)。我刚刚检查了我们的 .Net 集成,它正确地检索了两个寄存器,一个为 366,另一个为 367。
您的日志缺少40162
的事务,您可以添加相同的日志吗?当前日志仅显示从偏移量0xa0
(160) 读取 2 个寄存器的事务
还要注意 pymodbus 如何处理偏移量,偏移量 0
映射到寄存器 40001
所以 40162 的偏移量将是 40162-40001
即 0xa1
和类似的 40160 偏移量将是0x9f
。参考pymodbus.readthedocs.io/en/latest/source/library/…
@Sanju 感谢您的帮助,原来偏移 ^ 是问题的一部分,byteorder
和 wordorder
必须是 Endian.Big
。在我更改检索到的数据是正确的之后。请将此添加为答案。
【参考方案1】:
使用 pymodbus,您必须注意 pymodbus 如何处理偏移量,偏移量 0 映射到寄存器 40001,因此 40162 的偏移量将是 40162-40001
,即 0xa1
,同样对于 40160
,偏移量将是0x9f
。
更多信息请参考https://pymodbus.readthedocs.io/en/latest/source/library/pymodbus.html#pymodbus.register_read_message.ReadHoldingRegistersRequest
另请注意,BinaryPayloadDecoder
假定的默认 Endianness
是 Endian.Little
代表 byteorder
和 Endian.Big
代表 wordorder
。如果这些orders
不正确,您最终会得到错误的解码值。
【讨论】:
以上是关于Pymodbus TCP `read_holding_registers` 返回陈旧/旧数据的主要内容,如果未能解决你的问题,请参考以下文章
Pymodbus TCP `read_holding_registers` 返回陈旧/旧数据
如何在 PYMODBUS(Modicon?)中塑造一个 CALL