Модулі/OPC UA - OpenSCADAWiki

# Модулі/OPC UA

This page is a translated version of the page Modules/OPC UA and the translation is 100% complete.

English • ‎mRussian • ‎Українська

Модуль | Ім'я | Версія | Ліцензія | Джерело | Мови | Платформи | Тип | Автор
--- | --- | --- | --- | --- | --- | --- | --- | ---
OPC_UA | Клієнт OPC-UA | 2.10 | GPL2 | daq_OPC_UA.so | en,uk,ru,de | x86,x86_64,ARM | Збір Даних | Роман Савоченко
Опис
Надає реалізацію OPC-UA клієнтського сервісу.
OPC_UA | Сервер OPC-UA | 2.3 | GPL2 | daq_OPC_UA.so | en,uk,ru,de | x86,x86_64,ARM | Протокол | Роман Савоченко
Опис
Надає реалізацію OPC-UA сервісу серверу.
OPC_UA | Бібліотека реалізації OPC-UA у OpenSCADA | 2.3 | LGPL3 | libOPC_UA.{h,cpp} | en | x86,x86_64,ARM | Бібліотека | Роман Савоченко
Опис
Надає реалізацію протоколу OPC-UA в частині клієнта та серверу, у вигляді окремої бібліотеки. Загальна працемісткість: > 50 ЛД[!] Спонсорування, 2 роки ТП на 13 ЛД[!]: Дмитро Ликов, ТОВ Вектор Спонсорування, перенесення коду протоколу до LGPL бібліотеки, значного вдосконалення та документування на 8.4 ЛД[!]: Олександр Леута, MYSCADA Спонсорування, роботу з UAExpert 1.4 та kepware2 на 0.9 ЛД[!]: Устьянцев Михайло Спонсорування, роботу з UAExpert 1.5, реалізації клієнтського Publish та Chunks, значної уніфікації, підтримки Логічного Рівня та цілковитої ревізії документу на 10.4 ЛД[!]: Фонд Задача розширення модуля Завдання (To Do): - додати автоматичне створення вхідних транспортів та їх пре-конфігурацію із властивостей об'єкту КінцевогоВузла; - детально переглянути сервіс Publish щодо втрати пакетів та надсилання запиту Republish; - додати підтримку сервісу історії серверної частини, дивлячись та тестуючи спільно із обміном UAExpert; - додати підтримку сервісу історії клієнтської частини.

OPC (OLE for Process Control) — це сімейство протоколів та технологій, які надають єдиний інтерфейс для управління об'єктами автоматизації та технологічними процесами. Створення та підтримку специфікацій OPC координує міжнародна некомерційна організація OPC Foundation, яку створено у 1994 році провідними виробниками засобів промислової автоматизації.

У зв'язку з тим, що значний вплив у організації OPC Foundation має корпорація Microsoft, протоколи OPC до останнього часу були одноплатформними та закритими, з причини прив'язки до закритих технологій MS Windows. Однак, з недавніх пір, організацією OPC Foundation було створено такі багатоплатформні рішення, як OPC XML-DA та OPC-UA. Найбільший інтерес з них представляє OPC-UA, як уніфікуючий всі протоколи ранніх версій у межах відкритих та багатоплатформних технологій.

Цей модуль реалізує підтримку інтерфейсу та протоколу OPC-UA як у вигляді клієнтського сервісу, так і у вигляді серверу OPC-UA. Клієнтський сервіс OPC-UA реалізується однойменним модулем підсистеми "Збір даних", а сервер реалізується модулем підсистеми "Протоколи". Весь код реалізації цим модулем специфіки протоколу OPC-UA було винесено, за проханням користувачів, у окрему бібліотеку, яка розповсюджується під ліцензією LGPL3.

Поточною версією цих модулів та бібліотеки реалізуються бінарна частина протоколу та базові сервіси у небезпечному режимі та безпечних режимах політик "Base128Rsa15" та "Base256". Надалі планується реалізація решти сервісів OPC-UA, за потреби.

Хоча протокол OPC-UA і є багатоплатформним, його специфікація та SDK не є вільно-доступними, а надаються тільки членам організації OPC Foundation. З цієї причини реалізація даних модулів стикнулася зі значними перепонами та проблемами.

По перше, протокол OPC-UA складний та реалізація його взагалі без специфікації дуже працемістка. З цієї причини роботи над даними модулями тривалий час не починалися, та лише завдяки спонсорській допомозі однієї із організацій-члену OPC Foundation, проєкт OpenSCADA отримав документацію специфікації. При цьому SDK та вихідні тексти ANSIC-API протоколу OPC-UA отримано не було з причини несумісності їх ліцензії із GPL та, як наслідок, потенційної загрози порушення ліцензії при роботі із вихідними текстами, що могло призвести до подальших юридичних проблем при вільному розповсюджені цих модулів.

По друге, навіть наявність специфікації не дозволяє вирішити низку технічних питань без прикладів реалізації та можливості перевірки на робочому прототипі клієнта та сервера OPC-UA. Наприклад, саме технічні особливості реалізації алгоритмів симетричного шифрування та отримання ключів для них не дозволили реалізувати підтримку політик безпеки одразу.

Для налагодження функціювання модулів використовувалося демонстраційне ПЗ фірми Unified Automation, у складі OPC-UA клієнту — UAExpert та серверу — "OPC-UA Demo Server", із пакету SDK. У зв'язку із постійним розвитком самого клієнту "UAExpert", у плані інтерпретації специфікації OPC-UA, нові його версії часто мають проблеми при роботі із сервером OPC-UA від OpenSCADA. В цілому, результати сумісності роботи із клієнтами та серверами різних виробників можна отримати у таблиці сумісності.

## 1 Протокол OPC-UA

OPC-UA — це платформо-незалежний стандарт, за допомогою якого системи та пристрої різного типу можуть взаємодіяти шляхом відправки повідомлень між клієнтом та сервером через різноманітні типи мереж. Протокол підтримує безпечну взаємодію шляхом валідації клієнтів та серверів, а також протидії атакам. OPC-UA визначає поняття Сервіси, які сервери можуть надавати, а також сервіси, які сервер підтримує для клієнту. Інформація передається у вигляді типів даних, визначених OPC-UA та виробником, крім того сервера визначають об'єктну модель, для якої клієнти можуть здійснювати динамічний огляд.

OPC-UA надає поєднання інтегрованого адресного простору та сервісної моделі. Це дозволяє серверу інтегрувати дані, порушення (Alarms), повідомлень (Events) та історію у цьому адресному просторі, а також надавати доступ до них за посередництвом інтегрованих сервісів. Сервіси також надають інтегровану модель безпеки.

OPC-UA дозволяє серверам надавати для клієнтів визначення типів, для доступу до об'єктів із адресного простору. OPC-UA допускає надання даних у різних форматах, включаючи бінарні структури та XML-документи. Через адресний простір клієнти можуть запитати у сервера метадані, які описують формат даних.

OPC-UA додає підтримку множинної зв'язності між вузлами замість простого обмеження ієрархічністю. Така гнучкість, у комбінації із визначенням типів, дозволяє застосовувати OPC-UA для вирішення задач широкого спектру проблем.

OPC-UA спроєктовано для забезпечення надійної видачі даних. Основна особливість всіх OPC серверів — спроможність видавати данні та події.

OPC-UA спроєктовано для підтримки широкого діапазону серверів, від простіших ПЛК до промислових серверів. Ці сервери характеризуються широким спектром розмірів, продуктивності, платформ виконання та функційної ємності. Відтак, OPC-UA визначає вичерпну множину можливостей та сервер може імплементувати підмножини цих можливостей. Для забезпечення сумісності, OPC-UA визначає підмножини, іменовані Профілями, які сервери можуть вказувати для погодження. Клієнти можуть згодом виконувати огляд профілів серверу та прокидати взаємодію із сервером, основаним на профілях.

OPC-UA специфікація спроєктована як ядро у шарі ізольованому від підлеглих комп'ютерних технологій та мережевих транспортів. Це дозволяє OPC-UA, при потребі, розширюватися на майбутні технології без відторгнення основи дизайну. На цей час, специфікацією визначено два способи кодування даних: UA Binary та XML/text. Додатково визначено два типи транспортного шару: TCP та HTTP/SOAP.

OPC-UA спроєктовано як рішення для міграції із OPC клієнтів та серверів, які основані на Microsoft COM технологіях. OPC COM сервери (DA, HDA та A&E) можуть бути легко віддзеркалені у OPС-UA. Виробники можуть самостійно здійснювати таку міграцію або ж рекомендувати користувачам використовувати обгортки та конвертори між цими протоколами. OPC-UA уніфікує попередні моделі у єдиному адресному просторі з єдиною множиною сервісів.

