Содержание


Преамбула

Здесь описывается монитор opcuamon, являющийся клиентом OPCUA общего назначения для пакета crwdaq.
Монитор обеспечивает обмен данными между пакетом crwdaq и сервером OPCUA, к которому он подключается.

Монитор состоит из:

Сначала ознакомьтесь с терминологией OPCUA.
Затем узнайте как работает монитор.
См. также заметки по OPCUA.

См. также сервер opcuasrv.

Перейти к Содержанию


Терминология OPCUA: server, client, namespace, node, alias

Псевдонимы используются в программе монитора OpcuaMon для понятности и читабельности, при выполнении программы псевдонимы автоматически заменяются на соответствующие индексы узлов. Псевдонимы должны быть простыми именами по правилам Pascal и не должны быть идентификаторами узлов, т.к. весь смысл псевдонимов состоит в замене nodeId на понятное (для программистов) читабельное имя.

Перейти к Содержанию


Как работает монитор

Программа opcuamon.py используется в готовом виде, “как есть”.
Всё конфигурирование происходит на уровне оболочки opcuamon.pas.

Оболочка полностью отвечает за интеграцию монитора в пакет crwdaq.

Для использования монитора нужно правильно сконфигурировать оболочку opcuamon.pas.
При конфигурировании описываются подключения узлов OPCUA к кривым и тегам пакета crwdaq, а также способы их опроса/обновления.

Общая схема работы монитора

Перейти к Содержанию


Данные и копии данных сервера и клиента

Работая с программами монитора (клиента) opcuamon и сервера opcuasrv всегда надо помнить, что в клиент-серверных программах всегда есть несколько копий данных:

В нормальной ситуации сервер и клиент стараются синхронизовать (обновлять) данные как можно скорее, чтобы все копии данных соответствовали оригиналу (исходным данным сервера). Однако, поскольку сервер и клиент работают в разных процессах, а приемник и передатчик - в разных потоках, всегда существуют задержки с обновлениями, а потому эти четыре копии данных могут отличаться друг от друга. Больше того, в некоторых ситуациях копии гарантированно отличаются. Например, когда клиент инициирует команду записи, заранее предполагается, что текущая копия данных клиента отличается от (желаемых) данных сервера. Целью записи является именно сстремление изменить данные сервера, чтобы затем сервер, прислав обновление клиенту, изменил копию данных клиента на желаемое значение.

В нашем случае имеется четыре возможные копии данных:

Для понимания работы программ opcuasrv и opcuamon необходимо понимать, что всякое изменение данных происходит путем последовательного изменения (синхронизации) указанных копий данных.

Например, если клиент вызывал команду @OpcNodeSend WaveStarted 1, происходит примерно следующее:

В случае подключения к другому (внешнему) серверу OPCUA вместо серверной программы opcuasrv.py и её оболочки opcuasrv.pas будет выступать внешний сервер (например, SCADA). Но логика остается примерно такой же. Понимание этой логики (наличие нескольких копий данных и синхронизация между ними) позволит избежать ошибок.

Перейти к Содержанию


Оболочка opcuamon.pas

Оболочка монитора opcuamon.pas содержит программу DaqPascal, которая отвечает за приемопередачу данных OPCUA от монитора opcuamon.py на стороне пакета crwdaq. Задачей оболочки opcuamon.pas является интеграция монитора в пакет crwdaq, включая функции запуска остановки, конфигурирования и обмена данными с мониторной программой opcuamon.py.

Перейти к Содержанию


Конфигурирование opcuamon.pas

Конфигурирование opcuamon.pas включает в себя:

Имеется пример demo_opcuamon демонстрационной конфигурации для иллюстрации работы монитора opcuamon. В конфигурации имеется справка.

Перейти к Содержанию


Конфигурация устройства

Для использования монитора opcuamon надо создать DAQ устройство - например, &OpcuaMon.

Самый простой способ - использовать default конфигурацию opcuamon.cfg для стандартного сервера &OpcuaMon.
Для этого достаточно добавить в конфигурацию код:

[ConfigFileList] ; Default config for &OpcuaMon
ConfigFile = ~~\resource\daqsite\default\opcuamon.cfg
[]

Стандартная конфигурация хорошо подходит для большинства прикладных задач.

Поскольку в системе может быть несколько серверов OPCUA, мониторов тоже может быть несколько (по монитору на сервер). Поэтому кроме стандартного монитора &OpcuaMon также есть готовые стандартные конфигурации для мониторов &OpcuaMon1, &OpcuaMon2, &OpcuaMon3, которые конфигурируются аналогично.

Можно также сконфигурировать устройство вручную.

Пример конфигурации устройства &OpcuaMon:

