【问题标题】:pymodbus Modbus Server implementation with multiple slave devices context - writing to a register overwrites to all slaves具有多个从设备上下文的 pymodbus Modbus 服务器实现 - 写入寄存器会覆盖所有从设备
【发布时间】:2020-09-08 22:48:17
【问题描述】:

我对简单的 pymodbus 服务器实现有疑问。从我在文档中读到的内容来看,这个实现应该有每个从设备唯一的从上下文,即写入设备 0x01,寄存器地址 1,应该是与设备 0x02,寄存器 1 不同的寄存器。

在我的情况下,写入寄存器 1 会写入所有从地址的寄存器 1。有人可以检查我的服务器代码,看看我是否遗漏了什么,或者澄清我是否理解 pymodbus 服务器应该如何在单个标志设置为 False 的情况下工作。

干杯。代码在这里:

#!/usr/bin/env python3
"""
Pymodbus Synchronous Server
--------------------------------------------------------------------------

This synced server is implemented using TCP, with multiple slave contexts
"""
# --------------------------------------------------------------------------- #
# import the various server implementations
# --------------------------------------------------------------------------- #
from pymodbus.server.sync import StartTcpServer

from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext

def run_server():

    slaves = {

        0x01: ModbusSlaveContext(),
        0x02: ModbusSlaveContext()

    }

    context = ModbusServerContext(slaves=slaves, single=False)

    # ----------------------------------------------------------------------- #
    # initialize the server information
    # ----------------------------------------------------------------------- #
    # If you don't set this or any fields, they are defaulted to empty strings.
    # ----------------------------------------------------------------------- #
    identity = ModbusDeviceIdentification()
    identity.VendorName = 'Pymodbus'
    identity.ProductCode = 'PM'
    identity.VendorUrl = 'http://github.com/riptideio/pymodbus/'
    identity.ProductName = 'Pymodbus Server'
    identity.ModelName = 'Pymodbus Server'
    identity.MajorMinorRevision = '2.3.0'

    # ----------------------------------------------------------------------- #
    # run the server
    # ----------------------------------------------------------------------- #
    StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020))

if __name__ == "__main__":
    run_server()

