Спасибо Маркеру и всем примерам в сети. Наконец-то я получил эту работу, как я хотел. Надеюсь, это поможет кому-то другому.
Было несколько ошибок, с которыми я столкнулся:
- Я пробовал следующие примеры, которые я нашел в Интернете, все из которых использовали pymodbus.server.async вместо pymodbus.server.sync. Я обнаружил, что не могу импортировать pymodbus.server.async, потому что «async» - зарезервированное слово в Python3.7! (не в старых версиях Python). В любом случае я хотел использовать pymodbus.server.sync, потому что хотел избежать импорта twisted, если это вообще возможно. К этому серверу будет подключаться не более 1-3 клиентов.
- Во всех примерах, показывающих, что писатель обновлений используется "LoopingCall" от Twisted. Я понятия не имею, что такое Twisted, и не хотел использовать его, если не было необходимости. Я был знаком с многопроцессорностью и многопоточностью. Я уже запускал ModbusTcpServer в процессе и пытался создать управляемые объекты вокруг хранилища / контекста, чтобы у меня мог быть другой процесс, выполняющий обновление. Но это не сработало: я предполагаю, что StartTcpServer не любит получать управляемые объекты (?), И я не хотел углубляться в эту функцию.
- В одном из примеров отмечалось, что можно использовать поток Python, и это решило эту проблему. У меня все еще запущен ModbusTcpServer в процессе, но прямо перед тем, как я вызываю «StartTcpServer», я запускаю НИТЬ, а не ПРОЦЕСС с обновляющим писателем. Тогда мне не нужно было помещать хранилище / контекст в управляемые объекты, поскольку поток может видеть то же пространство данных, что и процесс, который его запустил. Мне просто нужен ДРУГОЙ управляемый объект для отправки сообщений в этот поток, как я уже привык делать с процессом.
Ооочень ...
Сначала я должен был сделать это: from threading import Thread
Затем я запустил следующее в процессе, как делал раньше, но ПЕРЕД вызовом StartTcpServer я запустил поток update_writer (все переменные start_addr, init_val и num_addrs установлены ранее).
discrete_inputs_obj = ModbusSequentialDataBlock(di_start_addr, [di_init_val]*di_num_addrs)
coils_obj = ModbusSequentialDataBlock(co_start_addr, [co_init_val]*co_num_addrs)
holding_regs_obj = ModbusSequentialDataBlock(hr_start_addr, [hr_init_val]*hr_num_addrs)
input_regs_obj = ModbusSequentialDataBlock(ir_start_addr, [ir_init_val]*ir_num_addrs)
mb_store = ModbusSlaveContext(di=discrete_inputs_obj, co=coils_obj, hr=holding_regs_obj, ir=input_regs_obj, zero_mode=True)
mb_context = ModbusServerContext(slaves=mb_store, single=True)
mb_store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(di_start_addr, [di_init_val]*di_num_addrs),
co=ModbusSequentialDataBlock(co_start_addr, [co_init_val]*co_num_addrs),
hr=ModbusSequentialDataBlock(hr_start_addr, [hr_init_val]*hr_num_addrs),
ir=ModbusSequentialDataBlock(ir_start_addr, [ir_init_val]*ir_num_addrs))
mb_context = ModbusServerContext(slaves=mb_store, single=True)
updating_writer_cfg = {}
updating_writer_cfg["mb_context"] = mb_context
updating_writer_cfg["managed_obj"] = managed_obj #For being able to send messages to this Thread
updating_writer_thread = Thread(target = updating_writer, args = [updating_writer_cfg]) # We need this to be a thread in this process so that they can share the same datastore
updating_writer_thread.start()
StartTcpServer(mb_context, address=("", port))
В цикле while update_writer у меня есть код, который опрашивает managed_obj для получения сообщений. При добавлении ключевых фрагментов кода в этот цикл:
mb_context[0].setValues(4, addr_to_write, regs_to_write)
... где 4 - функция записи, addr_to_write - адрес регистра, с которого следует начать запись, а regs_to_write - список значений регистров ... И ...
regs_to_read = mb_context[0].getValues(3, addr_to_read, num_regs_to_read)
... где 3 - функция чтения, addr_to_read - адрес регистра, с которого следует начать чтение. regs_to_read будет списком длиной num_regs_to_read.
person
Akash Sharma
schedule
10.01.2019