[DeviceList]
&OpcuaMon = device software program
[&OpcuaMon]
Comment       = OPCUA_MONITOR_PROGRAM
InquiryPeriod = 1
DevicePolling = 10, tpNormal
ProgramSource = ~~\resource\daqsite\opcuaserver\opcuamon.pas
DebugFlags    = 3
OpenConsole   = 2
StdInFifo     = 128
StdOutFifo    = 128
AnalogFifo    = 1000
DigitalFifo   = 1000
tagStdPyAppStat = Device/&OpcuaMon/StdPyApp.Stat
tagOpcuaMonStat = Device/&OpcuaMon/OpcuaMon.Stat
StartupScript = [&OpcuaMon.StartupScript]
FinallyScript = [&OpcuaMon.FinallyScript]
StartMonitorSection = [&OpcuaMon.StartMonitor]
StartMonitorPattern = /^(@Opc\w+.*|@Py\w+\s.*)$/i
StartMonitorTrigger = Welcome to opcuamon program.
DelayMonitorTrigger = 5000
FilterTooltipPattern = /^(info:|information:|warn:|warning:|error:|@warning|@error)\s/i
FilterConsolePattern = /^(info:|information:|warn:|warning:|error:)\s/i
tipInfoDelay = 15000
tipWarnDelay = 30000
tipErroDelay = 60000
[]

[TagList]
Device/&OpcuaMon/StdPyApp.Stat = string  0
Device/&OpcuaMon/OpcuaMon.Stat = string  0
[]

Кроме обычных параметров устройства задаются:

Тег tagStdPyAppStat определен так, чтобы гарантированно избежать конфликта имен.
Этот тег содержит строку статистики в формате cookie списка:
rss=RSS;vmd=VMS;gc=GE,OB,C0,C1,C2,GG,GW;poll=PC,PR,PW;ping=PT,PW;
где:
- RSS - resident set size - размер резидентной памяти программы opcuamon.py в байтах,
- VMS - virtual memory size - размер виртуальной памяти программы opcuamon.py в байтах,
- GE - флаг (0/1) разрешения сборщика мусора gc.isenabled(),
- OB - счетчик всех (динамических) объектов len(gc.get_objects()),
- C0 - счетчик сборщика мусора для 0-го поколения объектов gc.getcount()[0],
- C1 - счетчик сборщика мусора для 1-го поколения объектов gc.getcount()[1],
- C2 - счетчик сборщика мусора для 2-го поколения объектов gc.getcount()[2],
- GG - счетчик сборщика мусора для неопознанных объектов len(gc.garbage),
- GW - метка времени - когда обновлялась информация о памяти и сборщике мусора,
- PC - poll count - счетчик циклов опроса программы opcuamon.py,
- PR - poll rate - частота циклов опроса программы opcuamon.py,
- PW - poll when - метка времени когда обновлялись счетчики опроса,
- PT - ping time - время запроса-ответа в миллисекундах,
- PW - ping when - метка времени когда обновляялся ping.

Тег tagOpcuaMonStat определен так, чтобы гарантированно избежать конфликта имен.
Этот тег содержит строку статистики в формате cookie списка:
State=ST;ReadRate=RR;SendRate=SR;TimeStamp=TS;
где:
- ST - статус процесса: DEAD,STARTING,PREPARING,RUNNING,STOPPED,RESTARTING.
- RR - частота чтения данных, операций в секунду,
- SR - частота записи данных, операций в секунду,
- TS - метка времени, ms.

Тег tagStdPyAppStat позволяет клиентской программе наблюдать за работой программы opcuamon.py, чтобы была возможность изучать статистику её работы. При необходимости статистика извлекается из строки.

Перейти к Содержанию


Секции StartupScript, FinallyScript

В этих секциях описываются действия при старте и завершении работы DAQ-системы.
Секция завершения FinallyScript обычно пуста, т.к. после работы делать нечего.
Секция StartupScript должна содержать команды запуска программы opcuamon.py.
Стандартный вид секции инициализации приведен ниже:

[&OpcuaMon.StartupScript]                                       ; PyApp startup:
@PyApp Set Launch unix pyvenv                                   ; Command to launch script
@PyApp Set Script ~~/resource/daqsite/opcuaserver/opcuamon.py   ; Target script pathname
@PyApp Set Params                                               ; Script parameters
@PyApp Set PingCall @PollCount                                  ; Command on ping task
@PyApp Add PingCall @Memory                                     ; Command on ping task
@PyApp Set AutoStart 1                                          ; Enable AutoStart
@PyApp Set PipeSizeKb 128                                       ; Pipe buffer size, KB
@PyApp Set PreferToSend 0                                       ; 0:devPost, 1:devSend
@PyApp Set TimeOutToSend 100                                    ; Timeout to send data, ms
@PyApp Set TimeOutToStop 1000                                   ; Timeout to stop task, ms
@PyApp Set GuardTimerPeriod 5000                                ; Timer period to AutoStart
@PyApp Set PingTimerPeriod 1000                                 ; Timer period to PingCall
@PyApp Set CalcPing 1                                           ; Flag - calc Ping time
[]