## 2 Модуль реалізації протоколу

Модуль серверу містить код реалізації серверної частини OPC-UA — серверних сервісів (Рис.1), у частині специфічній для OpenSCADA, та використовуючи бібліотеку для OPC-UA специфічної частини. Для побудови OPC-UA серверу достатньо створити вхідний транспорт, за звичай це TCP-транспорт модуля Sockets, та обрати в ньому модуль даного протоколу, а також сконфігурувати хоча б один кінцевий вузол модуля протоколу, про що нижче.

Рис.1. Загальний стан "Серверу".

Загальний стан Серверу містить лише перелік активних каналів безпеки.

### 2.1 Обслуговування запитів за протоколом OPC-UA

Вхідні запити до модуля-протоколу обробляються модулем у відповідності до сконфігурованих кінцевих вузлів OPC-UA (EndPoints) (рис.2).

Рис.2. Кінцеві вузли протоколу.

Кінцевий вузол протоколу OPC-UA це фактично об'єкт серверу OPC-UA. Кінцеві вузли у OPC-UA можуть бути як локальними, так і віддаленими. Локальні кінцеві вузли призначено для надання ресурсів станції OpenSCADA за протоколом OPC-UA, в той-же час віддалені кінцеві вузли слугують для виконання як сервісу огляду доступних OPC-UA вузлів, так і для шлюзування запитів до віддалених станцій. У цій версії модуля підтримується тільки конфігурація локальних кінцевих вузлів.

Загальна конфігурація кінцевого вузла здійснюється на головній вкладці сторінки кінцевого вузла (рис.3) параметрами:

- Стан вузла, а саме: загальний статус, перелік активних сеансів та підписок, "Включено" та ім'я БД, яка містить конфігурацію, з відстеженням наявності даних у різних сховищах та наданням послідовного видалення дублікатів.
- Ідентифікатор, Ім'я та опис вузла.
- Стан, у який переводити вузол при завантажені: "Включено".
- Тип кодування протоколу, на цей час це лише "Бінарний".
- URL кінцевої точки.
- Анонімний користувач увімкнення анонімного доступу, або лише автентифікація за порожнього.
- Сертифікат серверу та приватний ключ у форматі PEM.

  Приховано у ввімкненому стані.

- Політики безпеки серверу.

Рис.3. Головна вкладка сторінки кінцевого вузла.

## 3 Модуль збору даних

Модуль збору даних надає можливість опитування та запису атрибутів значення(13) вузлів типу "Змінна" у режимі прямого опитування запитом "Read" та асинхронним сервісом запиту "Publish".

### 3.1 Об'єкт контролеру

Для додання джерела даних OPC-UA створюється та конфігурується об'єкт контролеру в OpenSCADA. Приклад вкладки конфігурації об'єкту контролеру даного типу зображено на рисунку 4.

Рис.4. Вкладка конфігурації об'єкту контролера OPC-UA.

За допомогою цієї вкладки можна встановити:

- Стан об'єкту контролеру, а саме: Статус, "Ввімкнено", "Виконується" та ім'я сховища, яке містить конфігурацію.

  Ручний перезапуск ввімкненого об'єкту контролеру викликає примусове переформування переліку елементів моніторингу.

- Ідентифікатор, ім'я та опис контролеру.
- Стан "Ввімкнено" та "Виконується", у який переводити об'єкт контролеру при завантажені.
- Політика планування та пріоритет задачі збору даних.
- Період синхронізації конфігурації атрибутів параметрів з віддаленою станцією, а також час повтору спроб відновлення підключення.
- URL кінцевого вузла віддаленої станції — сервера OPC-UA. На початку цю адресу можна вказати у вигляді "opc.tcp://{IP|name}:{port}", після чого, у випадку включення об'єкту контролера та наявності вказаного OPC-UA вузла, з'явиться можливість обрати уточнену адресу.

  Часто зустрічається ситуація, коли уточнена адреса є символьною, який у цій мережі не резолвиться, через некоректне налаштування серверу. У таких випадках потрібно залишити початкову IP-адресу або ім'я яке резолвиться у IP правильно.

- Політика безпеки та режим безпеки повідомлення.
- Сертифікат клієнту та приватний ключ у форматі PEM.

  Приховано у стані виконання.

- Користувач та пароль для аутентифікації на сервері, порожнє значення включає анонімний доступ.
- Асинхронний запис. Вмикає асинхронний запис змін до контролеру, у загальному циклі опитування та після самого опитування даних, блокуючи читання записаних значень на один цикл (до очищення буферу запису).

  Цей режим також запобігає втраті записаних даних за втрати підключення та записані дані будуть передані щойно підключення буде відновлено.

- Використовувати функцію "Read", інакше активується та використовується сервіс збору даних Publish (асинхронний) протоколу OPC-UA.

З метою полегшення ідентифікації вузлів на віддаленій станції, а також вибору їх для вставки у об'єкті параметру контролеру, в самому об'єкті контролеру передбачено вкладку навігації за вузлами віддаленої станції "Огляд вузлів серверу", де можна пройти за деревом об'єктів та ознайомитися з їх атрибутами (рис.5).

Рис.5. Вкладка "Огляд вузлів серверу" сторінки об'єкту контролеру OPC-UA.

### 3.2 Параметри

Модуль збору даних надає два типи параметру: "Стандартний (_Prm)" та "Логічний (_PrmL)". Додатковими конфігураційними полями параметрів цього модуля є:

- Стандартний (_Prm):
  - Перелік атрибутів — містить структурований перелік конфігурації атрибутів ModBUS.
- Логічний (_PrmL):
  - Шаблон параметру — адреса шаблону параметру DAQ.

#### 3.2.1 Стандартний (_Prm)

Додатковим конфігураційним полем параметру даного типу (рис.6) є перелік вузлів OPC-UA і поле навігації за вузлами OPC-UA у один рядок для вставки обраних вузлів типу "Змінна" до визначеного переліку. Атрибут у цьому переліку записується як "{ns}:{nid}[|[{flg}][|{id}[|{name}]]]".
Де:

