
В статье приведены примеры использования библиотеки OpcUaHelper.dll для работы с узлами OPC UA сервера на C#: подключение, просмотр узлов, чтение и запись значений. Материал охватывает одиночные и пакетные операции, а также чтение по подписке.
- Для работы устанавливается пакет OpcUaHelper через NuGet и подключается пространство имён using OpcUaHelper.
- В качестве тестового OPC UA сервера используется симулятор Codesys 3.5 с настроенным OPC UA сервером.
- Браузер узлов Node browser позволяет получить конфигурацию сервера и адреса узлов.
- Экземпляр OpcUaClient подключается к серверу асинхронно и отключается при закрытии формы.
- Чтение реализуется одиночным методом ReadNode, пакетным ReadNodes и подпиской через AddSubscription.
- Запись выполняется методом WriteNodes для нескольких узлов одновременно.
- OPC UA
- OpcUaHelper.dll
- OpcUaClient
- Node browser
- Codesys 3.5
- NodeId
- DataValue
- MonitoredItem
Кому полезно: Инженерам АСУ ТП и разработчикам на C#, работающим с OPC UA серверами.
Первоисточник: digielectric.ru
Выжимка составлена редакцией сайта с помощью ИИ по тексту статьи.
OPC UA [унифицированная архитектура OPC] является относительно новой и достаточно распространенной технологией «общения» между машинами. В данной статье приведу примеры того, как можно использовать методы, предоставляемы библиотекой классов OpcUaHelper.dll для осуществления операций с узлами сервера.
Предварительная подготовка
В диспетчере пакетов NuGet установите пакет OpcUaHelper, затем подключите пространство имен следующим образом:
using OpcUaHelper;
Подготовка сервера OPC UA
Для проведения тестов можно использовать любой Opc Ua сервер. В случае, если Opc Ua сервер отсутствует, можно создать тестовое скрипт на Python. Я, в качестве Opc Ua сервера использую симулятор Codesys 3.5. Скачать проект для CodeSys 3.5 SP20 с настроенным Opc Ua сервером можно здесь.
Node browser
Для проведения тестов можно использовать любой Opc Ua сервер. В случае, если Opc Ua сервер отсутствует, можно создать тестовое скрипт на Python. Я, в качестве Opc Ua сервера использую симулятор Codesys 3.5. Скачать проект для CodeSys 3.5 SP20 с настроенным Opc Ua сервером можно здесь.
При помощи браузера узлов Node browser можно получить данные о конфигурации сервера. Это позволит создать карту узлов Opc Ua сервера, узнать об адресах узлов сервера.
private void btnShowBrowse_Click(object sender, EventArgs e)
{
using (FormBrowseServer form = new FormBrowseServer())
{
form.ShowDialog();
}
}
Создание экземпляра Opc Ua клиента
//Экземпляр Opc Ua сервера
private OpcUaClient opcUaClient = new OpcUaClient();
//Асинхронный метод, вызываемый при загрузке формы
//В методе осуществляется подключение к Opc Ua серверу: opc.tcp://127.0.0.1:4840/Opc
private async void Form1_Load(object sender, EventArgs e)
{
//Авторизация (при необходимости)
opcUaClient.UserIdentity = new Opc.Ua.UserIdentity("ВАШ ЛОГИН", "ВАШ ПАРОЛЬ");
//Подключение к серверу
await opcUaClient.ConnectServer("opc.tcp://127.0.0.1:4840/MyFirstOpc");
}
//Метод, вызываемый при закрытии формы
//В методе осуществляется отключение от Opc Ua сервера
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
opcUaClient.Disconnect();
}
Просмотр локально зарегистрированных серверов
//Метод, вызываемый при нажатии на кнопку = Просмотр зарегистрированных Opc Ua серверов
private void btnDiscoverServer_Click( object sender, EventArgs e )
{
// Получение адреса зарегистрированного сервера
string endpointUrl = new Opc.Ua.Client.Controls.DiscoverServerDlg( ).ShowDialog( opcUaClient.AppConfig, null );
// Получить адрес, зарегистрированный другими серверами. Обратите внимание, что политика безопасности IP должна быть настроена правильно
// string endpointUrl = new Opc.Ua.Client.Controls.DiscoverServerDlg( ).ShowDialog( opcUaClient.AppConfig, "192.168.0.100" );
if (!string.IsNullOrEmpty( endpointUrl ))
{
// Получить адрес сервера, которым нужно управлять
}
}
Операция одиночного чтения узла
/// <summary>
/// Операция чтения узла
/// </summary>
private void btnReadSingleNode_Click(object sender, EventArgs e)
{
try
{
float value = opcUaClient.ReadNode<float>("ns=2;s=VibroSensors!AxX");
MessageBox.Show ($"Уровень жидкости в резервуаре: {value} %");
}
catch(Exception ex)
{
MessageBox.Show ($"{ex.Message}}");
}
}
Операция пакетного чтения узлов
/// <summary>
/// Операция пакетного чтения узлов с неизвестными типами
/// </summary>
private void btnReadNodesAsUnknowTypes_Click(object sender, EventArgs e)
{
try
{
// Инициализация списка с узлами, значение которых необходимо прочитать
List<NodeId> nodeList = new List<NodeId>( )
{
new NodeId ("ns=2;s=VibroSensors!AxX"),
new NodeId ("ns=2;s=VibroSensors!AxY"),
new NodeId ("ns=2;s=VibroSensors!AxZ")
};
// Пакетное чтение значений выбранных узлов
List<DataValue> uDataValues = opcUaClient.ReadNodes(nodeList.ToArray());
// В данном цикле получение прочитанного значения узла
// в виде object
foreach (var dataValue in uDataValues)
{
object value = dataValue.WrappedValue.Value;
// ВАШ КОД ...
}
}
catch (Exception ex)
{
ClientUtils.HandleException( this.Text, ex );
}
}
/// <summary>
/// Операция пакетного чтения узлов с определенными (известными) типами данных
/// </summary>
private void btnReadNodesAsKnowTypes_Click(object sender, EventArgs e)
{
try
{
// Если типы значений, которые вы читаете в пакетах, одинаковы, например, float, то есть удобный способ
List<string> tags = new List<string>( )
{
"ns=2;s=VibroSensors!AxX",
"ns=2;s=VibroSensors!AxY",
"ns=2;s=VibroSensors!AxZ"
};
// Значения определены в порядке
List<float> values = opcUaClient.ReadNodes<float>( tags.ToArray() );
}
catch (Exception ex)
{
ClientUtils.HandleException( this.Text, ex );
}
}
Операция чтения узла по подписке
/// <summary>
/// Обработка нажатия кнопки - подвисаться
/// </summary>
private void btnSubscribe_Click( object sender, EventArgs e )
{
OpcUaClient.AddSubscription("AxX", "ns=2;s=VibroSensors!AxX", SubCallback);
}
/// <summary>
/// Функция Callback
/// </summary>
private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args )
{
if (InvokeRequired)
{
Invoke( new Action<string, MonitoredItem, MonitoredItemNotificationEventArgs>(SubCallback), key, monitoredItem, args );
return;
}
// Обработка события по ключу
if (key == "AxX")
{
MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
if (notification != null)
{
txbVibroAxX.Text = notification.Value.WrappedValue.Value.ToString( );
}
}
}
Операция одиночной записи узла
/// <summary>
/// Операция чтения узла
/// </summary>
private void btnReadSingleNode_Click(object sender, EventArgs e)
{
try
{
float value = opcUaClient.ReadNode<float>("ns=2;s=VibroSensors!AxX");
MessageBox.Show ($"Уровень жидкости в резервуаре: {value} %");
}
catch(Exception ex)
{
MessageBox.Show ($"{ex.Message}}");
}
}
Операция пакетной записи узлов
/// <summary>
/// Пакетная запись значений в узлы
/// </summary>
private void btnWriteMultiNodes_Click(object sender, EventArgs e)
{
// Определение имен узлов, в которые
// необходимо записать значения
string[] nodes = new string[]
{
"ns=2;s=VibroSensors!AxX",
"ns=2;s=VibroSensors!AllSensors"
};
object[] data = new object[]
{
4, new float[]{2.1, 2.0, 1.9, 1.98, 1.99, 2.05}
};
// Запись данных в узлы Opc Ua сервера
bool result = opcUaClient.WriteNodes(nodes, data);