Реализация pymodbus Modbus Server с контекстом нескольких подчиненных устройств - запись в регистр перезаписывает все подчиненные устройства

У меня проблема с простой реализацией сервера 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()

0 ответов

У меня была аналогичная проблема с сервером RTU, и у меня был более менее такой же код, как и у вас.

Но для меня это было то, что я не сделал отдельные объекты ModbusSlaveContext в подчиненном dict. Но в вашем коде это не так.

Я делюсь своим кодом здесь, может быть, это кому-то поможет.

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()
Другие вопросы по тегам