В данной статье мы рассмотрим процесс создания простого OPC UA сервера с использованием популярной библиотеки node-opcua.

Что такое OPC UA?
OPC UA (Unified Architecture) — это стандарт промышленной автоматизации, который обеспечивает обмен данными между оборудованием, системами управления и приложениями. Он активно используется в системах IoT и промышленности 4.0.
Зачем использовать Node.js?
Node.js — это платформа, основанная на JavaScript, которая идеально подходит для разработки серверных приложений благодаря своей асинхронной модели ввода-вывода. С помощью библиотеки node-opcua мы можем быстро разрабатывать надежные OPC UA серверы.
Подготовка к работе
Перед началом убедитесь, что Node.js установлен на вашем компьютере. Установить Node.js можно, следуя инструкциям на официальном сайте.
Создание проекта
Создайте новую директорию для проекта:
mkdir myserver cd myserverИнициализируйте проект Node.js:
npm init -yУстановите библиотеку node-opcua:
npm install node-opcua --save
Теперь проект готов к разработке.
Написание скрипта сервера
Создайте файл server.js и начните с подключения необходимых модулей:
const { OPCUAServer, Variant, DataType, StatusCodes } = require("node-opcua"); const os = require("os");
Шаг 1: Создание экземпляра сервера
Инициализируйте сервер:
const server = new OPCUAServer({ port: 4334, resourcePath: "/UA/MyLittleServer", buildInfo: { productName: "MySampleServer", buildNumber: "1", buildDate: new Date() } });
Шаг 2: Инициализация сервера
Инициализация сервера выполняется асинхронно:
(async () => { await server.initialize(); console.log("Сервер инициализирован."); })();
Шаг 3: Добавление объектов и переменных
Мы создадим объект MyDevice и добавим в него переменные.
Добавление объекта
const addressSpace = server.engine.addressSpace; const namespace = addressSpace.getOwnNamespace(); const device = namespace.addObject({ organizedBy: addressSpace.rootFolder.objects, browseName: "MyDevice" });
Добавление переменной для чтения
let variable1 = 1; setInterval(() => { variable1 += 1; }, 500); namespace.addVariable({ componentOf: device, browseName: "MyVariable1", dataType: "Double", value: { get: () => new Variant({ dataType: DataType.Double, value: variable1 }) } });
Добавление переменной для чтения и записи
let variable2 = 10.0; namespace.addVariable({ componentOf: device, browseName: "MyVariable2", nodeId: "ns=1;s=MyVariable2", dataType: "Double", value: { get: () => new Variant( { dataType: DataType.Double, value: variable2 }), set: (variant) => { variable2 = parseFloat(variant.value); return StatusCodes.Good; } } });
Добавление переменной для отображения свободной памяти
namespace.addVariable({ componentOf: device, browseName: "FreeMemory", nodeId: "s=free_memory", dataType: "Double", value: { get: () => new Variant({ dataType: DataType.Double, value: os.freemem() / os.totalmem() * 100.0 }) } });
Шаг 4: Запуск сервера
После настройки всех переменных запустите сервер:
(async () => { await server.start(); console.log("Сервер запущен."); console.log("URL:", server.endpoints[0].endpointDescriptions()[0].endpointUrl); })();
Тестирование сервера
Сохраните файл server.js и выполните его:
node server.js
После запуска сервер будет доступен по адресу, указанному в консоли. Теперь его можно подключить к OPC UA клиенту для тестирования.
Полный код доступен здесь:
Скрытый текст
const { OPCUAServer, Variant, DataType, DataValue, StatusCodes } = require("node-opcua"); (async () => { // Let's create an instance of OPCUAServer const server = new OPCUAServer({ port: 4334, // the port of the listening socket of the server resourcePath: "/UA/MyLittleServer", // this path will be added to the endpoint resource name buildInfo: { productName: "MySampleServer1", buildNumber: "7658", buildDate: new Date(2014, 5, 2) } }); await server.initialize(); console.log("initialized"); const addressSpace = server.engine.addressSpace; const namespace = addressSpace.getOwnNamespace(); // declare a new object const device = namespace.addObject({ organizedBy: addressSpace.rootFolder.objects, browseName: "MyDevice" }); // add some variables // add a variable named MyVariable1 to the newly created folder "MyDevice" // emulate variable1 changing every 500 ms var uaVariable1 = namespace.addVariable({ componentOf: device, browseName: "MyVariable1", dataType: "Double" }); let variable1 = 1; const timerId = setInterval(() => { variable1 += 1; uaVariable1.setValueFromSource(new Variant({ dataType: DataType.Double, value: variable1 })); }, 500); addressSpace.registerShutdownTask(() => { clearInterval(timerId); }); const uaVariable2 = namespace.addVariable({ componentOf: device, nodeId: "ns=1;b=1020FFAA", // some opaque NodeId in namespace 4 browseName: "MyVariable2", dataType: "Double", accessLevel: "CurrentRead | CurrentWrite", }); const os = require("os"); /** * returns the percentage of free memory on the running machine * @return {double} */ function available_memory() { // var value = process.memoryUsage().heapUsed / 1000000; const percentageMemUsed = (os.freemem() / os.totalmem()) * 100.0; return percentageMemUsed; } namespace.addVariable({ componentOf: device, nodeId: "s=free_memory", // a string nodeID browseName: "FreeMemory", dataType: "Double", minimumSamplingInterval: 1000, // we need to specify a minimumSamplingInterval when using a getter value: { get: () => new Variant({ dataType: DataType.Double, value: available_memory() }) } }); const uaVariable3 = namespace.addVariable({ componentOf: device, nodeId: "s=process_name", // a string nodeID browseName: "ProcessName", dataType: "Float", minimumSamplingInterval: 100, value: { timestamped_get: () => new DataValue({ statusCode: StatusCodes.Good, sourceTimestamp: new Date(), serverTimestamp: new Date(), value: new Variant({ dataType: DataType.Float, value: Math.random() }) }) } }); server.start(function() { console.log("Server is now listening ... ( press CTRL+C to stop)"); console.log("port ", server.endpoints[0].port); const endpointUrl = server.endpoints[0].endpointDescriptions()[0].endpointUrl; console.log(" the primary server endpoint url is ", endpointUrl); }); })();
Заключение
Мы создали базовый OPC UA сервер с помощью Node.js и библиотеки node-opcua. Вы можете расширить этот сервер, добавляя собственные объекты и переменные, чтобы удовлетворить ваши требования.
