Содержание
Здесь описывается монитор
opcuamon, являющийся клиентом OPCUA
общего назначения для пакета crwdaq.
Монитор обеспечивает обмен данными между пакетом crwdaq
и сервером OPCUA, к которому он подключается.
Монитор состоит из:
Сначала ознакомьтесь с терминологией
OPCUA.
Затем узнайте как работает
монитор.
См. также заметки по
OPCUA.
См. также сервер opcuasrv.
opc.tcp://localhost:4840.http://opcfoundation.org. Обычно
используются имена, похожиеns=2;i=2003 по шаблону
/^ns=(\d+);(i=\d+)$/i./^ns=(\d+);(i=\d+|s=\S+|g=\S+)$/i.ns=2;i=2003 или
ns=2;s=Tag321.ns2i2003 по шаблону
/^ns(\d+)(i\d+)$/i,/^ns(\d+)(i\d+|s\S+|g\S+)$/i.ns2i2003 или
ns2sTag321.Псевдонимы используются в программе монитора OpcuaMon для понятности и читабельности, при выполнении программы псевдонимы автоматически заменяются на соответствующие индексы узлов. Псевдонимы должны быть простыми именами по правилам Pascal и не должны быть идентификаторами узлов, т.к. весь смысл псевдонимов состоит в замене nodeId на понятное (для программистов) читабельное имя.
Программа opcuamon.py
используется в готовом виде, “как есть”.
Всё конфигурирование происходит на уровне оболочки opcuamon.pas.
Оболочка полностью отвечает за интеграцию монитора в пакет crwdaq.
Для использования монитора нужно правильно сконфигурировать оболочку
opcuamon.pas.
При конфигурировании описываются подключения узлов
OPCUA к кривым и тегам пакета crwdaq,
а также способы их опроса/обновления.
@OpcuaNodeRead.@OpcuaNodeSend.Работая с программами монитора (клиента) opcuamon и сервера opcuasrv всегда надо помнить, что в клиент-серверных программах всегда есть несколько копий данных:
В нормальной ситуации сервер и клиент стараются синхронизовать (обновлять) данные как можно скорее, чтобы все копии данных соответствовали оригиналу (исходным данным сервера). Однако, поскольку сервер и клиент работают в разных процессах, а приемник и передатчик - в разных потоках, всегда существуют задержки с обновлениями, а потому эти четыре копии данных могут отличаться друг от друга. Больше того, в некоторых ситуациях копии гарантированно отличаются. Например, когда клиент инициирует команду записи, заранее предполагается, что текущая копия данных клиента отличается от (желаемых) данных сервера. Целью записи является именно сстремление изменить данные сервера, чтобы затем сервер, прислав обновление клиенту, изменил копию данных клиента на желаемое значение.
В нашем случае имеется четыре возможные копии данных:
Для понимания работы программ opcuasrv и opcuamon необходимо понимать, что всякое изменение данных происходит путем последовательного изменения (синхронизации) указанных копий данных.
Например, если клиент вызывал команду
@OpcNodeSend WaveStarted 1, происходит
примерно следующее:
@OpcDataSend node 1В случае подключения к другому (внешнему) серверу OPCUA вместо серверной программы opcuasrv.py и её оболочки opcuasrv.pas будет выступать внешний сервер (например, SCADA). Но логика остается примерно такой же. Понимание этой логики (наличие нескольких копий данных и синхронизация между ними) позволит избежать ошибок.
Оболочка монитора opcuamon.pas содержит программу DaqPascal, которая отвечает за приемопередачу данных OPCUA от монитора opcuamon.py на стороне пакета crwdaq. Задачей оболочки opcuamon.pas является интеграция монитора в пакет crwdaq, включая функции запуска остановки, конфигурирования и обмена данными с мониторной программой opcuamon.py.
Конфигурирование 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, чтобы была возможность изучать статистику её работы. При необходимости статистика извлекается из строки.
В этих секциях описываются действия при старте и завершении работы
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
задают способ опроса:
monitor p - читать данные по подписке, но при
отсутствии обновлений читать данные по запросу с периодом
p миллисекунд.
Для правильной работы должна быть оформлена подписка на данный
узел.
Это основной режим работы монитора для наблюдения данных.
Для этого способа опроса узла запись запрещена.
При попытке записи узла регистрируется ошибка.
polling p - читать данные по явному клиентскому
запросу с периодом p миллисекунд.
Этот метод подходит для чтения редко изменяемых данных без оформления
подписки.
Для этого способа опроса узла запись запрещена.
При попытке записи узла регистрируется ошибка.
trigger p y - запись данных по
триггеру (при изменении входных данных), но при отсутствии
изменений
делать запись по таймеру с периодом не реже p
миллисекунд. При этом учитывается источник
триггера,
который указывает, что именно (абсцисса или ордината кривой или значение
тега) считается триггером.
При этом чтение значений узла также происходит (аналогично режиму
monitor).
Необязательный параметр y задает источник триггера на
запись:
refresh p y - запись данных по таймеру с
периодом p миллисекунд без анализа изменений.
При этом чтение значений узла также происходит (аналогично режиму
monitor).
Этот метод подходит для записи редко изменяемых данных.
Заметим, что при указании периода опроса p=0
чтение/запись по таймеру отключается.
Это может быть полезно, чтобы читать/записывать данные только по
(внешним) событиям.
При работе по внешним событиям чтение/запись инициируется командами:
@OpcNodeRead n - чтение с сервера
значения узла n,@OpcNodeSend n v - запись значения
v в узле n,Для понимания работы монитора следует помнить, что монитор - клиент
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 ….
В этой секции описываются команды, вызываемые при старте монитора. Исполняются только команды, подходящие под шаблон 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
[]opc.tcp://localhost:4840./.*/ задает все узлы,
/Wave.*/i - псевдонимы, начинающиеся на
Wave,/how=monitor/i - все узлы с атрибутом
опроса в режиме monitor.Ниже описаны команды консоли оболочки opcuamon.pas.
Следует специально отметить, что консоли оболочки opcuamon.pas и монитора opcuamon.py - это две разные консоли для двух разных программных потоков, из не надо путать друг с другом.
Команда @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 задает
шаблон pattern (регулярное выражение) для подписки на
обновления данных от сервера OPCUA.
Например:
@OpcBooking /.*/i # подписка на все объявленные узлы
@OpcBooking /Wave.*/i # подписка на все узлы с псевдонимами Wave*
@OpcBooking /how=(monitor|trigger|refresh)/i # подписка на узлы с типом опроса (monitor|trigger|refresh)При подписке на данные сервер OPCUA будет присылать уведомлениия об изменении данных при их обновлении на стороне сервера.
При правильном конфигурировании обновления будут автоматически записываться в подключенные кривые или теги, а также будут посылаться сообщения, если они были указаны в конфигурации подключения узла.
Подписку на обновления данных сервера OPCUA следует
делать до старта монитора командой
@OpcMonitor.
Команда @OpcMonitor запускает цикл
опроса мониторной программы opcuamon.py. Перед запуском
необходимо задать (как минимум) адрес сервера @OpcAddress и
шаблоны для подписки узлов @OpcBooking.
Например:
@OpcMonitor # запуск монитораПосле запуска монитора должен начаться обмен данными с сервером OPCUA.
Команда @OpcNodeRead node посылает
мониторной программе opcuamon.py запрос на чтение узла
node. В качестве имени узла задается псевдоним или
индексный идентификатор узла.
Например:
@OpcNodeRead WaveSin # чтение узла с псевдонимом WaveSinКоманда чтения используется, если надо прочитать конкретный узел досрочно. Это может быть узел, на который не была оформлена подписка, либо подписка была оформлена, но данные почему-то долго не обновлялись.
При успешном выполнении данные будут (через некоторое время) присланы сервером.
Команда чтения работает только после старта цикла опроса монитора.
Команда @OpcNodeSend node value
посылает мониторной программе opcuamon.py запрос на
запись в узел node значения value на
стороне сервера OPCUA. В качестве имени узла
node задается псевдоним или индексный идентификатор
узла. Новое значение value передается в виде
строки.
Например:
@OpcNodeSend WaveAmplitude 3.14 # запись в узел с псевдонимом WaveAmplitude значения 3.14Команда записи используется, чтобы задать узлу (переменной на стороне сервера) новое значение.
При успешном выполнении данные будут (через некоторое время) обновлены на стороне сервера. Соответственно придет уведомление об изменении данных (если оформлена подписка). Надо, однако, быть готовым к тому, что сервер может отклонить изменение, если оно не разрешено, поэтому обновление данных может и не произойти.
Команда записи работает только после старта цикла опроса монитора.
Команда @OpcInform topic печатает в
консоли мониторной оболочки opcuamon.pas информацию на
тему topic:
@OpcInform - выдает справку (список
тем),@OpcInform * - выдает информацию по
всем темам,@OpcInform Alias - выдает список
псевдонимов,a = n, где@OpcInform Links - выдает список
связей узлов с хранилищем данных и атрибутами,a - how=…;ttr=…;ali=…;nai=…;ndi=…;nao=…;ndo=…;tag=…;msg=…;,
где$alias, узла
$node и значения данных
$data.@OpcInform Books - список подписок на
обновление данных,a = booked, где
a - псевдоним узла.@OpcInform how - выдает тип триггера
для каждого узла.Пример вывода команды @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 - клиент для
наблюдения данных OPCUA.
Он написан на языке Python с использованием модулей
asyncua и pycrwkit.
Монитор opcuamon.py используется в готовом виде,
“как есть”.
Всё конфигурирование происходит на уровне оболочки
opcuamon.pas.
Программа 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.pas и монитора opcuamon.py - это две разные консоли для двух разных программных потоков, из не надо путать друг с другом.
Управление программой opcuamon.py и обмен данными идет с помощью консольных команд, посылаемых клиентом в поток stdin и ответных сообщений от программы в потоке stdout. Формат команд и сообщений - текстовый, в кодировке utf8, с обычным разделением на строки с помощью разделителя строк EOL, равного LF под Unix или CRLF под Windows.
Команды задаются в формате DaqScript:
@,@ следует непустой
идентификатор команды,Пример команд:
@Help # команда без аргументов
@Exit 1 # команда с аргументом 1Печатает справку по командам.
@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 завершает программу с
кодом выхода n. Код выхода необязателен, по умолчанию
0.
Ответное сообщение: @Exit n -
уведомляет о выполнении команды.
Команда @PingEcho s выводит в консоль
эхо - т.е. саму себя. Применяется для проверки связи
(ping) и измерения времени отклика.
Ответное сообщение: @PingEcho s -
уведомляет о выполнении команды.
Команда @PollCount используется для
чтения счетчика циклов. Счетчик циклов служит для оценки частоты цикла
опроса команд и сообщений.
Ответное сообщение: @PollCount n -
возвращает значение счетчика циклов n.
Команда @PollPeriod n используется для
чтения/записи периода опроса n цикла опроса команд и
сообщений. При отсутствии аргумента происходит чтение, при наличии -
запись и чтение периода опроса.
Ответное сообщение: @PollPeriod n -
возвращает значение периода опроса n в миллисекундах
(мс).
Начальное значение периода опроса - 4 мс.
Команда @TermOnError n читает/задает
флаг n = (0/1) для обработки ошибок. Если флаг
установлен, при ошибках (исключениях) программа прекращает
выполнение.
Ответное сообщение: @TermOnError n -
возвращает значение флага.
Начальное значение флага - 0.
Команда @Memory используется для чтения
счетчиков памяти.
Ответное сообщение:
@Memory rss=R; vms=V; gc=G - возвращает
значение счетчика резидентной памяти R и виртуальной
памяти V в байтах, а также счетчиков “сборщика
мусора” (garbage collection) G.
Счетчики сборщика мусора имеет формат gc=ge,go,g0,g1,g2,gg:
Команда @OpcDataBook n служит для
подписки узла (node) с идентификатором n на
уведомления об изменении значения.
Идентификатор n задается в полной форме вида (например)
ns=2;i=13 или короткой форме
ns2i13.
Здесь:
Ответное сообщение: @OpcDataBook n -
уведомляет о выполнении команды.
Подписка должна выполняться (строго) до старта монитора командой
@OpcStartMon.
В результате подписка сервер OPCUA будет посылать
уведомления @OpcDataVary n v про каждом
изменении данных узла n на значение
v.
Команда @OpcServAddr u читает/задает
адрес u сервера в виде URL,
например
@OpcServAddr opc.tcp://localhost:4840.
Ответное сообщение: @OpcServAddr u -
возвращает адрес сервера u.
Команда @UseShortKey f читает/задает
флаг f = (0/1) для формата печати идентификаторов
узлов.
Если флаг установлен, при печати используется короткий формат
(ns2i13 вместо
ns=2;i=13).
Ответное сообщение: @UseShortKey f -
возвращает значение флага.
Начальное значение флага - 0.
Команда @OpcSubInter p читает/задает
интервал (период) опроса p для проверки обновления
подписки узлов (subscription interval).
Этот интервал определяяет частоту (периодичность) обновления данных на
стороне клиента.
Данные клиента будут обновляться с учетом двух факторов:
Другими словами, клиент будет получать обновления данных по факту изменения данных на стороне сервера, но не чаще интервала обновления.
Например, при значении
@OpcSubInter 1000 (интервал одна секунда)
обновления будут приходить с периодичностью раз в секунду - но только
для тех узлов, которые изменились за эту секунду.
Ответное сообщение: @OpcSubInter p -
возвращает значение интервала обновления подписки.
Начальное значение интервала подписки - 100.
Для получения максимальной частоты обновления используйте интервал
обновления @OpcSubInter 1.
В этом случае обновление данных на стороне клиента будет максимально
приближено к обновлению данных на сервере.
Значение интервала обновления должно быть задано командой @OpcSubInter ДО старта монитора командой @OpcStartMon. Попытка изменения интервала обновления после старта монитора будет (молча) проигнорирована.
Команда @OpcStartMon стартует монитор,
т.е. начинает обмен данными, на которые была оформлена подписка.
После старта монитора оформлять новые подписки уже нельзя вплоть до
перезапуска программы монитора.
Ответное сообщение: @OpcStartMon s -
возвращает статус монитора s = (0|1).
Сообшение @OpcDataVary n v посылается
при получении от сервера обновления узла с идентификатором
n с новым значением v.
Это сообщение является основным способом передачи данных от сервера при
их изменении.
Клиент должен обновлять свои (локальные) копии данных при получении этого сообщения.
Сообшение @OpcGotEvent e посылается при
получении от сервера события e.
Клиент должен выполнять обратотку событий при получении этого сообщения.
Сообшение @Error class e - m посылается
при возникновении ошибки (исключения) класса e с
сообщением m.
При этом программа может продолжить выполнение, если исключение было
перехвачено и обработано.
Но возможны и фатальные ошибки, при которых программа прекращает
работу.
Клиент должен выполнять обработку ошибок при получении этого сообщения.
Команда @OpcDataSend n v посылается для
записи в узел с идентификатором n значения
v.
Сервер должен выполнить запись данных узла при получении этой
команды.
Команда работает только после старта монитора командой @OpcStartMon.
Ответное сообщение: @OpcDataSend n v -
уведомляет о выполнении команды.
Команда @OpcDataRead n инициирует
непоследственное (без подписки) чтение значения узла с идентификатором
n.
Используется для чтения редко изменяемых данных без подписки, либо для
досрочного чтения данных.
Команда работает только после старта монитора командой @OpcStartMon.
Ответное сообщение: @OpcDataRead n v -
возвращает идентификатор узла n и его значение
v.
Здесь приведен пример сеанса работы opcuamon.py с указанием направления передачи:
< - ввод команд в поток
stdin программы opcuamon.py,> - вывод сообщений программы
opcuamon.py в поток stdout,> 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 daqgroup@mail.ru