- ns — простір імен, числом; нульове значення може бути опущено;
- nid — ідентифікатор вузла, числом, рядком, рядком байт або GUID;
- flg — прапорці нездійснення запиту цільових даних на сервері: тип значення (b-Логічний,i-Ціле,f-Реальне,s-Рядок,o-Об'єкт), режим запису/читання (r-читати, w-писати);
- id — ідентифікатор атрибуту що створюється;
- name — ім'я атрибуту що створюється.

Приклади:

  84 — кореневий вузол;
  3:"BasicDevices2"||var — вузол базових пристроїв у просторі імен 3 та у вигляді рядка із прямим ІД атрибуту;
  4:"61626364"||var|Variable — вузол у просторі імен 4 та у вигляді рядка байт із прямим ІД та назвою атрибуту;
  4:{40d95ab0-50d6-46d3-bffd-f55639b853d4}|irw|var|Variable — вузол у просторі імен 4 і у вигляді GUID із нездійсненням запиту цільових даних щодо Цілого Читання-Запису та прямим ІД і назвою атрибуту.

Рис.6. Вкладка конфігурації об'єкту параметра OPC-UA.

Вузли типу "Змінна" зі значенням у вигляді структури прочитати цілком зазвичай не можна тому потрібно її елементи вставляти до переліку вузлів читання окремо.

Відповідно до вказаного переліку вузлів виконується опитування та створення атрибутів параметру (рис.7).

Рис.7. Вкладка атрибутів параметру.

#### 3.2.2 Логічний (_PrmL)

Головну сторінку конфігурації параметру логічного типу представлено на рисунку 8.

Рис.8. Вкладка конфігурації параметру логічного типа.

Значення посилання при конфігурації шаблону (рис.9) записується у формі "{ns}:{id}".
Де:

- ns — простір імен, числом; нульове значення може бути опущено;
- id — ідентифікатор вузла, числом, рядком, рядком байт або GUID.

Приклади:

  84 — кореневий вузол;
  3:"BasicDevices2" — вузол базових пристроїв у просторі імен 3 та у вигляді рядка;
  4:"61626364" — вузол у просторі імен 4 та у вигляді рядка байт;
  4:{40d95ab0-50d6-46d3-bffd-f55639b853d4} — вузол у просторі імен 4 і у вигляді GUID.

Рис.9. Вкладка "Конфігурація шаблону" параметра логічного типу.

Модулем передбачена особлива обробка низки атрибутів шаблону:

- f_frq — частота обчислення процедури шаблону або час після останнього обчислення (негативне у секундах) для планування за CRON, тільки читання.
- f_start — ознака першого виконання процедури шаблону — запуск, тільки читання.
- f_stop — ознака останнього виконання процедури шаблону — зупинка, тільки читання.
- f_err — помилка параметру, повний доступ. Значення цього атрибуту шаблону потрапляє до атрибуту помилки параметру "err". Записати сюди EVAL для можливості встановлення ззовні атрибуту "err" та всіх інших у режимі Тільки для Читання.
- SHIFR — значення шифру параметру, тільки читання.
- NAME — значення назви параметру, тільки читання.
- DESCR — значення опису параметру, тільки читання.
- this — об'єкт даного параметру, дозволяє отримати доступ до атрибутів параметру, наприклад, для доступу до архівів-історії.

Відповідно до шаблону, що лежить у основі параметру, ми отримуємо набір атрибутів параметру (рис.10).

Рис.10. Вкладка атрибутів параметру логічного типу.

### 3.3 API користувацького програмування

У зв'язку із підтримкою параметрів логічного типу, має сенс надання низки функцій користувацького API для їх виклику із шаблону логічного параметру.

Об'єкт "Контролер" [this.cntr()]

- ElTp value( string addr, ElTp setVl = NULL ) — прямий доступ до значення-вузла із реєстрацією для збору.
  - addr — адреса значення-вузла у стандартному форматі;
  - setVl — встановлюване значення, NULL (не визначено) лише для отримання.

## 4 Бібліотека libOPC_UA

Ґрунтуючись на напрацюваннях цього модуля, протокольний код OPC-UA було винесено до окремої бібліотеки та опубліковано під ліцензією LGPLv3. Такі дії виконано з метою надати можливість простого додання підтримки протоколу OPC-UA стороннім проєктам. Бібліотека представлена двома файлами libOPC_UA.h, libOPC_UA.cpp; підтримується та міститься у складі цього модуля, тобто актуальну версію Ви можете завантажити тут: http://oscada.org/svn/trunk/OpenSCADA/src/moduls/daq/OPC_UA/libOPC_UA.

Бібліотеку, як і цей модуль, написано на мові програмування C++. Статичну діаграму класів, яка відображає архітектуру бібліотеки, наведено на рисунку 11. Згідно до діаграми класів, бібліотеку виконано у просторі імен "OPC", а архітектурно її можна поділити на клієнтську "Client" та серверну "Server" частини, які успадковано від загального класу протоколу "UA". Крім безпосередньо класів протоколу "OPC-UA" бібліотека включає в себе набір функцій та класів для обробки або збереження даних протоколу, окремо з яких треба відзначити клас вузла мови XML "XML_N", використаний для уніфікації звернень до API бібліотеки.

Рис.11. Статична діаграма класів бібліотеки libOPC_UA.

Використання бібліотеки загалом полягає у спадкуванні класу "Client" та/або "Server" згідно до функцій кінцевої програми та наступної реалізації віртуальних функцій властивостей клієнта/сервера у контексті протоколу OPC-UA, а також транспортної частини комунікації, тобто — підключення/відкриття TCP-сокету та передачу/читання неструктурованого потоку даних. Наступні запити, та обробка їх даних (для серверу), здійснюється через виклик функції запиту сервісу reqService() та/або обробки віртуальної функції запиту даних reqData(), тобто, фактично, інтеграція у модель даних додатку.

Після додання до клієнту підтримки асинхронного сервісу опитування даних сервісом "Publish", процес інтеграції доповнився періодичним викликом функції Client::poll() з метою опрацювання асинхронного сервісу. Функцію Client::poll() також забезпечено підтримкою синхронного режиму роботи, окремим аргументом, через уніфіковану інфраструктуру підписки-реєстрації елементів моніторингу, але функцією "Read". Тобто, наразі достатньо зареєструвати всі елементи моніторингу функцією Client::Subscr::monitoredItemAdd() а потім викликати функцію Client::poll() для отримання їх даних у потрібному режимі.

Після останнього перегляду коду у версії 2, інтеграція серверної частини додатково потребує обов'язкового запуску окремого потоку обробки всіх підписок, з викликом із нього функції Server::EP::subScrCycle() та аргументом лічильника циклів опрацювання підписок — періодичність виклику Server::EP::subscrProcPer().

### 4.1 Службові об'єкти, функції та клас UA

#### 4.1.1 Дані

Типи реалізацій (enum — SerializerType):

- ST_Binary = 0 — бінарний.

Типи запису відкриття каналу безпеки (enum — SC_ReqTP):

- SC_ISSUE = 0 — викликаючий;
- SC_RENEW = 1 — оновлюючий.

Режими безпеки повідомлення (enum — MessageSecurityMode):

- MS_None = 1 — без безпеки;
- MS_Sign = 2 — підпис;
- MS_SignAndEncrypt = 3 — підпис та шифрування.

Типи аутентифікації (enum — AuthTp):

- A_Anon = 0 — анонімно;
- A_UserNm = 1 — користувач+пароль;
- A_Cert = 2 — сертифікат.

Класи вузлів (enum — NodeClasses):

- NC_Object = 1 — об'єкт;
- NC_Variable = 2 — змінна;
- NC_Method = 4 — метод;
- NC_ObjectType = 8 — тип об'єкта;
- NC_VariableType = 16 — тип змінної;
- NC_ReferenceType = 32 — тип посилання;
- NC_DataType = 64 — тип даних;
- NC_View = 128 — вид.

Напрями огляду (enum — BrowseDirection):

- BD_FORWARD = 0 — вперед;
- BD_INVERSE = 1 — назад;
- BD_BOTH = 2 — вперед та назад.

Мітка часу повернення (enum — TimestampsToReturn):

- TS_SOURCE = 0 — джерела;
- TS_SERVER = 1 — сервера;
- TS_BOTH = 2 — джерела та сервера;
- TS_NEITHER = 3 — відсутня.

Доступ (enum — Access):

- ACS_Read = 0x01 — читання;
- ACS_Write = 0x02 — запис;
- ACS_HistRead = 0x04 — читання історії;
- ACS_HistWrite = 0x08 — запис історії;
- ACS_SemChange = 0x10 — ?.

Елементи маски опису оглядового запиту (enum — RefDscrResMask):

- RdRm_RefType = 0x01 — тип посилання;
- RdRm_IsForward = 0x02 — напрямок;
- RdRm_NodeClass = 0x04 — клас вузла;
- RdRm_BrowseName = 0x08 — ім'я огляду;
- RdRm_DisplayName = 0x10 — ім'я відображення;
- RdRm_TypeDef = 0x20 — тип визначення.

Ідентифікатори атрибутів вузла (enum — AttrIds):

- Aid_Error = 0 — помилка;
- AId_NodeId = 1 — ідентифікатор вузла;
- AId_NodeClass = 2 — клас вузла;
- AId_BrowseName = 3 — ім'я огляду;
- AId_DisplayName = 4 — ім'я відображення;
- AId_Descr = 5 — опис;
- AId_WriteMask = 6 — маска запису;
- AId_UserWriteMask = 7 — маска запису користувача;
- AId_IsAbstract = 8 — абстрактність;
- AId_Symmetric = 9 — симетричність;
- AId_InverseName = 10 — інверсне ім'я;
- AId_ContainsNoLoops = 11 — відсутність петель;
- AId_EventNotifier = 12 — повідомлення подій;
- AId_Value = 13 — значення;
- AId_DataType = 14 — тип даних;
- AId_ValueRank = 15 — ранг значення;
- AId_ArrayDimensions = 16 — розмірність масиву;
- AId_AccessLevel = 17 — рівень доступу;
- AId_UserAccessLevel = 18 — рівень доступу користувача;
- AId_MinimumSamplingInterval = 19 — мінімальний інтервал вимірювання;
- AId_Historizing — архівування;
- AId_Executable — виконуваний;
- AId_UserExecutable — виконуваний користувачем.

Стани підписки (enum — SubScrSt):

- SS_CUR = 0 — поточне (не міняти командою);
- SS_CLOSED = 1 — закрито;
- SS_CREATING = 2 — створення;
- SS_NORMAL = 3 — нормальний;
- SS_LATE = 4 — запізнілий;
- SS_KEEPALIVE = 5 — збереження живим.

Режими моніторингу (enum — MonitoringMode):

- MM_CUR = -1 — поточне (не міняти командою);
- MM_DISABLED = 0 — відімкнене;
- MM_SAMPLING = 1 — вимірювання;
- MM_REPORTING = 2 — звітність.

#### 4.1.2 Зовнішні функції

До бібліотеки включено низку зовнішніх функцій об'єкту TSYS ядра OpenSCADA для спрощення та уніфікації низки внутрішніх операцій:

- int64_t curTime( clockid_t clc = CLOCK_REALTIME ); — Поточний час у мікросекундах для лічильника clc, з початку епохи Unix (01.01.1970) для CLOCK_REALTIME.
- string int2str( int val ); — Перетворення цілого знакового у рядок в десятковому представлені.
- int str2int( const string &val ); — Перетворення значення рядка val в десятковому, шістнадцятковому або вісімковому представлені у ціле знакове.
- string uint2str( unsigned val ); — Перетворення цілого беззнакового у рядок в десятковому представлені.
- unsigned long str2uint( const string &val ); — Перетворення значення рядка val в десятковому, шістнадцятковому або вісімковому представлені у ціле беззнакове.
- string ll2str( int64_t val ); — Перетворення довгого цілого (64біт) у рядок в десятковому представлені.
- string real2str( double val, int prec = 15, char tp = 'g' ); — Перетворення реального із точністю prec знаків і типом tp у рядок.
- double str2real( const string &val ); — Перетворення значення рядка val у реальне.
- string strParse( const string &path, int level, const string &sep, int *off = NULL, bool mergeSepSymb = false ); — Розбір рядку path на складові, відокремлені роздільником sep, об'єднуючи односимвольні mergeSepSymb, починаючи зі зміщення off і контролюючи зміщення кінця елементу в ньому ж.
- string strLine( const string &str, int level, int *off = NULL ); — Розбір багаторядкового тексту на окремі рядки, починаючи зі зміщення off і контролюючи зміщення кінця елементу в ньому ж.
- string strMess( const char *fmt, ... ); — Формування рядка за шаблоном fmt та аргументами, реалізовано на основі "sprintf".

#### 4.1.3 Об'єкт автоматичного розблоковування POSIX мютексу для OPC (OPCAlloc)

Цей об'єкт керування мютексом є копією об'єкту "MtxAlloc" для ядра OpenSCADA.

Публічні методи:

- OPCAlloc( pthread_mutex_t &iM, bool ilock = false ); — Ініціалізація об'єкту автоматичного розблокування мютексу iM, створеного раніш, із блокуванням при створені за lock.
- int lock( ); — Захоплення ресурсу, повернення нуля при вдалому виконанні.
- int unlock( ); — Звільнення ресурсу, повернення нуля при вдалому виконанні.
- int tryLock( ); — Спроба захоплення ресурсу без очікування звільнення, повернення нуля при вдалому виконанні.

#### 4.1.4 Помилка OPC (OPCError)

Об'єкт помилки "OPCError" є урізаною копією об'єкту TError ядра OpenSCADA.

Публічні методи:

- OPCError( const char *fmt, ... ); — Конструктор типової помилки без коду.
- OPCError( int cod, const char *fmt, ... ); — Конструктор типової помилки із кодом помилки.

Публічні атрибути:

- int cod; — Код помилки.
- string mess; — Текст помилки.

#### 4.1.5 XML-тег (XML_N)

Об'єкт "XML_N" є урізаною копією об'єкту XMLNode ядра OpenSCADA.

Публічні методи:

- XML_N( const string &name = "" ); — Ініціалізація тегу з назвою name.
- XML_N( const XML_N &nd ); — Копіюючий конструктор.
- XML_N &operator=( const XML_N &prm ); — Копіювання гілки XML-дерева із prm.
- string name( ) const; — Назва тегу.
- XML_N* setName( const string &s ); — Встановлення назви тегу у s.
- string text( bool childs = false, bool recursive = false ) const; — Текст тегу, childs — для отримання тексту із спеціалізованих вузлів тексту.
- XML_N* setText( const string &s, bool childs = false ); — Встановлення тексту тегу у s, childs — для встановлення тексту у спеціалізованих вузол тексту.
- void attrList( vector<string> & list ) const; — Перелік атрибутів list у тегу.
- XML_N* attrDel( const string &name ); — Видалення атрибуту name.
- void attrClear( ); — Очищення атрибутів тегу.
- string attr( const string &name, bool caseSens = true ) const; — Отримання атрибуту name.
- XML_N* setAttr( const string &name, const string &val ); — Встановлення/створення атрибуту name зі значенням val.
- XML_N* clear( ); — Очищення тегу (рекурсивно, включаючи всі вкладення).
- bool childEmpty( ) const; — Перевірка на відсутність вкладених тегів.
- unsigned childSize( ) const; — Кількість вкладених тегів.
- void childAdd( XML_N *nd ); XML_N* childAdd( const string &name = "" ); — Додання вкладеного тегу.
- int childIns( unsigned id, XML_N *nd ); — Вставка вкладеного тегу nd у позицію id, негативне значення id веде відлік з кінця.
- XML_N* childIns( unsigned id, const string &name = "" ); — Вставка вкладеного тегу з ім'ям name у позицію id, негативне значення id веде відлік з кінця.
- void childDel( const unsigned id ); — Видалення вкладеного тегу id, Негативне значення id веде відлік з кінця.
- void childDel( XML_N *nd ); — Видалення вкладеного тегу за його адресою nd.
- XML_N* childClear( const string &name = "" ); — Очищення вкладеного тегу name.
- XML_N* childGet( const int, bool noex = false ) const; — отримання вкладеного тегу за порядковим номером.
- XML_N* childGet( const string &name, const int numb = 0, bool noex = false ) const; — Отримання вкладеного numb порядкового тегу за іменем тегу name, noex вказує на заборону генерації виключення у випадку відсутності тегу.
- XML_N* childGet( const string &attr, const string &name, bool noex = false ) const; — Отримання вкладеного тегу за значенням name атрибуту attr, noex вказує на заборону генерації виключення у випадку відсутності тегу.
- XML_N* getElementBy( const string &attr, const string &val ); — Пошук вкладеного вузла за значенням val атрибуту attr.
- XML_N* parent( ); — Батьківський тег цього тегу.
- XML_N* root( ); — Кореневий тег цього тегу.

#### 4.1.6 Об'єкт вузла OPC-UA (NodeId)

Дані:
Типи даних (enum — NodeId::Type):

- NodeId::Numeric — номер.
- NodeId::String — рядок.
- NodeId::Guid — глобальний унікальний ідентифікатор.
- NodeId::Opaque — opaque.

Публічні методи:

- NodeId( uint32_t n, uint16_t ns = 0 ); — Чисельний ініціюючий конструктор для числа n у просторі назв ns.
- NodeId( const string &str, uint16_t ns = 0, Type tp = String ); — Строковий ініціюючий конструктор для рядка str у просторі назв ns з типом tp.
- NodeId( const NodeId &node ); — Копіюючий конструктор об'єкту.
- NodeId( ); — Деструктор.
- bool operator==( const NodeId &node ); — Порівняння об'єктів.
- NodeId &operator=( const NodeId &node ); — Копіювання об'єкту.
- Type type( ) const; — Тип вузла.
- bool isNull( ) const; — Вузол нульовий — неініційований.
- uint16_t ns( ) const; — Простір назв.
- uint32_t numbVal( ) const; — Чисельні значення.
- string strVal( ) const; — Строкові значення.
- void setNs( uint16_t ns ); — Встановлення простору назв у ns.
- void setNumbVal( uint32_t n ); — Встановлення чисельного значення n.
- void setStrVal( const string &str, Type tp = String ); — Встановлення строкового значення str з типом tp.
- static NodeId fromAddr( const string &strAddr, bool strictStr = false, int *off = NULL ); — Формування об'єкту вузла із адреси strAddr, як суворий рядок strictStr та із кінцем розбору адреси у off.
- string toAddr( ) const; — Отримання адреси об'єкту вузла.

#### 4.1.7 Кореневий об'єкт протоколу OPC-UA (UA)

Публічні методи:

- virtual string lang2CodeSYS( ); — Дво-символьний код мови оточення.
- virtual void debugMess( const string &mess ) — Розташування налагоджувальних повідомлень.
- virtual uint32_t rcvBufSz( ); — Розмір буферу приймача, більш за 8192.
- virtual uint32_t sndBufSz( ); — Розмір буферу передавача, більш за 8192.
- virtual uint32_t msgMaxSz( ); — Максимальний розмір повідомлення, 0 для відсутності обмеження.
- virtual uint32_t chunkMaxCnt( ); — Максимальна кількість шматків, 0 для відсутності обмеження.
- static string iErr( const string &buf, int &off ); — Читання помилки із потоку buf за зміщенням off.
- static const char *iVal( const string &buf, int &off, char vSz ); — Читання значення розміром vSz із потоку buf за зміщенням off, як ділянку даних.
- static int64_t iN( const string &rb, int &off, char vSz ); — Читання знакового цілого розміром vSz (1, 2, 4, 8) із потоку rb за зміщенням off.
- static uint64_t iNu( const string &rb, int &off, char vSz ); — Читання беззнакового цілого розміром vSz (1, 2, 4, 8) із потоку rb за зміщенням off.
- static double iR( const string &rb, int &off, char vSz = 4 ); — Читання реального розміром vSz (4, 8) із потоку rb за зміщенням off.
- static string iS( const string &buf, int &off ); — Читання рядка із потоку buf за зміщенням off.
- static string iSl( const string &buf, int &off, string *locale = NULL ); — Читання локалізованого locale рядка із потоку buf за зміщенням off.
- static string iSqlf( const string &buf, int &off, uint16_t *nsIdx = NULL ); — Читання рядку із кваліфікатором nsIdx із потоку buf за зміщенням off.
- static int64_t iTm( const string &buf, int &off ); — Читання часу із потоку buf за зміщенням off, із перетворенням у епоху UNIX.
- static NodeId iNodeId( const string &buf, int &off ); — Читання ідентифікатору вузла із потоку buf за зміщенням off.
- static string iVariant( const string &buf, int &off, uint8_t *tp = NULL ); — Читання типу варіант із потоку buf за зміщенням off, повертає варіант у строковому вигляді для типу tp.
- static void iDataValue( const string &buf, int &off, XML_N &nVal ); — Читання комплексного значення (структура DataValue) у nVal із потоку buf за зміщенням off.
- static void oN( string &buf, int64_t val, char sz, int off = -1 ); — Запис знакового цілого val розміром sz (1, 2, 4, 8) у потік buf за зміщенням off.
- static void oNu( string &buf, uint64_t val, char sz, int off = -1 ); — Запис беззнакового цілого val розміром sz (1, 2, 4, 8) у потік buf за зміщенням off.
- static void oR( string &buf, double val, char sz = 4 ); — Запис реального val розміром sz (4, 8) у потік buf за зміщенням off.
- static void oS( string &buf, const string &val, int off = -1 ); — Запис рядку val у потік buf за зміщенням off.
- static void oSl( string &buf, const string &val, const string &locale = "" ); — Запис локалізованого locale рядка val у потік buf за зміщенням off.
- static void oSqlf( string &buf, const string &val, uint16_t nsIdx = 0 ); — Запис рядка val із кваліфікатором nsIdx у потік buf за зміщенням off.
- static void oTm( string &buf, int64_t val ); — Запис часу val (в епосі UNIX) у потік buf за зміщенням off.
- static void oNodeId( string &buf, const NodeId &val ); — Запис ідентифікатору вузла val у потік buf за зміщенням off.
- static void oRef( string &buf, uint32_t resMask, const NodeId &nodeId, const NodeId &refTypeId, bool isForward, const string &name, uint32_t nodeClass, const NodeId &typeDef ); — Запис у потік buf опису огляду (структура ReferenceDescription) для маски результату resMask, вузла nodeId, типу посилання refTypeId, напрямку isForward, назви name, класу вузла nodeClass, типу визначення typeDef.
- void oDataValue( string &buf, uint8_t eMsk, const string &vl, uint8_t vEMsk = 0, int64_t srcTmStmp = 0 ); — Запис комплексного значення (структура DataValue) у потік buf для маски кодування eMsk, значення vl, маски значення vEMsk, часу джерела srcTmStmp.
- static string randBytes( int num ); — Генерація потоку випадкових даних у кількості num.
- static string certPEM2DER( const string &certPem ); — Перетворення сертифікату із формату PEM certPem у формат DER.
- static string certDER2PEM( const string &certDer ); — Перетворення сертифікату із формату DER certDer у формат PEM.
- static string certThumbprint( const string &certPem ); — Отримання підпису із сертифікату PEM certPem.
- static string asymmetricEncrypt( const string &mess, const string &certPem, const string &secPolicy ); — Асиметричне кодування потоку повідомлення mess сертифікатом certPem (відкритим ключем) для політики secPolicy.
- static string asymmetricDecrypt( const string &mess, const string &pvKeyPem, const string &secPolicy ); — Асиметричне декодування потоку повідомлення mess ключем pvKeyPem для політики secPolicy.
- static bool asymmetricVerify( const string &mess, const string &sign, const string &certPem ); — Асиметрична верифікація підпису sign повідомлення mess сертифікатом certPem.
- static string asymmetricSign( const string &mess, const string &pvPem ); — Отримання асиметричного підпису закритим ключем сертифікату pvPem для повідомлення mess.
- static int asymmetricKeyLength( const string &keyCertPem ); — Отримання довжини ключа сертифікату keyCertPem.
- static string deriveKey( const string &secret, const string &seed, int keyLen ); — Вилучення ключа розміром keyLen із секрету secret та seed.
- static string symmetricCrypt( const string &mess, const string &keySet, const string &secPolicy, bool encrypt ); — Симетричне шифрування за encrypt або дешифрування потоку повідомлення mess ключем keySet для політики secPolicy.
- static string symmetricSign( const string &mess, const string &keySet, const string &secPolicy ); — Отримання симетричного підпису ключем keySet для повідомлення mess та політики secPolicy.

##### 4.1.7.1 Включений об'єкт параметрів безпеки (SecuritySetting)

Отримані дані:

- string policy — політика безпеки;
- MessageSecurityMode messageMode — режим повідомлення.

Публічні методи:

- SecuritySetting( const string &plc, int8_t mMode ) — Конструктор об'єкту із політикою безпеки plc та режимом повідомлення mMode.
- SecuritySetting( ) — Конструктор об'єкту із політикою безпеки "None" та режимом повідомлення MS_None.

### 4.2 Основний об'єкт Клієнту (Client->UA)

Застосування: Безпосередньо успадковується користувацьким об'єктом — Клієнт OPC-UA.

Публічні методи:

- virtual string applicationUri( ) = 0; — URI додатку.
- virtual string productUri( ) = 0; — URI продукту.
- virtual string applicationName( ) = 0; — Назва додатку.
- virtual string sessionName( ) = 0; — Назва сеансу.
- virtual string endPoint( ) = 0; — Кінцева точка.
- virtual string secPolicy( ) = 0; — Політика безпеки.
- virtual int secMessMode( ) = 0; — Режим безпеки повідомлення.
- virtual string cert( ) = 0; — Сертифікат.
- virtual string pvKey( ) = 0; — Приватний ключ.
- virtual string authData( ) = 0; — Дані аутентифікації:
  - "<Empty>" — анонімний;
  - "{User}\n{Password}" — за користувачем та паролем.
- virtual uint8_t publishReqsPool( ) — Кількість Publish запитів обслуговування сервісу публікації, типово 2(два).
- virtual string poll( bool byRead = false ); — Функція обслуговування сервісу публікації на предмет: читання вхідного каналу щодо відповідей публікації, відстеження наявності потрібної кількості Publish запитів та втрати зв'язку через відсутність відповідей публікацій протягом визначеного часу життя. За аргументом byRead функція також забезпечує пряме читання зареєстрованих елементів моніторингу запитом "Read".
- virtual int messIO( const char *oBuf, int oLen, char *iBuf = NULL, int iLen = 0 ) = 0; — Обмін повідомленнями, передача запиту та очікування відповіді.

  Змішаний режим запиту та вільного читання/запису все ще вирішується.

- virtual bool connect( int8_t est = -1 ); — Отримання статусу підключення, встановлення підключення для est = 1, відключення для est = 0.
- virtual void protIO( XML_N &io ); — Обробка запиту до протоколу.
- virtual void reqService( XML_N &io ); — Комплексний запит сервісу, який сам відстежує необхідність виклику допоміжних запитів відкриття/закриття каналу безпеки, відкриття/закриття/активації сеансу та решта.

Захищені атрибути:

- SClntSess sess; — дані сеансу;
- pthread_mutex_t mtxData; — замок доступу до даних.

#### 4.2.1 Комплексний сеанс Клієнту (Client::SClntSess)

Публічні дані:

- uint32_t servRcvBufSz, servSndBufSz, servMsgMaxSz, servChunkMaxCnt; — параметри буферу приймача, передавача, максимального розміру повідомлення та максимальної кількості шматків; які отримано від серверу запитом "HELLO";
- string endPoint; — кінцева точка;
- XML_N endPointDscr; — опис активної кінцевої точки;
- uint32_t secChnl, secToken; — індекс та талон каналу безпеки;
- int secLifeTime; — час життя каналу безпеки;
- bool secChnlChanged; — ознака зміни каналу безпеки для перепідключення чи повторної активації сеансу;
- uint32_t sqNumb, sqReqId, reqHndl; — номер послідовності, порядковий номер запиту та тримач запиту;
- string secPolicy; — політика безпеки;
- char secMessMode; — режим безпеки повідомлення;
- int64_t secChnlOpenTm, secLstMessReqTm; — час відкриття/оновлення каналу безпеки та останнього повідомлення запиту;
- string sesId, authTkId; — ідентифікатор та талон аутентифікації сеансу;
- double sesLifeTime; — час життя сеансу;
- string servCert, servNonce, servKey; — сертифікат, випадкова послідовність та симетричний ключ серверу;
- string clKey; — симетричний ключ клієнту;
- vector<Subscr> mSubScr; — підписки (об'єкт Subscr) клієнту;
- vector<uint32_t> mPublSeqs; — реєстр надісланих запитів публікації за порядковим номером запиту.

Публічні методи:

- void clearSecCnl( bool inclEP = false ) — Очищення каналу безпеки, включно із описом кінцевої точки inclEPdescr.
- void clearSess( bool inclSubscr = true ) — Очищення сеансу, включно із підписками inclSubscr.

##### 4.2.1.1 Підписка Клієнту (Client::Subscr)

Публічні дані:

- bool publEn; — увімкнути публікацію;
- double publInterval; — інтервал публікації у мілісекундах;
- uint32_t subScrId; — ідентифікатор підписки: <НУЛЬ> — неактивний об'єкт;
- uint32_t lifetimeCnt; — лічильник, за якого та відсутності сповіщень, у клієнта видаляється цей об'єкт;
- uint32_t maxKeepAliveCnt; — лічильник, за якого треба надсилати порожню відповідь публікації;
- uint32_t maxNtfPerPubl; — максимальна кількість сповіщень у одній відповіді Публікації;
- uint8_t pr; — пріоритет;
- vector<MonitItem> mItems; — контейнер елементів моніторингу;
- vector<uint32_t> mSeqToAcq; — реєстр послідовностей відповідей Публікації, які потребують підтвердження найближчим запитом Публікації;
- int64_t lstPublTm; — час останньої відповіді публікації;
- Client *clnt; — пряме посилання на об'єкт Клієнту.

Публічні методи:

- Subscr( Client *clnt, double publInterval = 1e3 ); — Конструктор Підписки щодо Клієнту clnt із інтервалом публікації publInterval.
- bool isActivated( ); — Повертає стан активації підписки.
- void activate( bool vl, bool onlyLocally = false ); — Активує (vl=TRUE) або деактивує (vl=FALSE) Підписку. Активація передбачає надсилання запиту "CreateSubscription" зі створенням зареєстрованих, але ще не активованих елементів моніторингу, сервісним запитом "CreateMonitoredItems". Деактивація передбачає надсилання сервісного запиту "DeleteSubscriptions", якщо не встановлено onlyLocally, із очищенням локальних даних елементів моніторингу.
- int monitoredItemAdd( const NodeId &nd, AttrIds aId = AId_Value, MonitoringMode mMode = MM_REPORTING ); — Додає вузол nd щодо атрибуту aId, як елемент моніторингу у режимі моніторингу mMode, та повертає ідентифікатор нового елементу. За активного стану Підписки також здійснюється сервісний запит "CreateMonitoredItems". Спеціальне значення "0" вузла nd передбачає здійснення сервісного запиту "CreateMonitoredItems" для всіх зареєстрованих та ще не активованих елементів.
- void monitoredItemDel( int32_t mItId, bool localDeactivation = false, bool onlyNoData = false ); — Видаляє елемент моніторингу mItId, позначаючи його як "ВІЛЬНИЙ" та здійснюючи також сервісний виклик "DeleteMonitoredItems" для не localDeactivation. onlyNoData використовується разом із localDeactivation для лише маркування елементу як "НЕМАЄ-ДАНИХ" після деяких помилок підключення. Спеціальне значення "-1" елементу моніторингу mItId передбачає здійснення деактивації всіх елементів.

###### 4.2.1.1.1 Елемент Моніторингу Підписки Клієнту (Client::Subscr::MonitItem)

Публічні дані:

- MonitoringMode md; — режим моніторингу;
- NodeId nd; — цільовий вузол: <ПОРОЖНЬО> — вільний елемент моніторингу;
- uint32_t aid; — ІД атрибуту вузла;
- double smplItv; — інтервал вимірювання;
- uint32_t qSz; — розмір черги;
- bool active; — активність елементу;
- uint32_t st; — код стану елементу;
- XML_N val; — контекст значення елементу: наявність атрибуту "nodata" означає відсутність даних.

Публічні методи:

- MonitItem( NodeId nd, uint32_t aid, MonitoringMode md = MM_REPORTING ); — Конструктор Елементу Моніторингу для вузла nd та його атрибуту aid у режимі моніторингу md.

### 4.3 Основний об'єкт Серверу (Server->UA)

Застосування: Прямо успадковується користувацьким об'єктом — Сервер OPC-UA.

Публічні методи:

- virtual bool debug( ); — Активовано налаштування.
- virtual string applicationUri( ) = 0; — URI додатку.
- virtual string productUri( ) = 0; — URI продукту.
- virtual string applicationName( ) = 0; — Ім'я додатку.
- virtual uint32_t clientRcvBufSz( const string &inPrtId ) = 0; — Розмір буферу приймача для підключення inPrtId, отриманий від клієнта.
- virtual uint32_t clientSndBufSz( const string &inPrtId ) = 0; — Розмір буферу передавача для підключення inPrtId, отриманий від клієнта.
- virtual uint32_t clientMsgMaxSz( const string &inPrtId ) = 0; — Максимальний розмір повідомлення для підключення inPrtId, отриманий від клієнта.
- virtual uint32_t clientChunkMaxCnt( const string &inPrtId ) = 0; — Максимальна кількість шматків для підключення inPrtId, отримана від клієнта.
- virtual void discoveryUrls( vector<string> &ls ) = 0; — URLи серверів огляду у ls.
- virtual bool inReq( string &request, const string &inPrtId, string *answ = NULL ); — Обробник вхідних запитів request екземпляру протоколу inPrtId та відповіді у answ.
- virtual int writeToClient( const string &threadId, const string &data ) = 0; — Прямий запис підключеному клієнту.
- virtual string clientAddr( const string &threadId ) = 0; — Адреса клієнту.
- virtual void clientRcvBufSzSet( const string &inPrtId, uint32_t vl ) = 0; — Встановлення розміру буферу приймача, отриманого від клієнта, у значення vl для підключення inPrtId.
- virtual void clientSndBufSzSet( const string &inPrtId, uint32_t vl ) = 0; — Встановлення розміру буферу передавача, отриманого від клієнта, у значення vl для підключення inPrtId.
- virtual void clientMsgMaxSzSet( const string &inPrtId, uint32_t vl ) = 0; — Встановлення максимального розміру повідомлення, отриманого від клієнта, у значення vl для підключення inPrtId.
- virtual void clientChunkMaxCntSet( const string &inPrtId, uint32_t vl ) = 0; — Встановлення максимальної кількості шматків, отриманої від клієнта, у значення vl, для підключення inPrtId.
- int chnlSet( int cid, const string &ep, int32_t lifeTm = 0, const string& clCert = "", const string &secPolicy = "None", char secMessMode = 1, const string &clAddr = "", uint32_t seqN = 1 ); — Встановлення каналу безпеки із ідентифікатором cid (ненульове значення для оновлення) для кінцевої точки ep, часу життя lifeTm, клієнтського сертифікату clCert, політики безпеки secPolicy, режиму безпеки повідомлення secMessMode, адреси клієнта clAddr, номеру послідовності пакета seqN.
- void chnlClose( int cid ); — Закриття каналу безпеки cid.
- SecCnl chnlGet( int cid ); SecCnl &chnlGet_( int cid ); — Отримання копії та доступу до об'єкту каналу безпеки cid.
- void chnlSecSet( int cid, const string &servKey, const string &clKey ); — Встановлення для каналу безпеки cid серверного servKey та клієнтського clKey симетричних ключів.
- static string mkError( uint32_t errId, const string &err = "" ); — Формування помилки з ідентифікатором errId та повідомленням err.

Захищені методи:

- virtual void epEnList( vector<string> &ls ) = 0; — Обробник запиту переліку кінцевих вузлів.
- virtual EP *epEnAt( const string &ep ) = 0; — Обробник запиту об'єкту кінцевої точки.

Захищені атрибути:

- pthread_mutex_t mtxData; — замок доступу до даних.

#### 4.3.1 Канал Безпеки Серверу (Server::SecCnl)

Публічні методи:

- SecCnl( const string &ep, uint32_t tokenId, int32_t lifeTm, const string &clCert, const string &secPolicy, char secMessMode, const string &clAddr, uint32_t secN ); — Конструктор об'єкту Каналу Безпеки для: кінцевої точки ep, талону безпеки tokenId, часу життя lifeTm, клієнтського сертифікату clCert, політики безпеки secPolicy, режиму безпеки повідомлень secMessMode, адреси клієнта clAddr, номеру послідовності створення каналу безпеки secN.

Публічні атрибути:

- string endPoint; — кінцева точка;
- string secPolicy; — політика безпеки;
- char secMessMode; — режим безпеки повідомлень;
- int64_t tCreate; — час створення;
- int32_t tLife; — час життя;
- uint32_t tokenId, tokenIdPrev; — поточний і попередній ідентифікатори талону;
- string clCert, clAddr, clKey; — сертифікат, адреса та симетричний ключ клієнту;
- string servKey; — симетричний ключ серверу;
- uint32_t servSeqN, clSeqN, reqId; — поточний номер послідовності пакету серверу, клієнту та запиту;
- int chCnt; — лічильник шматків пакету в акумуляції;
- string chB; — акумуляція пакету зі шматків.

#### 4.3.2 Сеанс Серверу (Server::Sess)

Публічні методи:

- Sess( const string &name, double tInact ); — Конструктор об'єкту Сеансу з назвою name та таймаутом неактивності tInact.
- bool isSecCnlActive( EP *ep ); — Повертає стан активности Каналу Безпеки, пов'язаному із сеансом.

Публічні атрибути:

- string name, inPrtId; — назва та ідентифікатор вхідного протоколу;
- string idPolicyId, user; — ідентифікатор політики і користувач автентифікації;
- uint32_t secCnl; — канал безпеки, пов'язаний із сеансом;
- double tInact; — час неактивності;
- int64_t tAccess; — час доступу;
- string servNonce; — випадкова послідовність серверу;
- map<string, ContPoint> cntPnts; — точки продовження запиту огляду;
- deque<string> publishReqs; — перелік запитів публікації.

##### 4.3.2.1 Точка продовження огляду Сеансу Серверу (Server::Sess::ContPoint)

Публічні методи:

- ContPoint( const string &brNode, const string &lstNode, uint32_t brDir, uint32_t refPerN, const string &refTypeId, uint32_t nClassMask, uint32_t resMask ) — Конструктор об'єкту для вузла гілки продовження огляду brNode, вузла списку lstNode, напрямку огляду brDir, числа спроб на вузол refPerN, ідентифікатору посилання refTypeId, маски класу вузла nClassMask та маски результату resMask.
- bool empty( ) const; — Точка продовження порожня.

Публічні атрибути:

- uint32_t brDir, refPerN, nClassMask, resMask; — напрямок огляду, число спроб на вузол, маска класу вузла, маска результату;
- string brNode, lstNode, refTypeId; — гілка вузлів, перелік вузла та ідентифікатор типу посилання.

#### 4.3.3 Підписка Серверу (Server::Subscr)

Публічні методи:

- Subscr copy( bool noWorkData = true ); — Копія об'єкту підписки, без робочих даних для noWorkData.
- SubScrSt setState( SubScrSt st = SS_CUR ); — Поверенення поточного стану та встановлення у st.

Публічні атрибути:

- SubScrSt st; — статус підписки;
- int sess; — сеанс підписки;
- bool publEn; — ввімкнення публікації;
- bool toInit; — ознака ініціації підписки — надсилання першого-порожнього пакету відповіді публікації;
- double publInterv; — інтервал публікації, мілісекунди;
- uint32_t seqN; — номер послідовності для відповідей, завертання через 1, не інкрементується на KeepAlive повідомленнях;
- uint32_t pubCntr, pubCntr_; — лічильник надсилань відповідей публікації для виявлення активності;
- uint32_t lifetimeCnt, wLT; — лічильник, за вичерпанням якого на протязі відсутності повідомлення від клієнту потрібно видаляти цей об'єкт;
- uint32_t maxKeepAliveCnt, wKA; — лічильник, за вичерпанням якого потрібно надсилати порожню відповідь публікації та встановлювати StatusChangeNotification у Bad_Timeout;
- uint32_t maxNtfPerPubl; — максимальна кількість повідомлень на одну відповідь публікації;
- uint8_t pr; — пріоритет;
- vector<MonitItem> mItems; — перелік елементів моніторингу;
- deque<string> retrQueue; — черга перенадсилання; використовується запитом перенадсилання "RePublish"; очищується на глибину згідно KeepAlive або прямим запитом публікації у наборі підтвердження.

##### 4.3.3.1 Елемент Моніторингу Підписки Серверу (Server::Subscr::MonitItem)

Публічні атрибути:

- MonitoringMode md; — режим моніторингу;
- NodeId nd; — цільовий вузол;
- uint32_t aid; — ідентифікатор атрибуту вузла;
- TimestampsToReturn tmToRet; — мітки часу для повернення;
- double smplItv; — інтервал вимірювання;
- uint32_t qSz; — розмір черги;
- bool dO; — відкидати старі;
- uint32_t cH; — вказівник клієнту;
- XML_N fltr; — фільтр;
- int vTp; — тип значень;
- int64_t dtTm; — час останнього значення;
- deque<Val> vQueue; — черга значень.

###### 4.3.3.1.1 Елемент значення Елементу Моніторингу Підписки Серверу (Server::Subscr::MonitItem::Val)

Публічні методи:

- Val( const string &vl, int64_t tm ) — Конструктор об'єкту значення vl на час tm.

Публічні атрибути:

- string vl; — значення;
- int64_t tm; — час значення;
- uint32_t st; — код статусу.

#### 4.3.4 Кінцева Точка Серверу (Server::EP)

Публічні методи:

- EP( Server *serv ); — Конструктор об'єкту Кінцевої Точки до серверу serv.
- virtual string id( ) = 0; — Ідентифікатор.
- virtual string url( ) = 0; — URL.
- virtual string cert( ) = 0; — Сертифікат, текстом формату PEM.
- virtual string pvKey( ) = 0; — Приватний ключ, текстом формату PEM.
- virtual double subscrProcPer( ) = 0; — Загальний мінімальний період циклу публікації та обробки його даних.
- virtual uint32_t limSubScr( ); — Обмеження на кількість підписок.
- virtual uint32_t limMonitItms( ); — Обмеження кількості елементів моніторингу.
- virtual uint32_t limRetrQueueTm( ); — Обмеження часу на глибину черги повторної передачі.
- bool enableStat( ); — Стан "Ввімкнено".
- virtual void setEnable( bool vl ); — Увімкнути.
- virtual void setPublish( const string &inPrtId ); — Ініціювати умови виклику publishCall() у вхідному потоці — циклічний виклик протоколу вхідного транспорту та пов'язання із Кінцевою Точкою.
- void subScrCycle( unsigned cntr ); — Функція виклику циклу обробки підписок на кроку cntr для відповіді у функції publishCall() вхідного потоку.
- int secN( ); — Кількість політик безпеки.
- string secPolicy( int sec ); — Отримання опису політики безпеки isec.
- MessageSecurityMode secMessageMode( int sec ); — Режим безпеки повідомлень політики безпеки sec.
- unsigned sessN( ); — Кількість сеансів.
- int sessCreate( const string &name, double tInact ); — Створення сеансу з назвою name та таймаутом неактивності tInact, повертає ідентифікатор сеансу.
- void sessServNonceSet( int sid, const string &servNonce ); — Встановлення випадкової послідовності серверу у servNonce для сеансу sid.
- virtual uint32_t sessActivate( int sid, uint32_t secCnl, bool check = false, const string &inPrtId = "", const XML_N &identTkn = XML_N() ); — Активація сеансу sid для зв'язування із каналом безпеки secCnl, з перевіркою check на можливість-потребу переназначення після розриву попереднього каналу безпеки, повертає помилку (0 — помилки немає).
- void sessClose( int sid ); — Закриття сеансу sid.
- Sess sessGet( int sid ); — Отримання екземпляру об'єкту сеансу для sid.
- Sess::ContPoint sessCpGet( int sid, const string &cpId ); — Отримання точки продовження огляду cpId сеансу sid.
- void sessCpSet( int sid, const string &cpId, const Sess::ContPoint &cp = Sess::ContPoint() ); — Встановлення точки продовження огляду cp для сеансу sid та ідентифікатору cpId.
- unsigned subscrN( ); — Кількість підписок.
- uint32_t subscrSet( uint32_t ssId, SubScrSt st, bool en = false, int sess = -1, double publInterval = 0, uint32_t lifetimeCnt = 0, uint32_t maxKeepAliveCnt = 0, uint32_t maxNotePerPubl = OpcUa_NPosID, int pr = -1 ); — Встановлення-створення підписки ssId для: стану st, увімкнення публікації en, сеансу sess, інтервалу публікації publInterv, лічильнику часу життя lifetimeCnt, лічильнику збереження "живим" maxKeepAliveCnt, максимальної кількості повідомлень у одній публікації maxNotePerPubl, пріоритету pr; повертає ідентифікатор підписки.
- Subscr subscrGet( uint32_t ssId, bool noWorkData = true ); — Отримання екземпляру підписки ssId, без робочих даних noWorkData.
- uint32_t mItSet( uint32_t ssId, uint32_t mItId, MonitoringMode md = MM_CUR, const NodeId &nd = NodeId(), uint32_t aid = OpcUa_NPosID, TimestampsToReturn tmToRet = TimestampsToReturn(-1), double smplItv = -2, uint32_t qSz = OpcUa_NPosID, int8_t dO = -1, uint32_t cH = OpcUa_NPosID, XML_N *fltr = NULL ); — Встановлення-сотворення елементу моніторингу mItId сеансу ssId для: режиму md, вузла nd, атрибуту aid, профілю мітки часу tmToRet, інтервалу вимірювання smplItv, розміру черги qSz, відкидання старих dO, вказівника клієнту cH, фільтру fltr; повертає ідентифікатор елементу моніторингу.
- Subscr::MonitItem mItGet( uint32_t ssId, uint32_t mItId ); — Отримання екземпляру елементу моніторингу mItId для сеансу ssId.
- virtual uint32_t reqData( int reqTp, XML_N &req ); — Обробник запиту даних — запит до дерева вузлів серверу.

Захищені методи:

- XML_N *nodeReg( const NodeId &parent, const NodeId &ndId, const string &name, int ndClass, const NodeId &refTypeId, const NodeId &typeDef = 0 ); — Реєстрація вузла ndId у дереві вузлів серверу для: батька parent, класу вузла ndClass, ідентифікатору типу посилання refTypeId та типу визначення typeDef.
- Sess *sessGet_( int sid ); — Отримання посилання на об'єкт сеансу sid, доступ не захищено захопленням ресурсу.

Захищені атрибути:

- char mEn; — стан "Ввімкнено";
- uint64_t cntReq; — лічильник запитів;
- vector<SecuritySetting> mSec; — перелік політик безпеки кінцевого вузла;
- vector<Sess> mSess; — перелік відкритих сеансів;
- vector<Subscr> mSubScr; — перелік підписок;
- XML_N objTree; — дерево вузлів серверу;
- map<string, XML_N*> ndMap; — карта посилань на вузли дерева;
- pthread_mutex_t> mtxData; — мютекс блокування багатопотокового доступу;
- Server *serv; — посилання на сервер — контейнер об'єкту кінцевої точки.

## 5 Приватні ключі та сертифікати

Для роботи клієнтської та серверної-протокольної частини OPC-UA потрібно створення та розташування приватного ключа і сертифікату у конфігурації об'єкту клієнта та сервера. У загальному випадку достатньо створення звичайного самопідписаного сертифікату та приватного ключа без пароля, однак, для виключення попереджувальних повідомлень, потрібно додати низку службових полів до сертифікату. Це можна виконати взявши файл конфігурації створення сертифікату та виконати наступну процедуру:

    # Створення приватного ключа:
    openssl genrsa -out key_c.pem -des3 -rand /var/log/messages 2048
    # Створення приватного ключа без пароля:
    openssl rsa -in key_c.pem -out key_c1.pem
    # Створення самопідписаного сертифікату:
    openssl req -x509 -new -key key_c.pem -out cert_c.pem -config ./OPC-UA_openssl.cnf -days 3650
    # Розташувати вміст файлу key_c1.pem у поле приватного ключа та cert_c.pem у поле сертифікату!

## 6 Зауваження

У процесі реалізації модулів підтримки OPC-UA було виявлено низку невідповідностей офіційного SDK зі специфікацією OPC-UA:

- OPC-UA Part 6 на сторінці 27 містить зображення процесу рукостискання для встановлення безпечного каналу. Пакет створення сесії, виходячи із цього процесу, підписується клієнтським симетричним ключем, а кодування серверним. Насправді і підпис і шифрування здійснюється серверним ключем.
- OPC-UA Part 4 на сторінці 141 містить опис структури даних підпису, де перший йдуть дані підпису, а потім рядок алгоритму. Насправді реалізовано зворотна послідовність.

## 7 Таблиця сумісності із реалізаціями OPC-UA інших виробників

ПЗ | Ядро | Огляд | Читання | Запис | Публікація | Зауваження
--- | --- | --- | --- | --- | --- | ---
OpenSCADA parts
OpenSCADA OPC-UA Client (libOPC_UA client part) | + | + | + | + | + | IO requests by XML implemented: HEL (HELLO), OPN (OpenSecureChannel), CLO (CloseSecureChannel), FindServers, GetEndpoints, CreateSession, ActivateSession, CloseSession, Read, Write, Browse, CreateSubscription, DeleteSubscriptions, CreateMonitoredItems, DeleteMonitoredItems, Publish, Poll (the special empty request of checking the input channel). Chunks implemented.
OpenSCADA OPC-UA Server (libOPC_UA server part) | + | + | + | + | + | The requests implemented: HELF, OPNF, CLOF, MSGF: FindServers, GetEndpoints, CreateSession, ActivateSession, CloseSession, CreateSubscription, ModifySubscription, DeleteSubscriptions, MonitoredItems, ModifyMonitoredItems, SetMonitoringMode, DeleteMonitoredItems, SetPublishingMode, TranslateBrowsePathsToNodeIds, RegisterNodes, UnregisterNodes, Browse, BrowseNext, Read, Write, Publish, Republish. Chunks implemented.
Clients
UAExpert 1.2, 1.3 | Pass | Pass | Pass | Pass | Pass |
Indusoft web studio 7.1 | Pass | Pass | Pass | Pass | Pass |
Iconics genesis64 10.8 | Pass | Pass | Pass | Pass | Pass |
Insat masterscada 3.7 | Pass | Pass | Pass | Pass | Pass |
Sample Applications of Unified Architecture | Pass | Pass | Pass | Not tested | Pass |
Wonderware System Platform | Pass | Pass | Pass | Not tested | Pass | Result mask processing fix into the service "Browse" for nodes of OpenSCADA data model. ...
Kepware | Pass | Pass | Pass | Pass | Pass | Specific value types OpcUa_IntAuto and OpcUa_UIntAuto was added for adaptive integer type selection, mostly for provide integer not fixed as int64. Time stamp was removed from "Write" package but the client tell 0x80730000(OpcUa_BadWriteNotSupported)
UAExpert 1.4 | Pass | Pass | Pass | Pass | Pass | Packages sequence number split from it request and set self managing.
UAExpert 1.5 | Pass | Pass | Pass | Pass | Pass | The Server code cleaned from inconsistency of the data types and the types appended for declaration own OpenSCADA types OpcUa_IntAuto and OpcUa_UIntAuto.
Servers
IgnitionOPC_UA | Pass | Pass | Pass | Not tested | Not tested |
B&R Embedded OPC-UA Server | Pass | Pass | Pass | Pass | Pass | the authenticate process fixed by the server provides self specific identifiers to its. The string of bytes wrong interpretation fixed; 2021.05: has limits on direct reading by the service request "Read", so that was an initiator of implementing the service request "Publish" and Chunks for the Client part, UAExpert 1.5 adaption, significant refactoring and the document complete revision.

## 8 Посилання

- Діаграма: Статична діаграма класів бібліотеки libOPC_UA.
- Файл конфігурації створення сертифікату для OPC-UA.

Modules/OPC_UA/uk - GFDL | July 2026 | OpenSCADA 1+r3070