Как остановить асинхронный ModbusTcpServer на pymodbus?
Я хочу остановить pymodbus
асинхронной ModbusTcpServer
затем запустите новый сервер, поэтому я попытался использовать следующий упрощенный фрагмент кода, но получил ошибку:
from pymodbus.server.async import StartTcpServer, StopServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from time import sleep
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def main(name='Pymodbus'):
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
identity = ModbusDeviceIdentification()
identity.VendorName = name
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.0'
StartTcpServer(
context,
identity=identity,
address=("localhost", 5020),
defer_reactor_run=True
)
sleep(3)
name += 'stuff'
StopServer()
sleep(3)
main(name) # Recursive
main()
Из:
INFO:pymodbus.server.async:Starting Modbus TCP Server on localhost:5020
DEBUG:pymodbus.server.async:Running in Main thread
Traceback (most recent call last):
File "stack.py", line 42, in <module>
main()
File "stack.py", line 38, in main
StopServer()
File "/usr/local/lib/python3.6/dist-packages/pymodbus/server/async.py", line 328, in StopServer
reactor.stop()
File "/usr/local/lib/python3.6/dist-packages/twisted/internet/base.py", line 630, in stop
"Can't stop reactor that isn't running.")
twisted.internet.error.ReactorNotRunning: Can't stop reactor that isn't running.
[ОБНОВИТЬ]
Кроме того, я пытался с другим потоком остановить ModbusTcpServer
с defer_reactor_run=Flase
аргумент (по умолчанию) в ModbusTcpServer
, но поведение осталось таким же, даже так:
import threading
import logging
from pymodbus.server.async import StartTcpServer, StopServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def stop():
StopServer()
def main(name='Pymodbus'):
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
identity = ModbusDeviceIdentification()
identity.VendorName = name
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.0'
t = threading.Timer(5, stop)
t.daemon = True
t.start()
StartTcpServer(
context,
identity=identity,
address=("localhost", 5020),
defer_reactor_run=False
)
name += 'stuff'
main(name) # Recursive
main()
Из:
INFO:pymodbus.server.async:Starting Modbus TCP Server on localhost:5020
DEBUG:pymodbus.server.async:Running in Main thread
DEBUG:pymodbus.server.async:Running in spawned thread
DEBUG:pymodbus.server.async:Stopping Server from another thread
INFO:pymodbus.server.async:Starting Modbus TCP Server on localhost:5020
DEBUG:pymodbus.server.async:Running in Main thread
Traceback (most recent call last):
File "stack.py", line 41, in <module>
main()
File "stack.py", line 39, in main
main() # Recursive
File "stack.py", line 35, in main
defer_reactor_run=False
File "/usr/local/lib/python3.6/dist-packages/pymodbus/server/async.py", line 257, in StartTcpServer
reactor.run(installSignalHandlers=_is_main_thread())
File "/usr/local/lib/python3.6/dist-packages/twisted/internet/base.py", line 1260, in run
self.startRunning(installSignalHandlers=installSignalHandlers)
File "/usr/local/lib/python3.6/dist-packages/twisted/internet/base.py", line 1240, in startRunning
ReactorBase.startRunning(self)
File "/usr/local/lib/python3.6/dist-packages/twisted/internet/base.py", line 748, in startRunning
raise error.ReactorNotRestartable()
twisted.internet.error.ReactorNotRestartable
2 ответа
Я нашел альтернативное решение, чтобы остановить и запустить Async ModbusTcpServer с помощью другого кода Python, потому что, очевидно, мы не можем перезапустить reactor
событие-цикл.
Это runner.py
код:
import subprocess
python_version = '3'
path_to_run = './'
py_name = 'async_server.py'
def run():
args = [f"python{python_version}", f"{path_to_run}{py_name}"]
sub_process = subprocess.Popen(args, stdout=subprocess.PIPE)
output, error_ = sub_process.communicate()
if not error_:
print(output)
else:
print(error_)
run() # Recursively.
if __name__ == '__main__':
run()
Это async_server.py
фрагмент кода:
from pymodbus.server.async import StartTcpServer, StopServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
import threading
import sys
import logging
FORMAT = ('%(asctime)-15s %(threadName)-15s'
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def stop():
print('Process will be down.')
StopServer() # Stop server.
sys.exit(0) # Kill the server code.
def run_async_server():
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [17] * 100))
slaves = {
0x01: store,
0x02: store,
0x03: store,
}
context = ModbusServerContext(slaves=slaves, single=False)
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 = '1.5'
from twisted.internet import reactor
StartTcpServer(context, identity=identity, address=("localhost", 5020),
defer_reactor_run=True)
print('Start an async server.')
t = threading.Timer(5, stop)
t.daemon = True
t.start()
reactor.run()
print('Server was stopped.')
if __name__ == "__main__":
run_async_server()
Из:
$ python3 runner.py
2019-01-24 12:45:05,126 MainThread INFO async :254 Starting Modbus TCP Server on localhost:5020
2019-01-24 12:45:10,129 Thread-1 DEBUG async :222 Running in spawned thread
2019-01-24 12:45:10,129 Thread-1 DEBUG async :332 Stopping Server from another thread
b'Start an async server.\nProcess will be down.\nServer was stopped.\n'
2019-01-24 12:45:13,389 MainThread INFO async :254 Starting Modbus TCP Server on localhost:5020
2019-01-24 12:45:18,392 Thread-1 DEBUG async :222 Running in spawned thread
2019-01-24 12:45:18,392 Thread-1 DEBUG async :332 Stopping Server from another thread
b'Start an async server.\nProcess will be down.\nServer was stopped.\n'
2019-01-24 12:45:21,653 MainThread INFO async :254 Starting Modbus TCP Server on localhost:5020
2019-01-24 12:45:26,656 Thread-1 DEBUG async :222 Running in spawned thread
2019-01-24 12:45:26,657 Thread-1 DEBUG async :332 Stopping Server from another thread
b'Start an async server.\nProcess will be down.\nServer was stopped.\n'
.
.
.
Вы можете использовать пример из папок библиотеки: asynchronous-server.py
в python3.7 async был включен как ключевое слово, но в pymodbus 2.3.0 pymodbus.server.async был изменен на pymodbus.server.asynchronous
Я поделюсь с вами примером, который мне подходит:
Если у вас есть еще вопросы, напишите мне на электронную почту:Danielsalazr@hotmail.com
#Este codigo funciona ingresando a la direccion esclavo 16 en decimal
#la Ip debe ser la misma que esta asignada en el dispositivo
#los datos se actualizan a patir del registro #15
#Aparentemente la direcion del esclavo no tiene importancia, debido a que
#al realizar la conexion desde el software QModMaster, el numero ingresado
#em el campo SlaveAddr, no afecta la posibilidad de conexion
'''
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 StartTcpServer
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 = 0x01
address = 0x10
values = context[slave_id].getValues(register, address, count=5)
#el valor count = 5 modifica los datos de los siguientes 5 registros
#continuos al registro especificado en la variable address = 0x10, 16 en decimal
values = [v + 1 for v in values]
log.debug("new values: " + str(values))
context[slave_id].setValues(register, address, values)
#---------------------------------------------------------------------------#
# 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)
#ModbusSlaveContext.setValues("lol",hr,3,25)
#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 = '1.0'
#---------------------------------------------------------------------------#
# run the server you want
#---------------------------------------------------------------------------#
time = 1 # 5 seconds delay
loop = LoopingCall(f=updating_writer, a=(context,))
loop.start(time, now=False) # initially delay by time
StartTcpServer(context, identity= identity, address=("192.168.0.40", 502)) #here you need
#change the ip for the ip address of your device
Привет из Колумбии
В первом примере сервер TCP не запущен, поскольку вы установили для параметра param defer_reactor_run значение True, но вы явно его не запускали. Таким образом, когда вы пытаетесь остановить его, происходит сбой, поскольку он не был запущен.
Во втором примере вы запускаете его, но в следующий раз вызываете его рекурсивно с помощью вызова main(name)! Итак, он завершается с ошибкой, поскольку он уже запущен! следующий код должен работать:
from pymodbus.server.async import StartTcpServer, StopServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from time import sleep
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def main(name='Pymodbus'):
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
identity = ModbusDeviceIdentification()
identity.VendorName = name
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.0'
StartTcpServer(
context,
identity=identity,
address=("localhost", 5020),
defer_reactor_run=False
)
sleep(3) # for the fun ?
# and do your stuff
StopServer()
main()
Если вы хотите отложить запуск, вы должны позвонить:
from twisted.internet import reactor
StartTcpServer(context, identity=identity, address=("localhost", 5020),
defer_reactor_run=True)
reactor.run()