node-red-contrib-iiot-opcua
Version:
An Industrial IoT OPC UA toolbox contribution package for Node-RED based on node-opcua.
272 lines (269 loc) • 13.9 kB
JavaScript
/**
The BSD 3-Clause License
Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
All rights reserved.
node-red-contrib-iiot-opcua
*/
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.logger = void 0;
// SOURCE-MAP-REQUIRED
const core = __importStar(require("./opcua-iiot-core"));
const fsm_1 = require("@xstate/fsm");
const opcua_iiot_core_1 = require("./opcua-iiot-core");
var logger;
(function (logger) {
logger.internalDebugLog = core.Debug('opcuaIIoT:connector');
logger.detailDebugLog = core.Debug('opcuaIIoT:connector:details');
logger.libDebugLog = core.Debug('opcuaIIoT:connector:nodeopcua');
})(logger = exports.logger || (exports.logger = {}));
// sets values within node.iiot (refactored to node.iiot)
const initConnectorNode = () => {
return Object.assign(Object.assign({}, core.initCoreNode()), { sessionNodeRequests: 0, endpoints: [], userIdentity: undefined, opcuaClient: undefined, opcuaSession: undefined, discoveryServer: undefined, serverCertificate: undefined, discoveryServerEndpointUrl: undefined, hasOpcUaSubscriptions: false });
};
const createConnectorFinalStateMachine = function () {
return (0, fsm_1.createMachine)({
id: 'connector',
initial: opcua_iiot_core_1.FsmConnectorStates.StateIdle,
states: {
idle: { on: {
INITOPCUA: opcua_iiot_core_1.FsmConnectorStates.StateInit,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd
}
},
init: { on: {
OPEN: opcua_iiot_core_1.FsmConnectorStates.StateOpened,
CLOSE: opcua_iiot_core_1.FsmConnectorStates.StateClosed,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd
}
},
opened: { on: {
SESSIONREQUEST: opcua_iiot_core_1.FsmConnectorStates.StateSessionRequested,
CLOSE: opcua_iiot_core_1.FsmConnectorStates.StateClosed,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd
}
},
sessionRequested: { on: {
OPEN: opcua_iiot_core_1.FsmConnectorStates.StateOpened,
SESSIONACTIVATE: opcua_iiot_core_1.FsmConnectorStates.StateSessionActive,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd
}
},
sessionActive: { on: {
OPEN: opcua_iiot_core_1.FsmConnectorStates.StateOpened,
SESSIONCLOSE: opcua_iiot_core_1.FsmConnectorStates.StateClosed,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd
}
},
sessionClosed: { on: {
IDLE: opcua_iiot_core_1.FsmConnectorStates.StateIdle,
OPEN: opcua_iiot_core_1.FsmConnectorStates.StateOpened,
CLOSE: opcua_iiot_core_1.FsmConnectorStates.StateClosed,
SESSIONRESTART: opcua_iiot_core_1.FsmConnectorStates.StateSessionRestart,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
UNLOCK: opcua_iiot_core_1.FsmConnectorStates.StateUnlocked,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd
}
},
sessionRestart: { on: {
IDLE: opcua_iiot_core_1.FsmConnectorStates.StateIdle,
SESSIONCLOSE: opcua_iiot_core_1.FsmConnectorStates.StateClosed,
OPEN: opcua_iiot_core_1.FsmConnectorStates.StateOpened,
CLOSE: opcua_iiot_core_1.FsmConnectorStates.StateClosed,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd
}
},
closed: { on: {
OPEN: opcua_iiot_core_1.FsmConnectorStates.StateOpened,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
UNLOCK: opcua_iiot_core_1.FsmConnectorStates.StateUnlocked,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd,
IDLE: opcua_iiot_core_1.FsmConnectorStates.StateIdle
}
},
locked: { on: {
SESSIONCLOSE: opcua_iiot_core_1.FsmConnectorStates.StateClosed,
OPEN: opcua_iiot_core_1.FsmConnectorStates.StateOpened,
CLOSE: opcua_iiot_core_1.FsmConnectorStates.StateClosed,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked,
UNLOCK: opcua_iiot_core_1.FsmConnectorStates.StateUnlocked,
SESSIONRESTART: opcua_iiot_core_1.FsmConnectorStates.StateSessionRestart,
RECONFIGURE: opcua_iiot_core_1.FsmConnectorStates.StateReconfigured,
STOP: opcua_iiot_core_1.FsmConnectorStates.StateStopped,
RENEW: opcua_iiot_core_1.FsmConnectorStates.StateRenewed,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd
}
},
unlocked: { on: {
IDLE: opcua_iiot_core_1.FsmConnectorStates.StateIdle,
OPEN: opcua_iiot_core_1.FsmConnectorStates.StateOpened,
END: opcua_iiot_core_1.FsmConnectorStates.StateEnd,
LOCK: opcua_iiot_core_1.FsmConnectorStates.StateLocked
}
},
stopped: { on: {} },
end: { on: {} },
reconfigured: { on: {} },
renewed: { on: {} }
}
});
};
const startConnectorMachineService = (toggleMachine) => {
return (0, fsm_1.interpret)(toggleMachine).start();
};
const subscribeConnectorFSMService = (service, eventFn) => {
if (service === undefined || eventFn === undefined)
throw new Error('Service or event handler missing');
return service.subscribe(eventFn);
};
function setListenerToClient(node) {
if (!node.iiot.opcuaClient) {
logger.internalDebugLog('Client Not Valid On Setting Events To Client');
if (node.showErrors) {
node.error(new Error('Client Not Valid To Set Event Listeners'), { payload: 'No Client To Set Event Listeners' });
}
return;
}
node.iiot.opcuaClient.on('close', function (err) {
if (err) {
logger.internalDebugLog('Connection Error On Close ' + err);
}
if (node.iiot.isInactiveOnOPCUA()) {
logger.detailDebugLog('Connector Not Active On OPC UA Close Event');
}
else {
node.iiot.resetOPCUAConnection('Connector To Server Close');
}
logger.internalDebugLog('!!!!!!!!!!!!!!!!!!!!!!!! CLIENT CONNECTION CLOSED !!!!!!!!!!!!!!!!!!!');
logger.internalDebugLog('CONNECTION CLOSED: ' + node.endpoint);
node.emit('server_connection_close');
});
node.iiot.opcuaClient.on('backoff', function (number, delay) {
logger.internalDebugLog('!!! CONNECTION FAILED (backoff) FOR #', number, ' retrying ', delay / 1000.0, ' sec. !!!');
logger.internalDebugLog('CONNECTION FAILED: ' + node.endpoint);
node.iiot.stateService.send('LOCK');
});
node.iiot.opcuaClient.on('abort', function () {
logger.internalDebugLog('!!! Abort backoff !!!');
logger.internalDebugLog('CONNECTION BROKEN: ' + node.endpoint);
if (node.iiot.isInactiveOnOPCUA()) {
logger.detailDebugLog('Connector Not Active On OPC UA Backoff Abort Event');
}
else {
node.iiot.resetOPCUAConnection('Connector To Server Backoff Abort');
}
node.emit('server_connection_abort');
});
node.iiot.opcuaClient.on('connection_lost', function () {
logger.internalDebugLog('!!!!!!!!!!!!!!!!!!!!!!!! CLIENT CONNECTION LOST !!!!!!!!!!!!!!!!!!!');
logger.internalDebugLog('CONNECTION LOST: ' + node.endpoint);
node.iiot.stateService.send('LOCK');
node.emit('server_connection_lost');
});
node.iiot.opcuaClient.on('connection_reestablished', function () {
logger.internalDebugLog('!!!!!!!!!!!!!!!!!!!!!!!! CLIENT CONNECTION RE-ESTABLISHED !!!!!!!!!!!!!!!!!!!');
logger.internalDebugLog('CONNECTION RE-ESTABLISHED: ' + node.endpoint);
node.iiot.stateService.send('UNLOCK');
});
node.iiot.opcuaClient.on('start_reconnection', function () {
logger.internalDebugLog('!!!!!!!!!!!!!!!!!!!!!!!! CLIENT STARTING RECONNECTION !!!!!!!!!!!!!!!!!!!');
logger.internalDebugLog('CONNECTION STARTING RECONNECTION: ' + node.endpoint);
node.iiot.stateService.send('LOCK');
});
node.iiot.opcuaClient.on('timed_out_request', function () {
logger.internalDebugLog('!!!!!!!!!!!!!!!!!!!!!!!! CLIENT TIMED OUT REQUEST !!!!!!!!!!!!!!!!!!!');
logger.internalDebugLog('CONNECTION TIMED OUT REQUEST: ' + node.endpoint);
});
node.iiot.opcuaClient.on('security_token_renewed', function () {
logger.detailDebugLog('!!!!!!!!!!!!!!!!!!!!!!!! CLIENT SECURITY TOKEN RENEWED !!!!!!!!!!!!!!!!!!!');
logger.detailDebugLog('CONNECTION SECURITY TOKEN RENEWED: ' + node.endpoint);
});
node.iiot.opcuaClient.on('after_reconnection', function () {
logger.internalDebugLog('!!!!!!!!!!!!!!!!!!!!!!!! CLIENT RECONNECTED !!!!!!!!!!!!!!!!!!!');
logger.internalDebugLog('CONNECTION RECONNECTED: ' + node.endpoint);
node.emit('after_reconnection', node.iiot.opcuaClient);
node.iiot.stateService.send('UNLOCK');
});
}
function logSessionInformation(node) {
var _a;
if (!((_a = node.iiot) === null || _a === void 0 ? void 0 : _a.opcuaSession)) {
logger.detailDebugLog('Session Not Valid To Log Information');
return;
}
logger.internalDebugLog('Session ' + node.iiot.opcuaSession.name + ' Id: ' + node.iiot.opcuaSession.sessionId + ' Started On ' + node.endpoint);
logger.detailDebugLog('name :' + node.iiot.opcuaSession.name);
logger.detailDebugLog('sessionId :' + node.iiot.opcuaSession.sessionId);
logger.detailDebugLog('authenticationToken :' + node.iiot.opcuaSession.authenticationToken);
logger.internalDebugLog('timeout :' + node.iiot.opcuaSession.timeout);
if (node.iiot.opcuaSession.serverNonce) {
logger.detailDebugLog('serverNonce :' + node.iiot.opcuaSession.serverNonce ? node.iiot.opcuaSession.serverNonce.toString('hex') : 'none');
}
if (node.iiot.opcuaSession.serverCertificate) {
logger.detailDebugLog('serverCertificate :' + node.iiot.opcuaSession.serverCertificate ? node.iiot.opcuaSession.serverCertificate.toString('base64') : 'none');
}
else {
logger.detailDebugLog('serverCertificate : None');
}
logger.detailDebugLog('serverSignature :' + node.iiot.opcuaSession.serverSignature ? node.iiot.opcuaSession.serverSignature : 'none');
if (node.iiot.opcuaSession.lastRequestSentTime) {
logger.detailDebugLog('lastRequestSentTime : ' + node.iiot.opcuaSession.lastRequestSentTime);
logger.internalDebugLog('lastRequestSentTime converted :' + node.iiot.opcuaSession.lastRequestSentTime ? new Date(node.iiot.opcuaSession.lastRequestSentTime).toISOString() : 'none');
}
if (node.iiot.opcuaSession.lastResponseReceivedTime) {
logger.detailDebugLog('lastResponseReceivedTime : ' + node.iiot.opcuaSession.lastResponseReceivedTime);
logger.internalDebugLog('lastResponseReceivedTime converted :' + node.iiot.opcuaSession.lastResponseReceivedTime ? new Date(node.iiot.opcuaSession.lastResponseReceivedTime).toISOString() : 'none');
}
}
function checkEndpoint(endpoint, errorHandler) {
if (endpoint && endpoint.includes('opc.tcp://') && endpoint.lastIndexOf(':') > 8) {
return true;
}
else {
logger.internalDebugLog('Endpoint Not Valid -> ' + endpoint);
errorHandler(new Error('endpoint does not include opc.tcp://'));
return false;
}
}
const coreConnector = {
initConnectorNode,
createConnectorFinalStateMachine,
startConnectorMachineService,
subscribeConnectorFSMService,
setListenerToClient,
logSessionInformation,
checkEndpoint,
internalDebugLog: logger.internalDebugLog
};
exports.default = coreConnector;
//# sourceMappingURL=opcua-iiot-core-connector.js.map