pymodbus: обновить контекст работающего сервера

У меня есть работающий сервер ModbusRTU, следуя этому примеру. Я знаю, как обновить контекст, но не могу обновить контекст работающего сервера.

Когда я обновляю контекст в функции run_updating_server() (до StartSerialServer()), все работает нормально. Но когда я пытаюсь обновить текущий контекст, вызвав update_writer(context), он не обновляется.

Также вызов моей собственной функции getUpdatedContext() из update_writer() не работает:

 def updating_writer(a):
    a =(getContext(),)
    """ 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
    """

    log.debug("updating the context")
    context = a[0]
    register = 3
    slave_id = 0x41
    address = 0x10
    values = context[slave_id].getValues(register, address, count=5)
    values = [v + 1 for v in values]
    log.debug("new values: " + str(values))
    context[slave_id].setValues(register, address, values)

получитьконтекст():

def getContext():
    store = ModbusSlaveContext(
      di=ModbusSequentialDataBlock(0, [17]*100),
      co=ModbusSequentialDataBlock(0, [17]*100),
      hr=ModbusSequentialDataBlock(0, [17]*100),
      ir=ModbusSequentialDataBlock(0, [17]*100))

    store.setValues(5, 1, [0])
    context = ModbusServerContext(slaves=store, single=True)
    return context

мой полный код:

#!/usr/bin/env python

import os
import sys
"""
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 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
    """

    log.debug("updating the context")
    context = a[0]
    register = 3
    slave_id = 0x41
    address = 0x10
    values = context[slave_id].getValues(register, address, count=5)
    values = [v + 1 for v in values]
    log.debug("new values: " + str(values))
    context[slave_id].setValues(register, address, values)

def run_updating_server():
    # ----------------------------------------------------------------------- # 
    # initialize your data store
    # ----------------------------------------------------------------------- # 

    store = ModbusSlaveContext(
        di=ModbusSequentialDataBlock(0, [17]*100),
        co=ModbusSequentialDataBlock(0, [17]*100),
        hr=ModbusSequentialDataBlock(0, [17]*100),
        ir=ModbusSequentialDataBlock(0, [17]*100))

    context = ModbusServerContext(slaves=store, single=True)

    # ----------------------------------------------------------------------- # 
    # 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.2.0'

    # ----------------------------------------------------------------------- # 
    # run the server you want
    # ----------------------------------------------------------------------- # 
    time = 5
    loop = LoopingCall(f=updating_writer, a=(context,))
    loop.start(time, now=False)  # initially delay by time

    log.debug("::: Starting Modbus RTU server :::")

    # RTU:
    StartSerialServer(context, framer=ModbusRtuFramer, identity=identity,
                      port='/dev/ttyUSB0', 
                      timeout=2, 
                      baudrate=115200, 
                      parity='E',
                      bytesize=8,
                      stopbits=1)

def main():
    pid = str(os.getpid())
    filename = 'modbusUpdatingServer.pid'
    pidfile = str(os.getcwd()) + '/' + filename 
    if os.path.isfile(pidfile):
        print (filename + " already exists \n exiting")
        sys.exit()
    open(pidfile, 'w').write(pid)
    try:
        # run server
        run_updating_server()
    finally:
        os.unlink(pidfile)

if __name__ == "__main__":
    main()

Я хочу обновить контекст из другого скрипта Python, я пробовал:

  • вызов update_writer(a) из этого «другого скрипта Python», где a = updatedContext.

  • вызов getUpdatedContext() с помощью update_writer(a), которая является функцией в «этом другом скрипте Python», которая возвращает updatedContext

  • сделайте контекст глобальным, добавьте функцию updateContext(a), вызовите эту функцию из другого скрипта Python.

В итоге код компилировался, но контекст работающего сервера не обновлялся.

здесь код из «другого скрипта Python»:

from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSlaveContext, ModbusServerContext
from threading import Thread
import os
import subprocess
import sys

from modbusUpdatingServer import updating_writer, run_updating_server