[&OpcUaMon.FinallyScript]
[]

В обычной ситуации нет необходимости менять эти секции.

Перейти к Содержанию


Задание псевдонимов

Псевдонимы узлов используются для того, чтобы иметь возможность оперировать понятными (читабельными) именами узлов данных вместо трудно понимаемых индексных идентификаторов. Псевдонимы позволяют сосредоточить все проблемы подключения данных в одном месте, в описании псевдонимов, а дальше работать в терминах предметной области, используя понятные для людей имена узлов.

Псевдонимы узлов задаются в секции устройства (например [&OpcuaMon]) в формате строк:

Alias name = node

где

Например:

[&OpcuaMon]
;***************************
;**** Alias to Node mapping:
;***************************
Alias WaveSin       = ns2i2003
Alias WaveCos       = ns2i2004
Alias WaveAmplitude = ns2i2005
Alias WaveFrequency = ns2i2006
Alias WaveNoise     = ns2i2007
Alias WaveStarted   = ns2i2008
[]

При выполнении программы монитора каждый псевдоним заменяется на короткий индексный идентификатор узла.

Настоятельно рекомендуется задавать псевдонимы для всех используемых узлов и работать с псевдонимами, а не с индексными идентификаторами. Это облегчит написание кода и его сопровождение.

Перейти к Содержанию


Список связей задается в секции описания устройства, например, [&OpcuaMon]. Он задает связи узлов OPCUA с кривыми, тегами, сообщениями и атрибутами.
Это связи указывают, куда и как “укладывать” полученные от сервера данные.

Пример секции связей:

[&OpcuaMon]
;*****************************************
;**** Link nodes with tags/curves/messages
;*****************************************
Link node WaveSin       with AnalogOutput 0 tag DEMO_OPCUAMON.WAVE.SIN       monitor 5000 message @DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data
Link node WaveCos       with AnalogOutput 1 tag DEMO_OPCUAMON.WAVE.COS       monitor 5000 message @DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data
Link node WaveAmplitude with                tag DEMO_OPCUAMON.WAVE.AMPLITUDE refresh 5000 message @DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data
Link node WaveFrequency with                tag DEMO_OPCUAMON.WAVE.FREQUENCY refresh 5000 message @DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data
Link node WaveNoise     with                tag DEMO_OPCUAMON.WAVE.NOISE     refresh 5000 message @DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data
Link node WaveStarted   with                tag DEMO_OPCUAMON.WAVE.STARTED   refresh 5000 message @DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data
Link node WaveSin       with AnalogInput  0 tag DEMO_OPCUAMON.TEST           trigger 5000 :y message @DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data
[]

Общий формат:

[&OpcuaMon]
Link node n with (Analog|Digital)(Input|Output) i tag t (monitor|polling|trigger|refresh) p y message m
[]
# n - псевдоним или индексный идентификатор узла OPCUA
# i - номер подключения (Аналог|Цифрового)(Ввода|Вывода)
# t - имя подключеннного к узлу тега
# p - период проверки/обновления данных, мс
# y - необязательный тип триггера (:x|:y|:t), по умолчанию :y
# m - сообщение c подстановкой $node (идентификатор узла),
#     $alias (псевдоним узла), $data (значение данных)

Параметры (Analog|Digital)(Input|Output) i, tag t, message m - необязательны.
Их можно не указывать, если они не нужны.

Наличие ключевых слов Link node … with … - строго обязательно, их порядок имеет значение.

Параметры Link node n with … (monitor|polling|trigger|refresh) p … строго обязательны.

Параметр node n задает псевдоним или (короткий) индексный идентификатор узла.
Рекомендуется всегда использовать псевдонимы - так будет легче понимать код.

Параметры (monitor|polling|trigger|refresh) p y задают способ опроса:

Заметим, что при указании периода опроса p=0 чтение/запись по таймеру отключается.
Это может быть полезно, чтобы читать/записывать данные только по (внешним) событиям.

При работе по внешним событиям чтение/запись инициируется командами:

Перейти к Содержанию


Объяснение режимов и триггеров

Для понимания работы монитора следует помнить, что монитор - клиент OPCUA - имеет лишь копию
данных, которыми владеет сервер. Поэтому клиент не может изменить данные сразу, вместо этого он
посылает серверу команду (запрос) на изменение данных на сервере. Затем, если сервер одобрил
изменения, обновленные данные приходят клиенту по подписке (либо считываются клиентом явно),
чтобы клиент обновил свою копию данных.

Режим monitor p с периодом таймера p является основным методом чтения (наблюдения) данных.
Для правильной работы на узел должна быть оформлена подписка на обновления @OpcBooking ….
Таймер p гарантирует, что чтение данных будет выполняться не реже p миллисекунд,
даже если сервер долго не обновляет данные. При нулевом значении p таймер отключается.
Нулевой таймер можно использовать для работы по событиям (посылкой явных команд чтения).
При работе монитор сохраняет прочитанные с сервера данные в подключенные кривые
(Analog|Digital)Output … и теги Tag ….

