node-red-contrib-iiot-opcua
Version:
An Industrial IoT OPC UA toolbox contribution package for Node-RED based on node-opcua.
937 lines (934 loc) • 41.8 kB
JavaScript
/**
The BSD 3-Clause License
Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
Copyright 2015,2016 - Mika Karaila, Valmet Automation Inc. (node-red-contrib-opcua)
All rights reserved.
node-red-contrib-iiot-opcua
*/
'use strict';
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_opcua_1 = require("node-opcua");
const opcua_iiot_core_1 = require("./opcua-iiot-core");
const debug_1 = __importDefault(require("debug"));
const path_1 = __importDefault(require("path"));
const alarms_and_conditions_demo_1 = require("../helpers/alarms-and-conditions-demo");
const internalDebugLog = (0, debug_1.default)('opcuaIIoT:server'); // eslint-disable-line no-use-before-define
const detailDebugLog = (0, debug_1.default)('opcuaIIoT:server:details'); // eslint-disable-line no-use-before-define
const isa95DebugLog = (0, debug_1.default)('opcuaIIoT:server:ISA95'); // eslint-disable-line no-use-before-define
const isa95DetailDebugLog = (0, debug_1.default)('opcuaIIoT:server:ISA95:details'); // eslint-disable-line no-use-before-define
const flex = {}; // eslint-disable-line no-use-before-define
const flexInternalDebugLog = (0, debug_1.default)('opcuaIIoT:server:flex'); // eslint-disable-line no-use-before-define
const flexDetailDebugLog = (0, debug_1.default)('opcuaIIoT:server:flex:details'); // eslint-disable-line no-use-before-define
let simulatorInterval = null; // eslint-disable-line no-use-before-define
const maxTimeInterval = 500000; // eslint-disable-line no-use-before-define
let timeInterval = 1; // eslint-disable-line no-use-before-define
const UNLIMITED_LISTENERS = 0; // eslint-disable-line no-use-before-define
let intervalList = []; // eslint-disable-line no-use-before-define
let conditions = [];
const simulateVariation = function (data) {
let value = (1.0 + Math.sin(timeInterval / 360 * 3)) / 2.0;
timeInterval++;
if (timeInterval > maxTimeInterval) {
timeInterval = 1;
}
if (data.tankLevel) {
data.tankLevel.setValueFromSource({ dataType: 'Double', value });
}
if (data.tankLevel2) {
data.tankLevel2.setValueFromSource({ dataType: 'Double', value });
}
};
const constructAddressSpaceFromScript = function (server, constructAddressSpaceScript, eventObjects) {
return new Promise((resolve, reject) => {
if (server.engine && constructAddressSpaceScript && constructAddressSpaceScript !== '') {
try {
constructAddressSpaceScript(server, server.engine.addressSpace, eventObjects, resolve);
}
catch (err) {
reject(err);
}
}
else {
reject(new Error('Wrong Parameters Construct AddressSpace From Script'));
}
});
};
const constructAddressSpace = function (server, asoDemo) {
return new Promise((resolve, reject) => {
var _a;
if (!server) {
reject(new Error('Server Not Valid To Construct Address Space'));
return;
}
const addressSpace = (_a = server.engine) === null || _a === void 0 ? void 0 : _a.addressSpace;
if (!addressSpace) {
reject(new Error('No AddressSpace From OPC UA Server Engine'));
return;
}
addressSpace.installAlarmsAndConditionsService();
const namespace = addressSpace.getOwnNamespace();
const exclusiveLimitAlarmType = addressSpace.findEventType('ExclusiveLimitAlarmType');
if (!exclusiveLimitAlarmType) {
throw new Error("cannot find ExclusiveLimitAlarmType in namespace 0");
}
let nonExclusiveLimitAlarmType = addressSpace.findEventType('NonExclusiveLimitAlarmType');
if (!nonExclusiveLimitAlarmType) {
throw new Error("cannot find NonExclusiveLimitAlarmType in namespace 0");
}
let view = namespace.addView({
organizedBy: addressSpace === null || addressSpace === void 0 ? void 0 : addressSpace.rootFolder.views,
browseName: 'PLUS4NODERED_VIEW',
displayName: [
new node_opcua_1.LocalizedText({ text: 'OPCUA-IIoT plus4nodered.com Server View', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'OPCUA-IIoT plus4nodered.com Server Sicht', locale: 'de-DE' })
]
});
if (!asoDemo) {
resolve(null);
}
else {
let data = {};
(0, alarms_and_conditions_demo_1.constructAlarmAddressSpaceDemo)(data, addressSpace);
timeInterval = 1;
simulatorInterval = setInterval(function () {
simulateVariation(data);
}, 500);
intervalList.push(simulatorInterval);
let vendorName = namespace.addObject({
organizedBy: addressSpace.rootFolder.objects,
typeDefinition: 'FolderType',
nodeId: 'i=1234',
browseName: 'PLUS4NODERED',
displayName: [
new node_opcua_1.LocalizedText({ text: 'OPCUA-IIoT plus4nodered.com Server', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'OPCUA-IIoT plus4nodered.com Server', locale: 'de-DE' })
],
eventNotifier: 1,
notifierOf: addressSpace.rootFolder.objects.server
});
let variable1 = 1;
intervalList.push(setInterval(function () {
if (variable1 < 1000000) {
variable1 += 1;
}
else {
variable1 = 0;
}
}, 100));
namespace.addVariable({
componentOf: vendorName,
nodeId: 'i=16479',
browseName: 'MyVariable1',
displayName: 'PLUS for Node-RED Double Variable',
dataType: 'Double',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Double',
value: variable1
});
}
}
});
let variable2 = 10.0;
namespace.addVariable({
componentOf: vendorName,
nodeId: 'b=1020FFAA',
browseName: 'MyVariable2',
displayName: 'PLUS for Node-RED Double Binary Variable',
dataType: 'Double',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Double',
value: variable2
});
},
set: function (variant) {
variable2 = parseFloat(variant.value);
return node_opcua_1.StatusCodes.Good;
}
}
});
let variable3 = 1000.0;
namespace.addVariable({
componentOf: vendorName,
nodeId: 's=TestReadWrite',
browseName: 'TestReadWrite',
displayName: 'PLUS for Node-RED Test Read and Write',
dataType: 'Double',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Double',
value: variable3
});
},
set: function (variant) {
variable3 = parseFloat(variant.value);
return node_opcua_1.StatusCodes.Good;
}
}
});
let memoryVariable = namespace.addVariable({
componentOf: vendorName,
nodeId: 's=free_memory',
browseName: 'FreeMemory',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Free Memory', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Freier Arbeitsspeicher', locale: 'de-DE' })
],
dataType: 'Double',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Double',
value: (0, opcua_iiot_core_1.availableMemory)()
});
}
}
});
addressSpace.installHistoricalDataNode(memoryVariable);
let counterValue = 0;
intervalList.push(setInterval(function () {
if (counterValue < 65000) {
counterValue += 1;
}
else {
counterValue = 0;
}
}, 1000));
let counterVariable = namespace.addVariable({
componentOf: vendorName,
nodeId: 's=Counter',
browseName: 'Counter',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Counter', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Zähler', locale: 'de-DE' })
],
dataType: 'UInt16',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'UInt16',
value: counterValue
});
}
}
});
addressSpace.installHistoricalDataNode(counterVariable);
let fullCounterValue = 8900;
let fullCounterVariable = namespace.addVariable({
componentOf: vendorName,
eventSourceOf: vendorName,
nodeId: 's=FullCounter',
browseName: 'FullCounter',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Full-Counter', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Voll-Zähler', locale: 'de-DE' })
],
dataType: 'Int32',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Int32',
value: fullCounterValue
});
}
}
});
addressSpace.installHistoricalDataNode(fullCounterVariable);
namespace.instantiateNonExclusiveLimitAlarm(nonExclusiveLimitAlarmType, {
componentOf: vendorName,
conditionSource: fullCounterVariable,
browseName: 'FullCounterLimitCondition',
displayName: new node_opcua_1.LocalizedText({ text: 'Full Counter Limit Condition', locale: 'en-US' }),
description: 'ExclusiveLimitAlarmType Condition',
conditionName: 'FullCounterLimitCondition',
inputNode: fullCounterVariable,
highHighLimit: 9990,
highLimit: 9000,
lowLimit: -9000,
lowLowLimit: -9990,
optionals: [
"ConfirmedState", "Confirm" // confirm state and confirm Method
]
});
intervalList.push(setInterval(function () {
if (fullCounterValue < 10000) {
fullCounterValue += 1;
}
else {
fullCounterValue = -10000;
}
fullCounterVariable.setValueFromSource({
dataType: node_opcua_1.DataType.Int32,
value: fullCounterValue
});
}, 100));
let externalValueWithSourceTimestamp = new node_opcua_1.DataValue({
value: new node_opcua_1.Variant({ dataType: 'Double', value: 10.0 }),
sourceTimestamp: null,
sourcePicoseconds: 0
});
intervalList.push(setInterval(function () {
externalValueWithSourceTimestamp.value.value = Math.random();
externalValueWithSourceTimestamp.sourceTimestamp = new Date();
}, 1000));
namespace.addVariable({
organizedBy: vendorName,
nodeId: 's=Pressure',
browseName: 'Pressure',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Pressure', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Druck', locale: 'de-DE' })
],
dataType: 'Double',
value: {
timestamped_get: function () {
return externalValueWithSourceTimestamp;
}
}
});
namespace.addVariable({
organizedBy: vendorName,
nodeId: 's=Matrix',
browseName: 'Matrix',
displayName: [new node_opcua_1.LocalizedText({ text: 'P4NR Matrix', locale: 'en-US' })],
dataType: 'Double',
valueRank: 2,
arrayDimensions: [3, 3],
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Double',
arrayType: node_opcua_1.VariantArrayType.Matrix,
dimensions: [3, 3],
value: [1, 2, 3, 4, 5, 6, 7, 8, 9]
});
}
}
});
namespace.addVariable({
organizedBy: vendorName,
nodeId: 's=Position',
browseName: 'Position',
displayName: [new node_opcua_1.LocalizedText({ text: 'P4NR Position', locale: 'en-US' })],
dataType: 'Double',
valueRank: 1,
arrayDimensions: null,
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Double',
arrayType: node_opcua_1.VariantArrayType.Array,
value: [1, 2, 3, 4]
});
}
}
});
let pumpSpeed = namespace.addVariable({
organizedBy: vendorName,
nodeId: 's=PumpSpeed',
browseName: 'PumpSpeed',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Pump Speed', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Geschwindigkeit Pumpe', locale: 'de-DE' })
],
dataType: 'Double',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Double',
value: 200 + 100 * Math.sin(Date.now() / 10000)
});
}
}
});
namespace.addVariable({
organizedBy: vendorName,
nodeId: 's=SomeDate',
browseName: 'SomeDate',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Some Date', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Einfaches Datum', locale: 'de-DE' })
],
dataType: 'DateTime',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: node_opcua_1.DataType.DateTime,
value: new Date(Date.UTC(2016, 9, 13, 8, 40, 0))
});
}
}
});
namespace.addVariable({
organizedBy: vendorName,
nodeId: 's=MultiLanguageText',
browseName: 'MultiLanguageText',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Multi Language Text', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Mehrsprachiger Text', locale: 'de-DE' })
],
dataType: 'LocalizedText',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: node_opcua_1.DataType.LocalizedText,
value: [{ text: 'multilingual text', locale: 'en' },
{ text: 'plus4nodered.de mehrsprachiger Text', locale: 'de' },
{ text: 'plus4nodered.com texte multilingue', locale: 'fr' }]
});
}
}
});
let fanSpeed = namespace.addVariable({
organizedBy: vendorName,
nodeId: 's=FanSpeed',
browseName: 'FanSpeed',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Fan Speed', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Geschwindigkeit Lüfter', locale: 'de-DE' })
],
dataType: 'Double',
value: new node_opcua_1.Variant({ dataType: 'Double', value: 1000.0 })
});
intervalList.push(setInterval(function () {
fanSpeed.setValueFromSource(new node_opcua_1.Variant({
dataType: 'Double',
value: 1000.0 + (Math.random() * 100 - 50)
}));
}, 10));
let method = namespace.addMethod(vendorName, {
nodeId: 'i=12345',
browseName: 'Bark',
inputArguments: [
{
name: 'barks',
dataType: 'UInt32',
description: { text: 'specifies the number of time I should bark' }
}, {
name: 'volume',
dataType: 'UInt32',
description: { text: 'specifies the sound volume [0 = quiet ,100 = loud]' }
}
],
outputArguments: [{
name: 'Barks',
dataType: 'String',
description: { text: 'the generated barks' },
valueRank: 1
}]
});
method.bindMethod(function (inputArguments, context, callback) {
let nbBarks = inputArguments[0].value;
let volume = inputArguments[1].value;
let soundVolume = new Array(volume).join('!');
let barks = [];
for (let i = 0; i < nbBarks; i++) {
barks.push('Whaff' + soundVolume);
}
let callMethodResult = {
statusCode: node_opcua_1.StatusCodes.Good,
outputArguments: [{
dataType: node_opcua_1.DataType.String,
arrayType: node_opcua_1.VariantArrayType.Array,
value: barks
}]
};
callback(null, callMethodResult);
});
let temperatureValue = 170;
let analogItemNode = namespace.addAnalogDataItem({
componentOf: vendorName,
eventSourceOf: vendorName,
nodeId: 's=TemperatureAnalogItem',
browseName: 'TemperatureAnalogItem',
displayName: [
new node_opcua_1.LocalizedText({ text: 'P4NR Temperature', locale: 'en-US' }),
new node_opcua_1.LocalizedText({ text: 'P4NR Temperatur', locale: 'de-DE' })
],
definition: '(tempA -25) + tempB',
valuePrecision: 0.5,
engineeringUnitsRange: { low: 100, high: 200 },
instrumentRange: { low: -100, high: +200 },
engineeringUnits: node_opcua_1.standardUnits.degree_celsius,
dataType: 'Double',
value: {
get: function () {
return new node_opcua_1.Variant({
dataType: 'Double',
value: temperatureValue
});
}
}
});
namespace.instantiateExclusiveLimitAlarm(exclusiveLimitAlarmType, {
componentOf: vendorName,
conditionSource: analogItemNode,
browseName: 'TemperatureLimitCondition',
displayName: new node_opcua_1.LocalizedText({ text: 'Temperature Limit Condition', locale: 'en-US' }),
description: 'ExclusiveLimitAlarmType Condition',
conditionName: 'TemperatureLimitCondition',
inputNode: analogItemNode,
highHighLimit: 240,
highLimit: 200,
lowLimit: 100,
lowLowLimit: 10,
optionals: [
"ConfirmedState", "Confirm" // confirm state and confirm Method
]
});
intervalList.push(setInterval(function () {
if (temperatureValue < 250) {
temperatureValue += 0.5;
}
else {
temperatureValue = -40;
}
analogItemNode.setValueFromSource({
dataType: node_opcua_1.DataType.Double,
value: temperatureValue
});
}, 500));
view.addReference({
referenceType: 'Organizes',
nodeId: pumpSpeed.nodeId
});
resolve('');
}
});
};
const buildGeneralServerOptions = (node, prefix) => __awaiter(void 0, void 0, void 0, function* () {
let serverOptions = yield buildServerOptions(node, prefix);
serverOptions.userManager = {
isValidUser: function (userName, password) {
return checkUser(node, userName, password);
}
};
return setDiscoveryOptions(node, serverOptions);
});
const destructAddressSpace = function (done) {
intervalList.forEach(function (value, index, list) {
clearInterval(value);
list[index] = null;
});
intervalList = [];
done();
};
const start = function (server, node) {
return new Promise(function (resolve, reject) {
if (!server) {
reject(new Error('Server Not Valid To Start'));
return;
}
if (!node) {
reject(new Error('Node Not Valid To Start'));
return;
}
server.start(() => {
var _a;
node.iiot.initialized = true;
if ((_a = server.endpoints) === null || _a === void 0 ? void 0 : _a.length) {
server.endpoints.forEach((endpoint) => {
endpoint.endpointDescriptions().forEach((endpointDescription) => {
var _a;
internalDebugLog('Server endpointUrl:', endpointDescription.endpointUrl, 'securityMode:', endpointDescription.securityMode.toString(), 'securityPolicyUri:', endpointDescription.securityPolicyUri ? (_a = endpointDescription.securityPolicyUri) === null || _a === void 0 ? void 0 : _a.toString() : 'None Security Policy Uri');
});
});
let endpointUrl = server.endpoints[0].endpointDescriptions()[0].endpointUrl;
internalDebugLog('Primary Server Endpoint URL ' + endpointUrl);
}
server.on('newChannel', function (channel) {
internalDebugLog('Client connected with address = ' +
channel.remoteAddress + ' port = ' + channel.remotePort);
});
server.on('closeChannel', function (channel) {
internalDebugLog('Client disconnected with address = ' +
channel.remoteAddress + ' port = ' + channel.remotePort);
});
server.on('create_session', function (session) {
internalDebugLog('############## SESSION CREATED ##############');
if (session.clientDescription) {
detailDebugLog('Client application URI:' + session.clientDescription.applicationUri);
detailDebugLog('Client product URI:' + session.clientDescription.productUri);
detailDebugLog('Client application name:' + session.clientDescription.applicationName ? session.clientDescription.applicationName.toString() : 'none application name');
detailDebugLog('Client application type:' + session.clientDescription.applicationType ? session.clientDescription.applicationType.toString() : 'none application type');
}
internalDebugLog('Session name:' + session.sessionName ? session.sessionName.toString() : 'none session name');
internalDebugLog('Session timeout:' + session.sessionTimeout);
internalDebugLog('Session id:' + session.sessionId);
});
server.on('session_closed', function (session, reason) {
internalDebugLog('############## SESSION CLOSED ##############');
internalDebugLog('reason:' + reason);
internalDebugLog('Session name:' + session.sessionName ? session.sessionName.toString() : 'none session name');
});
internalDebugLog('Server Initialized');
if (server.serverInfo) {
detailDebugLog('Server Info:' + JSON.stringify(server.serverInfo));
}
resolve('');
});
});
};
const readConfigOfServerNode = function (node, config) {
node.name = config.name;
// network
node.port = config.port;
node.endpoint = config.endpoint;
node.alternateHostname = config.alternateHostname;
// limits
node.maxAllowedSessionNumber = parseInt(config.maxAllowedSessionNumber) || 10;
node.maxConnectionsPerEndpoint = parseInt(config.maxConnectionsPerEndpoint) || 10;
node.maxAllowedSubscriptionNumber = parseInt(config.maxAllowedSubscriptionNumber) || 50;
node.maxNodesPerRead = config.maxNodesPerRead || 1000;
node.maxNodesPerBrowse = config.maxNodesPerBrowse || 2000;
node.delayToClose = config.delayToClose || 1000;
node.showStatusActivities = config.showStatusActivities;
node.showErrors = config.showErrors;
// certificates
node.individualCerts = config.individualCerts;
node.publicCertificateFile = config.publicCertificateFile;
node.privateCertificateFile = config.privateCertificateFile;
// Security
node.allowAnonymous = config.allowAnonymous;
// User Management
node.opcuaUsers = config.users;
// XML-Set Management
node.xmlsets = config.xmlsets;
// Audit
node.isAuditing = config.isAuditing;
// discovery
node.disableDiscovery = !config.serverDiscovery;
node.registerServerMethod = config.registerServerMethod || 1;
node.discoveryServerEndpointUrl = config.discoveryServerEndpointUrl;
node.capabilitiesForMDNS = (config.capabilitiesForMDNS) ? config.capabilitiesForMDNS.split(',') : [config.capabilitiesForMDNS];
};
const initServerNode = function (node) {
node.iiot = (0, opcua_iiot_core_1.initCoreServerNode)();
if (node.setMaxListeners)
node.setMaxListeners(UNLIMITED_LISTENERS);
};
const loadNodeSets = function (node, dirname) {
let standardNodeSetFile = node_opcua_1.nodesets.standard;
let xmlFiles = [standardNodeSetFile];
if (node.xmlsets) {
node.xmlsets.forEach((xmlsetFileName) => {
detailDebugLog('Load XML Set for ' + xmlsetFileName.name);
if (xmlsetFileName.path) {
if (xmlsetFileName.path.startsWith('public/vendor/')) {
xmlFiles.push(path_1.default.join(dirname, xmlsetFileName.path));
}
else {
xmlFiles.push(xmlsetFileName.path);
}
}
});
detailDebugLog('appending xmlFiles: ' + xmlFiles.toString());
}
detailDebugLog('node set:' + xmlFiles.toString());
node.iiot.xmlFiles = xmlFiles;
};
const loadCertificates = function (node) {
const nodeOPCUAServerPath = (0, opcua_iiot_core_1.getNodeOPCUAServerPath)();
detailDebugLog('config: ' + node.publicCertificateFile);
if (!node.individualCerts || node.publicCertificateFile === null || node.publicCertificateFile === '') {
node.publicCertificateFile = path_1.default.join(nodeOPCUAServerPath, '/certificates/server_selfsigned_cert_2048.pem');
detailDebugLog('default key: ' + node.publicCertificateFile);
}
detailDebugLog('config: ' + node.privateCertificateFile);
if (!node.individualCerts || node.privateCertificateFile === null || node.privateCertificateFile === '') {
node.privateCertificateFile = path_1.default.join(nodeOPCUAServerPath, '/certificates/PKI/own/private/private_key.pem');
detailDebugLog('default key: ' + node.privateCertificateFile);
}
return node;
};
const checkUser = function (node, userName, password) {
// valid if there is no user in the server
if (node.opcuaUsers && node.opcuaUsers.length < 1)
return true;
let isValidUser = false;
detailDebugLog('Server User Request For ' + userName);
node.opcuaUsers.forEach(function (user) {
if (userName === user.name && password === user.password) {
isValidUser = true;
}
});
if (isValidUser) {
detailDebugLog('Valid Server User Found');
}
else {
detailDebugLog('Server User ' + userName + ' Not Found');
}
return isValidUser;
};
const initRegisterServerMethod = function (node) {
node.iiot.initialized = false;
node.iiot.opcuaServer = null;
if (!node.registerServerMethod) {
node.registerServerMethod = node_opcua_1.RegisterServerMethod.HIDDEN;
}
else {
switch (parseInt(node.registerServerMethod)) {
case 2:
node.registerServerMethod = node_opcua_1.RegisterServerMethod.MDNS;
break;
case 3:
node.registerServerMethod = node_opcua_1.RegisterServerMethod.LDS;
break;
default:
node.registerServerMethod = node_opcua_1.RegisterServerMethod.HIDDEN;
}
}
return node;
};
const setDiscoveryOptions = function (node, serverOptions) {
if (!node.disableDiscovery) {
serverOptions.registerServerMethod = node.registerServerMethod;
if (node.discoveryServerEndpointUrl && node.discoveryServerEndpointUrl !== '') {
serverOptions.discoveryServerEndpointUrl = node.discoveryServerEndpointUrl;
}
if (node.capabilitiesForMDNS && node.capabilitiesForMDNS.length) {
serverOptions.capabilitiesForMDNS = node.capabilitiesForMDNS;
}
}
else {
node.registerServerMethod = node_opcua_1.RegisterServerMethod.HIDDEN;
}
return serverOptions;
};
const getAddressSpace = function (node, msg, errorHandler) {
var _a, _b;
if (!((_b = (_a = node.iiot.opcuaServer) === null || _a === void 0 ? void 0 : _a.engine) === null || _b === void 0 ? void 0 : _b.addressSpace)) {
errorHandler(new Error('Server AddressSpace Not Valid'), msg);
return null;
}
return node.iiot.opcuaServer.engine.addressSpace;
};
const addVariableToAddressSpace = function (node, msg, humanReadableType, isProperty, errorHandler) {
let addressSpace = getAddressSpace(node, msg, errorHandler);
if (!addressSpace) {
return;
}
let rootFolder = addressSpace.findNode(msg.payload.referenceNodeId);
let variableData = (0, opcua_iiot_core_1.getVariantValue)(msg.payload.datatype, msg.payload.value);
let newNodeOPCUAVariable = {};
if (isProperty) {
newNodeOPCUAVariable = {
propertyOf: rootFolder
// modellingRule: 'Mandatory'
};
}
else {
newNodeOPCUAVariable = {
componentOf: rootFolder
};
}
newNodeOPCUAVariable.nodeId = msg.payload.nodeId;
newNodeOPCUAVariable.browseName = msg.payload.browsename;
newNodeOPCUAVariable.displayName = new node_opcua_1.LocalizedText({ locale: "en-US", text: msg.payload.displayname });
newNodeOPCUAVariable.dataType = msg.payload.datatype;
newNodeOPCUAVariable.value = {
get() {
return new node_opcua_1.Variant({
dataType: node_opcua_1.DataType[msg.payload.datatype],
value: variableData
});
},
set(variant) {
variableData = variant.value;
return node_opcua_1.StatusCodes.Good;
}
};
addressSpace.getOwnNamespace().addVariable(newNodeOPCUAVariable);
internalDebugLog(msg.payload.nodeId + ' ' + humanReadableType + ' Added To Address Space');
};
const addObjectToAddressSpace = function (node, msg, humanReadableType, errorHandler) {
let addressSpace = getAddressSpace(node, msg, errorHandler);
if (!addressSpace) {
return;
}
let rootFolder = addressSpace.findNode(msg.payload.referenceNodeId);
if (rootFolder) {
let newNodeOPCUObject = {
organizedBy: rootFolder,
typeDefinition: msg.payload.objecttype,
nodeId: msg.payload.nodeId,
browseName: msg.payload.browsename,
displayName: new node_opcua_1.LocalizedText({ locale: null, text: msg.payload.displayname })
};
addressSpace.getOwnNamespace().addObject(newNodeOPCUObject);
internalDebugLog(msg.payload.nodeId + ' ' + humanReadableType + ' Added To Address Space');
}
else {
errorHandler(new Error('Root Reference Not Found'), msg);
}
};
const deleteNodeFromAddressSpace = function (node, msg, errorHandler) {
let addressSpace = getAddressSpace(node, msg, errorHandler);
if (!addressSpace) {
return;
}
if (msg.payload.nodeId) {
let searchedNode = addressSpace.findNode(msg.payload.nodeId);
if (searchedNode) {
internalDebugLog('Delete NodeId ' + msg.payload.nodeId);
addressSpace.deleteNode(searchedNode);
}
else {
internalDebugLog('Delete NodeId Not Found ' + msg.payload.nodeId);
}
}
else {
errorHandler(new Error('OPC UA Command NodeId Not Valid'), msg);
}
};
const restartServer = function (node, statusHandler, emitHandler, sendHandler) {
if (node.iiot.opcuaServer) {
node.iiot.opcuaServer.shutdown(function () {
emitHandler('shutdown');
});
}
else {
node.iiot.opcuaServer = null;
emitHandler('shutdown');
}
sendHandler({ payload: 'server shutdown' });
node.oldStatusParameter = (0, opcua_iiot_core_1.setNodeStatusTo)(node, 'shutdown', node.oldStatusParameter, node.showStatusActivities, statusHandler);
};
const createServerNameWithPrefix = function (serverPort, prefix) {
let serverPrefix = (prefix !== '') ? prefix + '-' : prefix;
return 'NodeRED-IIoT-' + serverPrefix + 'Server-' + serverPort;
};
const buildServerOptions = (node, prefix) => __awaiter(void 0, void 0, void 0, function* () {
let today = new Date();
// const SecurityPolicy = require("node-opcua").SecurityPolicy;
return {
defaultSecureTokenLifetime: 60000000,
port: typeof node.port === 'string' ? parseInt(node.port) : node.port,
nodeset_filename: node.iiot.xmlFiles,
resourcePath: '/' + node.endpoint || 'UA/NodeRED' + prefix + 'IIoTServer',
buildInfo: {
productName: node.name || 'NodeOPCUA IIoT Server',
buildNumber: today.getTime().toString(),
buildDate: today
},
serverCapabilities: {
operationLimits: {
maxNodesPerRead: node.maxNodesPerRead,
maxNodesPerBrowse: node.maxNodesPerBrowse
}
},
serverInfo: {
applicationType: node_opcua_1.ApplicationType.Server,
applicationUri: (0, node_opcua_1.makeApplicationUrn)(yield (0, node_opcua_1.extractFullyQualifiedDomainName)(), createServerNameWithPrefix(node.port, prefix)),
productUri: createServerNameWithPrefix(node.port, prefix),
applicationName: { text: 'Node-RED', locale: 'en' },
gatewayServerUri: null,
discoveryProfileUri: null,
discoveryUrls: []
},
maxAllowedSessionNumber: node.maxAllowedSessionNumber,
maxConnectionsPerEndpoint: node.maxConnectionsPerEndpoint,
allowAnonymous: node.allowAnonymous,
securityPolicies: [
node_opcua_1.SecurityPolicy.None,
node_opcua_1.SecurityPolicy.Basic128,
node_opcua_1.SecurityPolicy.Basic192,
node_opcua_1.SecurityPolicy.Basic192Rsa15,
node_opcua_1.SecurityPolicy.Basic256Rsa15,
node_opcua_1.SecurityPolicy.Basic256Sha256,
node_opcua_1.SecurityPolicy.Aes128_Sha256_RsaOaep,
node_opcua_1.SecurityPolicy.Aes256_Sha256_RsaPss,
node_opcua_1.SecurityPolicy.PubSub_Aes128_CTR,
node_opcua_1.SecurityPolicy.PubSub_Aes256_CTR
],
certificateFile: node.publicCertificateFile,
privateKeyFile: node.privateCertificateFile,
alternateHostname: node.alternateHostname || '',
userManager: checkUser,
isAuditing: node.isAuditing,
registerServerMethod: node.registerServerMethod,
disableDiscovery: node.disableDiscovery
};
});
const createServer = (node, serverOptions, postInitialize, statusHandler, verbose = false) => __awaiter(void 0, void 0, void 0, function* () {
/* istanbul ignore next */
if (verbose) {
coreServer.flexDetailDebugLog('serverOptions:' + JSON.stringify(serverOptions));
}
const options = yield serverOptions;
node.iiot.opcuaServer = yield coreServer.createServerObject(node.maxAllowedSubscriptionNumber, options);
node.oldStatusParameter = (0, opcua_iiot_core_1.setNodeStatusTo)(node, 'waiting', node.oldStatusParameter, node.showStatusActivities, statusHandler);
yield node.iiot.opcuaServer.initialize();
postInitialize();
coreServer.setOPCUAServerListener(node);
});
const createServerObject = (maxSubscriptions, serverOptions) => __awaiter(void 0, void 0, void 0, function* () {
// TODO: now via serverOptions.serverCapabilities.maxSessions
serverOptions.maxAllowedSessionNumber = maxSubscriptions || 10;
let server = new node_opcua_1.OPCUAServer(serverOptions);
// TODO: later at server.engine.serverCapabilities.maxSessions = maxSubscriptions || 10
return server;
});
const setOPCUAServerListener = function (node) {
node.iiot.opcuaServer.on('newChannel', function (channel) {
internalDebugLog('Client connected new channel with address = ', channel.remoteAddress, ' port = ', channel.remotePort);
});
node.iiot.opcuaServer.on('closeChannel', function (channel) {
internalDebugLog('Client disconnected close channel with address = ', channel.remoteAddress, ' port = ', channel.remotePort);
});
node.iiot.opcuaServer.on('post_initialize', function () {
internalDebugLog('initialized');
});
};
const coreServer = {
internalDebugLog,
detailDebugLog,
isa95DebugLog,
isa95DetailDebugLog,
flexInternalDebugLog,
flexDetailDebugLog,
maxTimeInterval,
timeInterval,
simulatorInterval,
simulateVariation,
constructAddressSpaceFromScript,
constructAddressSpace,
destructAddressSpace,
start,
readConfigOfServerNode,
initServerNode,
loadNodeSets,
loadCertificates,
checkUser,
initRegisterServerMethod,
setDiscoveryOptions,
getAddressSpace,
addVariableToAddressSpace,
addObjectToAddressSpace,
deleteNodeFromAddressSpace,
restartServer,
createServerNameWithPrefix,
createServerObject,
setOPCUAServerListener,
buildGeneralServerOptions,
createServer,
};
exports.default = coreServer;
//# sourceMappingURL=opcua-iiot-core-server.js.map