def writeUpdatedContext():
    store = ModbusSlaveContext(
    di=ModbusSequentialDataBlock(0, [17]*100),
    co=ModbusSequentialDataBlock(0, [17]*100),
    hr=ModbusSequentialDataBlock(0, [17]*100),
    ir=ModbusSequentialDataBlock(0, [17]*100))

    store.setValues(5, 1, [0])

    context = ModbusServerContext(slaves=store, single=True)
    updating_writer(a=(context,)   

def main():
    choice = input("press x if you want to update the context")

    if choice == 'x' or choice == 'X':
        writeUpdatedContext()


if __name__ == "__main__":
    main()

Как я должен взаимодействовать с update_writer? Чего я хочу добиться, так это того, чтобы мой сервер modbusRTU работал и обновлял контекст от другой угрозы, чтобы мой клиент (главный) modbus мог читать заполненные мной регистры.


person user_cr    schedule 19.10.2019    source источник
comment
каково содержание a?   -  person Prudhvi    schedule 19.10.2019
comment
Не могли бы вы добавить более полный код?   -  person Benyamin Jafari    schedule 19.10.2019
comment
Ваш код отлично работает, удаляя собственный вызов функции a =(getContext(),) и соответствующий импорт. Я тестировал его на Linux, Python 2.7.16 и 3.7.3 и pyModbus 2.2.0. Вы хотя бы видите строки отладки DEBUG:root:new values: [xx, xx, xx, xx, xx] с изменением xx?   -  person Marcos G.    schedule 21.10.2019
comment
Извините, я не понял: этот код работает так, да, я вижу строки отладки. но я хочу вызвать update_writer(a) вне цикла (из другого скрипта Python). но когда я делаю этот вызов, контекст (a) не обновляется.   -  person user_cr    schedule 21.10.2019
comment
Понятно... Я не понял этого из вашего вопроса. На мой взгляд, идея этого примера состоит в том, чтобы обновить значения вашего сервера с updating_writer(). Но вы говорите, что хотите вызвать updating_writer() из другого скрипта? Как ты это делаешь? Можете ли вы добавить свой второй сценарий?   -  person Marcos G.    schedule 22.10.2019
comment
Я обновил свой вопрос. По сути, я просто вызываю update_writer(a), где a — мой новый контекст.   -  person user_cr    schedule 22.10.2019
comment
Теперь я понимаю, что вы имеете в виду, хорошее обновление. То, как вы это делаете, не сработает, у вас есть два разных контекста Modbus, и они находятся в разных местах памяти. Я думаю, вы неправильно поняли, как работает loopingCall. Вам не нужно вызывать updating_writer вручную, он уже периодически вызывается loopingCall. Чего я не понимаю, так это почему вы хотите обновить свой сервер Modbus из другого скрипта. Если это жесткое требование, вы можете попробовать заменить twisted на multiprocessing, см., например, здесь   -  person Marcos G.    schedule 23.10.2019
comment
Спасибо @MarcosG. Теперь я понимаю свою проблему. Я хочу обновить контекст из другого скрипта, потому что мне нужен 1 скрипт, который является сервером Modbus, и еще один скрипт с пользовательским интерфейсом. Есть ли серьезный недостаток, если я использовал скрученный, а затем передал свой контекст в качестве ссылки? Мне непонятно, почему в моем случае лучше использовать многопроцессорность, не могли бы вы рассказать об этом подробнее?   -  person user_cr    schedule 23.10.2019
comment
Пожалуйста. Я не говорю, что вы должны отказаться от twisted. Используете ли вы объектно-ориентированный подход? Вы видели этот пример. Вы также можете взглянуть на pyModSlave, он не использует pymodbus, но может дать вам идеи для организовать свой код, может быть. Я думал, вас интересует быстрое и грязное решение; если вам нужен графический интерфейс, я бы предпочел взглянуть на эти примеры и, возможно, на другие, более общие (я не думаю, что ваша проблема вообще связана с Modbus).   -  person Marcos G.    schedule 23.10.2019