Пример:

# Чтение узла WaveSin по подписке, но не реже 5сек
Link node WaveSin with AnalogOutput 0 monitor 5000

Режим polling p с периодом таймера p является вспомогательным методом чтения редко изменяемых данных.
Таймер p обеспечивает чтение данных с периодом p миллисекунд, даже если нет подписки на обновления.
При нулевом значении p таймер отключается, автоматических обновлений при этом не происхоит.
Нулевой таймер можно использовать для работы по событиям (посылкой явных команд чтения).
При работе монитор сохраняет прочитанные с сервера данные в подключенные кривые
(Analog|Digital)Output … и теги Tag ….

Пример:

# Чтение узла WaveSin без подписки, раз в 5сек
Link node WaveSin with AnalogOutput 0 polling 5000

Режим trigger p y с периодом таймера p является основным методом записи (и наблюдения) данных.
Для правильной работы на узел должна быть оформлена подписка на обновления @OpcBooking ….
Таймер p гарантирует, что запись и чтение данных будет идти не реже p миллисекунд,
даже если сервер долго не обновляет данные. При нулевом значении p таймер отключается.
Нулевой таймер можно использовать для работы по событиям (посылкой явных команд записи/чтения).
Параметр y со значением по умолчанию :y задает источник триггера на запись.
Источник :y - триггер записи при изменении координаты y подключенной кривой (Analog|Digital)Input.
Источник :x - триггер записи при изменении координаты x подключенной кривой (Analog|Digital)Input.
Источник :t - триггер записи при изменении значения t подключенного тега.
При этом в подключенную кривую (Analog|Digital)Output … или тег Tag … идет сохранение
значений узла, прочитанных с сервера, аналогично режиму monitor p.

Пример:

# Запись/чтение узла WaveSin по триггеру :y, но не реже 5сек
Link node WaveSin with AnalogInput 0 tag Demo.WaveSin trigger 5000 :y

Режим refresh p y работает аналогично режиму trigger, только триггер на запись по
изменению значений не используется, а запись идет по таймеру p (или по внешним событиям).
Источник триггера играет роль только при подключении тега - он указывает, что при записи данные
следует брать из тега, если указано значение источника триггера :t.
При этом в подключенную кривую (Analog|Digital)Output … или тег Tag … идет сохранение
значений узла, прочитанных с сервера, аналогично режиму monitor p.

Пример:

# Запись/чтение узла WaveSin по таймеру 5сек
Link node WaveSin with AnalogInput 0 tag Demo.WaveSin refresh 5000 :y

Наконец, при указании нулевого таймера p чтение/запись ведется по событиям,
т.е. по сообщениям @OpcNodeRead …, @OpcNodeSend ….

Перейти к Содержанию


Задание секции StartMonitor

В этой секции описываются команды, вызываемые при старте монитора. Исполняются только команды, подходящие под шаблон StartMonitorPattern. Эти команды посылаются в консоль оболочки opcuamon.pas для выполнения.

Монитор стартует только после получения от мониторной программы opcuamon.py ключевой (триггерной) строки StartMonitorTrigger, а также после задержки на заданную величину DelayMonitorTrigger миллисекунд. Это нужно для правильного запуска мониторной программы, т.к. ей требуется некоторое время для проведения внутренней инициализации.

В секции старта монитора задаются параметры подключения к серверу OPCUA, а также оформляется подписка на обновление нужных для работы узлов. Затем делается старт цикла опроса монитора для начала обмена данными. Также, если нужно, делается запись начальных значений некоторых узлов.

Пример типичной секции старта монитора:

[&OpcuaMon.StartMonitor]                                        ; Start monitor actions:
@OpcAddress  opc.tcp://localhost:4840                           ; Set server address URL
@OpcBooking  /how=(monitor|trigger|refresh)/i                   ; Subscribe (monitor|trigger|refresh) nodes
@OpcSubInter 1                                                  ; Subscription update interval, ms
@UseShortKey 1                                                  ; Flag to use short node id
@OpcMonitor                                                     ; Start monitoring
@OpcNodeSend WaveStarted 1                                      ; Write node value
[]

Перейти к Содержанию


Комады оболочки opcuamon.pas

Ниже описаны команды консоли оболочки opcuamon.pas.

Следует специально отметить, что консоли оболочки opcuamon.pas и монитора opcuamon.py - это две разные консоли для двух разных программных потоков, из не надо путать друг с другом.

Перейти к Содержанию


Команда @OpcAddress url

Команда @OpcAddress url задает адрес URL для подключения сервера OPCUA.

Например:

@OpcAddress  opc.tcp://localhost:4840

