简体   繁体   中英

Pymodbus TCP `read_holding_registers` returns stale/old data

I've started using pymodbus to read values from modbus to store in a database off site. I've been struggling with an issue that the value received in the response is not the same as the value I can see on the Jace.

I've tried modbus-tk as well and I'm getting the same incorrect response, so it must be something in my Python code that is causing this issue. The readings retrieved from our legacy system (VB.Net) are the same as the outputs I see on the Jace.

This is the simple function retrieving the data from modbus. We have 2 registers at 40160 and 40162 the first one is reading 366 which is correct and the 2nd one is reading 367 (This is the one I'm having the problem with). I've also seen the same issue with other registers where the reading does not update even though I can see on the Jace that the value has increased.

# -*- 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 logs

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'

杰斯读书

配置

Update

With the help of Sanju, it was pointed out to me that the offset I'm using might be incorrect. This was indeed the case, by changing the offset by 1 (40162 - 40001 = 161) I was able to retrieve the correct values from the register, the wordorder needed to change to Endian.Big .

Updated code

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

With pymodbus you will have to pay attention to how pymodbus deals with offsets, an offset 0 maps to register 40001 so the offset for 40162 would be 40162-40001 which is 0xa1 and similarly for 40160 the offset would be 0x9f . For more info refer https://pymodbus.readthedocs.io/en/latest/source/library/pymodbus.html#pymodbus.register_read_message.ReadHoldingRegistersRequest

Also note, the default Endianness assumed by BinaryPayloadDecoder is Endian.Little for byteorder and Endian.Big for wordorder . You will end up with wrong decoded values if these orders are not correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM