У меня есть работающий сервер 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 мог читать заполненные мной регистры.
a
? - person Prudhvi   schedule 19.10.2019a =(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.2019updating_writer()
. Но вы говорите, что хотите вызватьupdating_writer()
из другого скрипта? Как ты это делаешь? Можете ли вы добавить свой второй сценарий? - person Marcos G.   schedule 22.10.2019loopingCall
. Вам не нужно вызыватьupdating_writer
вручную, он уже периодически вызываетсяloopingCall
. Чего я не понимаю, так это почему вы хотите обновить свой сервер Modbus из другого скрипта. Если это жесткое требование, вы можете попробовать заменитьtwisted
наmultiprocessing
, см., например, здесь - person Marcos G.   schedule 23.10.2019twisted
. Используете ли вы объектно-ориентированный подход? Вы видели этот пример. Вы также можете взглянуть на pyModSlave, он не использует pymodbus, но может дать вам идеи для организовать свой код, может быть. Я думал, вас интересует быстрое и грязное решение; если вам нужен графический интерфейс, я бы предпочел взглянуть на эти примеры и, возможно, на другие, более общие (я не думаю, что ваша проблема вообще связана с Modbus). - person Marcos G.   schedule 23.10.2019