Здесь 4840 - стандартный TCP порт OPCUA, зарегистрированный в IANA как OPC UA Connection Protocol. См. service-names-port-numbers.txt.

Имя сервера OPCUA следует задавать в самом начале, до старта монитора командой @OpcMonitor.

Перейти к Содержанию


Команда @OpcBooking pattern

Команда @OpcBooking pattern задает шаблон pattern (регулярное выражение) для подписки на обновления данных от сервера OPCUA.

Например:

@OpcBooking  /.*/i                              # подписка на все объявленные узлы
@OpcBooking  /Wave.*/i                          # подписка на все узлы с псевдонимами Wave*
@OpcBooking  /how=(monitor|trigger|refresh)/i   # подписка на узлы с типом опроса (monitor|trigger|refresh)

При подписке на данные сервер OPCUA будет присылать уведомлениия об изменении данных при их обновлении на стороне сервера.

При правильном конфигурировании обновления будут автоматически записываться в подключенные кривые или теги, а также будут посылаться сообщения, если они были указаны в конфигурации подключения узла.

Подписку на обновления данных сервера OPCUA следует делать до старта монитора командой @OpcMonitor.

Перейти к Содержанию


Команда @OpcMonitor

Команда @OpcMonitor запускает цикл опроса мониторной программы opcuamon.py. Перед запуском необходимо задать (как минимум) адрес сервера @OpcAddress и шаблоны для подписки узлов @OpcBooking.

Например:

@OpcMonitor   # запуск монитора

После запуска монитора должен начаться обмен данными с сервером OPCUA.

Перейти к Содержанию


Команда @OpcNodeRead node

Команда @OpcNodeRead node посылает мониторной программе opcuamon.py запрос на чтение узла node. В качестве имени узла задается псевдоним или индексный идентификатор узла.

Например:

@OpcNodeRead WaveSin    # чтение узла с псевдонимом WaveSin

Команда чтения используется, если надо прочитать конкретный узел досрочно. Это может быть узел, на который не была оформлена подписка, либо подписка была оформлена, но данные почему-то долго не обновлялись.

При успешном выполнении данные будут (через некоторое время) присланы сервером.

Команда чтения работает только после старта цикла опроса монитора.

Перейти к Содержанию


Команда @OpcNodeSend node value

Команда @OpcNodeSend node value посылает мониторной программе opcuamon.py запрос на запись в узел node значения value на стороне сервера OPCUA. В качестве имени узла node задается псевдоним или индексный идентификатор узла. Новое значение value передается в виде строки.

Например:

@OpcNodeSend WaveAmplitude 3.14    # запись в узел с псевдонимом WaveAmplitude значения 3.14

Команда записи используется, чтобы задать узлу (переменной на стороне сервера) новое значение.

При успешном выполнении данные будут (через некоторое время) обновлены на стороне сервера. Соответственно придет уведомление об изменении данных (если оформлена подписка). Надо, однако, быть готовым к тому, что сервер может отклонить изменение, если оно не разрешено, поэтому обновление данных может и не произойти.

Команда записи работает только после старта цикла опроса монитора.

Перейти к Содержанию


Команда @OpcInform topic

Команда @OpcInform topic печатает в консоли мониторной оболочки opcuamon.pas информацию на тему topic:

Пример вывода команды @OpcInform:

@opcinform
&OPCUAMON ! No topics specified.
&OPCUAMON : Available topics are:
&OPCUAMON :  Links - table of node links.
&OPCUAMON :  Alias - alias to node table.
&OPCUAMON :  Books - nodes booking table.
&OPCUAMON :  How   - node trig how table.
&OPCUAMON :  *     - all listed topics.
@opcinform *
&OPCUAMON : Alias to Node table:
 wavenoise     = ns2i2007
 wavesin       = ns2i2003
 wavecos       = ns2i2004
 wavefrequency = ns2i2006
 wavestarted   = ns2i2008
 waveamplitude = ns2i2005
&OPCUAMON : Table of Node links:
 wavenoise     - how=refresh 5000;tag=264;ali=wavenoise;nod=ns2i2007;msg=@DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data;
 wavesin       - how=monitor 5000;nao=0;tag=265;ali=wavesin;nod=ns2i2003;msg=@DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data;
 wavecos       - how=monitor 5000;nao=1;tag=266;ali=wavecos;nod=ns2i2004;msg=@DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data;
 wavefrequency - how=refresh 5000;tag=262;ali=wavefrequency;nod=ns2i2006;msg=@DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data;
 wavestarted   - how=refresh 5000;tag=261;ali=wavestarted;nod=ns2i2008;msg=@DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data;
 waveamplitude - how=refresh 5000;tag=263;ali=waveamplitude;nod=ns2i2005;msg=@DevPost &DEMO_OPCUAMON.MAIN.CTRL OpcData $alias $data;