【问题讨论】:

    标签: python python-3.x modbus-tcp pymodbus pymodbustcp


    【解决方案1】:

    我在 RTU 服务器上遇到了类似的问题,并且代码和你的代码不太一样。

    但对我来说,我没有在从属字典中创建单独的 ModbusSlaveContext 对象。但您的代码中并非如此。

    我在这里分享我的代码,也许它可以帮助某人。

    Python code:
        #!/usr/bin/env python
        """
        Pymodbus Server With Updating Thread
        --------------------------------------------------------------------------
        
        This is an example of having a background thread updating the
        context while the server is operating. This can also be done with
        a python thread::
        
            from threading import Thread
        
            thread = Thread(target=updating_writer, args=(context,))
            thread.start()
        """
        # --------------------------------------------------------------------------- #
        # import the modbus libraries we need
        # --------------------------------------------------------------------------- #
        from pymodbus.server.asynchronous import StartSerialServer
        from pymodbus.device import ModbusDeviceIdentification
        from pymodbus.datastore import ModbusSequentialDataBlock
        from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
        from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer
        
        # --------------------------------------------------------------------------- #
        # import the payload builder
        # --------------------------------------------------------------------------- #
        from pymodbus.constants import Endian
        from pymodbus.payload import BinaryPayloadDecoder
        from pymodbus.payload import BinaryPayloadBuilder
        
        # --------------------------------------------------------------------------- #
        # import the twisted libraries we need
        # --------------------------------------------------------------------------- #
        from twisted.internet.task import LoopingCall
        
        # --------------------------------------------------------------------------- #
        # configure the service logging
        # --------------------------------------------------------------------------- #
        import logging
        logging.basicConfig()
        log = logging.getLogger()
        log.setLevel(logging.DEBUG)
        
        # --------------------------------------------------------------------------- #
        # define your callback process
        # --------------------------------------------------------------------------- #
        
        
        def updating_writer(a):
            """ A worker process that runs every so often and
            updates live values of the context. It should be noted
            that there is a race condition for the update.
        
            :param arguments: The input arguments to the call
            """
            context = a[0]
            register = 3
            
            #### Write to registers slave 1 ####
            slave_id = 0x01
            log.debug(f"::: Make payload to SLAVE={slave_id} :::")
        
            # Total energy
            builder = BinaryPayloadBuilder(
                byteorder=Endian.Big,
                wordorder=Endian.Little
                )
            builder.add_32bit_int(20000)  # kWh Tot*10
            energy = builder.to_registers()
        
            # Phase 1 variables
            builder = BinaryPayloadBuilder(
                byteorder=Endian.Big,
                wordorder=Endian.Little
                )
            builder.add_32bit_int(4000)  # VL1L2*10
            builder.add_32bit_int(2300)  # VL1N*10
            builder.add_32bit_int(1000)  # AL1*1000
            builder.add_32bit_int(2300)  # kWL1*10
            phase1 = builder.to_registers()
        
            log.debug(f"::: Write registers to SLAVE={slave_id} :::")
            context[slave_id].setValues(register, 0x0112, energy)
            context[slave_id].setValues(register, 0x011e, phase1)
            context[slave_id].setValues(register, 0x000b, [0x0155])
        
            #### Write to registers slave 100 ####
            slave_id = 0x64
            log.debug(f"::: Make payload to SLAVE={slave_id} :::")
        
            # Total energy
            builder = BinaryPayloadBuilder(
                byteorder=Endian.Big,
                wordorder=Endian.Little
                )
            builder.add_32bit_int(20000)  # kWh Tot*10
            energy = builder.to_registers()
        
            # Phase 1 variables
            builder = BinaryPayloadBuilder(
                byteorder=Endian.Big,
                wordorder=Endian.Little
                )
            builder.add_32bit_int(4000)  # VL1L2*10
            builder.add_32bit_int(2300)  # VL1N*10
            builder.add_32bit_int(2000)  # AL1*1000
            builder.add_32bit_int(4600)  # kWL1*10
            phase1 = builder.to_registers()
        
            log.debug(f"::: Write registers to SLAVE={slave_id} :::")
            context[slave_id].setValues(register, 0x0112, energy)
            context[slave_id].setValues(register, 0x011e, phase1)
            context[slave_id].setValues(register, 0x000b, [0x0155])
        
        
        def run_updating_server():
            # ----------------------------------------------------------------------- # 
            # initialize your data store
            # ----------------------------------------------------------------------- # 
        
            addresses = [1, 100]
            slaves = {}
            for adress in addresses:
                store = ModbusSlaveContext(zero_mode=True)
                slaves.update({adress: store})
        
            context = ModbusServerContext(slaves=slaves, single=False)
        
            # ----------------------------------------------------------------------- # 
            # initialize the server information
            # ----------------------------------------------------------------------- # 
            identity = ModbusDeviceIdentification()
            identity.VendorName = 'pymodbus'
            identity.ProductCode = 'PM'
            identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
            identity.ProductName = 'pymodbus Server'
            identity.ModelName = 'pymodbus Server'
            identity.MajorMinorRevision = '2.3.0'
        
            # ----------------------------------------------------------------------- # 
            # run the server you want
            # ----------------------------------------------------------------------- # 
            time = 5  # 5 seconds delay
            loop = LoopingCall(f=updating_writer, a=(context,))
            loop.start(time, now=False) # initially delay by time
            StartSerialServer(
                context=context,
                framer=ModbusRtuFramer,
                identity=identity,
                port='/dev/ttyUSB0',
                timeout=0.0001,
                baudrate=9600,
                parity='N',
                bytesize=8,
                stopbits=1,
                ignore_missing_slaves=True)
    
    if __name__ == "__main__":
        run_updating_server()
    

    【讨论】:

      猜你喜欢
      • 2015-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-05-14
      • 2022-07-22
      • 2014-11-09
      • 2018-12-15
      • 1970-01-01
      • 2015-03-05
      相关资源
      最近更新 更多