&OPCUAMON : Nodes Booking table:
 wavenoise     = Booked
 wavesin       = Booked
 wavecos       = Booked
 wavefrequency = Booked
 wavestarted   = Booked
 waveamplitude = Booked
&OPCUAMON : Node Trig How table:
 wavenoise     = refresh
 wavesin       = monitor
 wavecos       = monitor
 wavefrequency = refresh
 wavestarted   = refresh
 waveamplitude = refresh

Перейти к Содержанию


Монитор opcuamon.py

Здесь описывается монитор opcuamon.py - клиент для наблюдения данных OPCUA.
Он написан на языке Python с использованием модулей asyncua и pycrwkit.

Монитор opcuamon.py используется в готовом виде, “как есть”.
Всё конфигурирование происходит на уровне оболочки opcuamon.pas.

Перейти к Содержанию


Вызов программы opcuamon.py

Программа opcuamon.py вызывается командами:

unix pyvenv opcuamon.py                                 # простой вызов без параметров
unix pyvenv opcuamon.py -u opc.tcp://localhost:4840     # вызов с указанием адреса сервера
unix pyvenv opcuamon.py --url opc.tcp://localhost:4840  # вызов с указанием адреса сервера

Команда unix pyvenv … вызывает программу в (правильном) виртуальном окружении.
Необязательная опция -u или --url задает адрес сервера для подключения.
Сервер подключения может быть задан позже командой @OpcServAddr.

Перейти к Содержанию


Команды и сообщения opcuamon.py

Ниже описаны команды консоли мониторной программы opcuamon.py.

Следует специально отметить, что консоли оболочки opcuamon.pas и монитора opcuamon.py - это две разные консоли для двух разных программных потоков, из не надо путать друг с другом.

Управление программой opcuamon.py и обмен данными идет с помощью консольных команд, посылаемых клиентом в поток stdin и ответных сообщений от программы в потоке stdout. Формат команд и сообщений - текстовый, в кодировке utf8, с обычным разделением на строки с помощью разделителя строк EOL, равного LF под Unix или CRLF под Windows.

Команды задаются в формате DaqScript:

Пример команд:

@Help           # команда без аргументов
@Exit 1         # команда с аргументом 1

Перейти к Содержанию


Команда @Help

Печатает справку по командам.

@help
 @Help             -  print this help
 @Exit n           -  exit with code n
 @PingEcho s       -  print echo (for testing)
 @PollCount        -  print polling loop counter
 @PollPeriod n     -  set polling loop period n ms
 @TermOnError n    -  terminate on error flag (0/1)
 @Memory           -  get process memory rss,vms
 @OpcDataBook n    -  subscribe data change of node (n), like ns=2;i=13 or ns2i13
 @OpcServAddr u    -  get/set server address URL (u), like opc.tcp://localhost:4840
 @UseShortKey f    -  flag (0/1) to use short key (ns2i13 instead of ns=2;i=13)
 @OpcSubInter p    -  subscription interval (period) ms, default is 100
 @OpcStartMon      -  start monitor to view subscribed nodes data
 @OpcDataVary n v  -  notification on node (n) changed to value (v)
 @OpcGotEvent e    -  notification on got event (e)
 @OpcDataSend n v  -  write node (n) value (v)
 @OpcDataRead n    -  read node (n) value

Перейти к Содержанию


Команда @Exit n

Команда @Exit n завершает программу с кодом выхода n. Код выхода необязателен, по умолчанию 0.

Ответное сообщение: @Exit n - уведомляет о выполнении команды.

Перейти к Содержанию


Команда @PingEcho s

Команда @PingEcho s выводит в консоль эхо - т.е. саму себя. Применяется для проверки связи (ping) и измерения времени отклика.

Ответное сообщение: @PingEcho s - уведомляет о выполнении команды.

Перейти к Содержанию


Команда @PollCount

Команда @PollCount используется для чтения счетчика циклов. Счетчик циклов служит для оценки частоты цикла опроса команд и сообщений.

Ответное сообщение: @PollCount n - возвращает значение счетчика циклов n.

Перейти к Содержанию


Команда @PollPeriod n

Команда @PollPeriod n используется для чтения/записи периода опроса n цикла опроса команд и сообщений. При отсутствии аргумента происходит чтение, при наличии - запись и чтение периода опроса.

Ответное сообщение: @PollPeriod n - возвращает значение периода опроса n в миллисекундах (мс).

Начальное значение периода опроса - 4 мс.

Перейти к Содержанию


Команда @TermOnError n

Команда @TermOnError n читает/задает флаг n = (0/1) для обработки ошибок. Если флаг установлен, при ошибках (исключениях) программа прекращает выполнение.

Ответное сообщение: @TermOnError n - возвращает значение флага.

Начальное значение флага - 0.

Перейти к Содержанию


Команда @Memory

Команда @Memory используется для чтения счетчиков памяти.

Ответное сообщение: @Memory rss=R; vms=V; gc=G - возвращает значение счетчика резидентной памяти R и виртуальной памяти V в байтах, а также счетчиков “сборщика мусора” (garbage collection) G.

Счетчики сборщика мусора имеет формат gc=ge,go,g0,g1,g2,gg:

Перейти к Содержанию


Команда @OpcDataBook n

Команда @OpcDataBook n служит для подписки узла (node) с идентификатором n на уведомления об изменении значения.
Идентификатор n задается в полной форме вида (например) ns=2;i=13 или короткой форме ns2i13.

Здесь:

Ответное сообщение: @OpcDataBook n - уведомляет о выполнении команды.

Подписка должна выполняться (строго) до старта монитора командой @OpcStartMon.

В результате подписка сервер OPCUA будет посылать уведомления @OpcDataVary n v про каждом изменении данных узла n на значение v.

Перейти к Содержанию


Команда @OpcServAddr u

Команда @OpcServAddr u читает/задает адрес u сервера в виде URL,
например @OpcServAddr opc.tcp://localhost:4840.

Ответное сообщение: @OpcServAddr u - возвращает адрес сервера u.

Перейти к Содержанию


Команда @UseShortKey f

Команда @UseShortKey f читает/задает флаг f = (0/1) для формата печати идентификаторов узлов.
Если флаг установлен, при печати используется короткий формат (ns2i13 вместо ns=2;i=13).

Ответное сообщение: @UseShortKey f - возвращает значение флага.

Начальное значение флага - 0.

Перейти к Содержанию


Команда @OpcSubInter p

Команда @OpcSubInter p читает/задает интервал (период) опроса p для проверки обновления подписки узлов (subscription interval).
Этот интервал определяяет частоту (периодичность) обновления данных на стороне клиента.

Данные клиента будут обновляться с учетом двух факторов:

Другими словами, клиент будет получать обновления данных по факту изменения данных на стороне сервера, но не чаще интервала обновления.

Например, при значении @OpcSubInter 1000 (интервал одна секунда) обновления будут приходить с периодичностью раз в секунду - но только для тех узлов, которые изменились за эту секунду.

Ответное сообщение: @OpcSubInter p - возвращает значение интервала обновления подписки.

Начальное значение интервала подписки - 100.

Для получения максимальной частоты обновления используйте интервал обновления @OpcSubInter 1.
В этом случае обновление данных на стороне клиента будет максимально приближено к обновлению данных на сервере.

Значение интервала обновления должно быть задано командой @OpcSubInter ДО старта монитора командой @OpcStartMon. Попытка изменения интервала обновления после старта монитора будет (молча) проигнорирована.

Перейти к Содержанию


Команда @OpcStartMon

Команда @OpcStartMon стартует монитор, т.е. начинает обмен данными, на которые была оформлена подписка.
После старта монитора оформлять новые подписки уже нельзя вплоть до перезапуска программы монитора.

Ответное сообщение: @OpcStartMon s - возвращает статус монитора s = (0|1).

Перейти к Содержанию


Сообшение @OpcDataVary n v

Сообшение @OpcDataVary n v посылается при получении от сервера обновления узла с идентификатором n с новым значением v.
Это сообщение является основным способом передачи данных от сервера при их изменении.

Клиент должен обновлять свои (локальные) копии данных при получении этого сообщения.

Перейти к Содержанию


Сообшение @OpcGotEvent e

Сообшение @OpcGotEvent e посылается при получении от сервера события e.

Клиент должен выполнять обратотку событий при получении этого сообщения.

Перейти к Содержанию


Сообшение @Error class e - m

Сообшение @Error class e - m посылается при возникновении ошибки (исключения) класса e с сообщением m.
При этом программа может продолжить выполнение, если исключение было перехвачено и обработано.
Но возможны и фатальные ошибки, при которых программа прекращает работу.

Клиент должен выполнять обработку ошибок при получении этого сообщения.

Перейти к Содержанию


Команда @OpcDataSend n v

Команда @OpcDataSend n v посылается для записи в узел с идентификатором n значения v.
Сервер должен выполнить запись данных узла при получении этой команды.
Команда работает только после старта монитора командой @OpcStartMon.

Ответное сообщение: @OpcDataSend n v - уведомляет о выполнении команды.

Перейти к Содержанию


Команда @OpcDataRead n

Команда @OpcDataRead n инициирует непоследственное (без подписки) чтение значения узла с идентификатором n.
Используется для чтения редко изменяемых данных без подписки, либо для досрочного чтения данных.
Команда работает только после старта монитора командой @OpcStartMon.

Ответное сообщение: @OpcDataRead n v - возвращает идентификатор узла n и его значение v.

Перейти к Содержанию


Пример сеанса работы opcuamon.py

Здесь приведен пример сеанса работы opcuamon.py с указанием направления передачи:

> Start opcuamon.
> Type '@Exit' to terminate.
> Type '@Help' to show help.
> Welcome to opcuamon program.
< @OpcServAddr opc.tcp://localhost:4840
< @OpcDataBook ns2i13
< @OpcDataBook ns2i14
< @OpcDataBook ns2i15
< @OpcDataBook ns2i16
< @OpcStartMon
< @UseShortKey 1
> @OpcServAddr opc.tcp://localhost:4840
> @OpcDataBook ns=2;i=13
> @OpcDataBook ns=2;i=14
> @OpcDataBook ns=2;i=15
> @OpcDataBook ns=2;i=16
> @OpcStartMon 1
> @UseShortKey 1
> @OpcNodeId ns2i13 ns=2;i=13 MyVariable 0:Root/0:Objects/2:MyObject/2:MyVariable
> @OpcNodeId ns2i14 ns=2;i=14 MyStringVariable 0:Root/0:Objects/2:MyObject/2:MyStringVariable
> @OpcNodeId ns2i15 ns=2;i=15 MyDateTimeVar 0:Root/0:Objects/2:MyObject/2:MyDateTimeVar
> @OpcNodeId ns2i16 ns=2;i=16 myarrayvar 0:Root/0:Objects/2:MyObject/2:myarrayvar
> Try to subscribe 4 items
> @OpcDataVary ns2i13 0.791247236619192
> @OpcDataVary ns2i14 Really nice string
> @OpcDataVary ns2i15 2025-03-27 15:46:27.569819+00:00
> @OpcDataVary ns2i16 [6.7, 7.9, 9.3]
> @OpcDataVary ns2i13 0.7258003090504381
> @OpcDataVary ns2i13 0.6531284185627572
> @OpcDataVary ns2i13 0.5735154919086519
> @OpcDataVary ns2i13 0.48857180253009197
> @OpcDataVary ns2i13 0.3987087773532503
> @OpcDataVary ns2i13 0.30449508639881023
> @OpcDataVary ns2i13 0.20728769690795765
< @OpcDataSend ns2i13 123
< @OpcDataSend ns2i14 Test string
< @OpcDataSend ns2i15 2025-03-26 07:00:0.0+00:00
< @OpcDataSend ns2i16 [3.14, 1.23, 4.56]
< @OpcDataSend ns2i13 456.789
< @OpcDataSend ns2i14 Demo string
< @OpcDataSend ns2i15 2025-03-26 12:59:0.0+00:00
< @OpcDataSend ns2i16 [1.23, 4.56, 7.89]
< @OpcDataRead ns2i13
< @OpcDataRead ns2i14
< @OpcDataRead ns2i15
< @OpcDataRead ns2i16
> @OpcDataSend ns2i13 123.0
> @OpcDataVary ns2i13 123.0
> @OpcDataSend ns2i14 Test string
> @OpcDataVary ns2i14 Test string
> @OpcDataVary ns2i13 -0.6900187558595284
> @OpcDataSend ns2i15 2025-03-26T07:00:00+00:00
> @OpcDataVary ns2i15 2025-03-26 07:00:00+00:00
> @OpcDataSend ns2i16 [3.14, 1.23, 4.56]
> @OpcDataVary ns2i16 [3.14, 1.23, 4.56]
> @OpcDataSend ns2i13 456.789
> @OpcDataVary ns2i13 456.789
> @OpcDataSend ns2i14 Demo string
> @OpcDataVary ns2i14 Demo string
> @OpcDataSend ns2i15 2025-03-26T12:59:00+00:00
> @OpcDataVary ns2i15 2025-03-26 12:59:00+00:00
> @OpcDataSend ns2i16 [1.23, 4.56, 7.89]
> @OpcDataVary ns2i16 [1.23, 4.56, 7.89]
> @OpcDataRead ns2i13 456.789
> @OpcDataRead ns2i14 Demo string
> @OpcDataRead ns2i15 2025-03-26 12:59:00+00:00
> @OpcDataRead ns2i16 [1.23, 4.56, 7.89]
> @OpcDataVary ns2i13 -0.7590365345154336
> @OpcDataVary ns2i13 -0.8208951663911515
> @OpcDataVary ns2i13 -0.8743369438809138
> @OpcDataVary ns2i13 -0.9187194413555398
> @OpcDataVary ns2i13 -0.9536834786091303
> @OpcDataVary ns2i13 -0.9790187032613554
> @OpcDataVary ns2i13 -0.9945377947002254
> @OpcDataVary ns2i13 -0.9999921378527783
> @OpcDataVary ns2i13 -0.9953108072529953
> @OpcDataVary ns2i13 0.8101942492046739
> @OpcDataVary ns2i13 0.8648789373357433
> @OpcDataVary ns2i13 0.9110046688589891
< @Exit
> Program terminated. Press Enter to exit.
> @Exit 0

Желаем успешного использования opcuamon.


CRW-DAQ Copyright (c) 2001-2025 Alexey Kuryakin