Skip to content

Commit

Permalink
feat: new flex connector the send connection data to the connector vi…
Browse files Browse the repository at this point in the history
…a events #44
  • Loading branch information
biancode committed Oct 15, 2018
1 parent 5681752 commit 25df528
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 33 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"node-red": {
"nodes": {
"OPCUA-IIoT-Connector": "opcuaIIoT/opcua-iiot-connector.js",
"OPCUA-IIoT-Flex-Connector": "opcuaIIoT/opcua-iiot-flex-connector.js",
"OPCUA-IIoT-Inject": "opcuaIIoT/opcua-iiot-inject.js",
"OPCUA-IIoT-Node": "opcuaIIoT/opcua-iiot-node.js",
"OPCUA-IIoT-Event": "opcuaIIoT/opcua-iiot-event.js",
Expand Down
1 change: 1 addition & 0 deletions src/core/opcua-iiot-core-listener.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ de.biancoroyal.opcua.iiot.core.listener.createStatelyMachine = function () {
'endsub': 'END'
},
'ERROR': {
'idlesub': 'IDLE',
'initsub': 'INIT',
'endsub': 'END'
},
Expand Down
9 changes: 9 additions & 0 deletions src/locales/en-US/opcua-iiot-flex-connector.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"opcua-iiot-contrib": {
"label": {
"connector": "Connector",
"showActivities": "Show Activities",
"showErrors": "Show Errors"
}
}
}
96 changes: 66 additions & 30 deletions src/opcua-iiot-connector.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,23 +90,6 @@ module.exports = function (RED) {
node.privateKeyFile = null
}

node.opcuaClientOptions = {
securityPolicy: node.securityPolicy || 'None',
securityMode: node.messageSecurityMode || 'NONE',
defaultSecureTokenLifetime: node.defaultSecureTokenLifetime,
keepSessionAlive: node.keepSessionAlive,
certificateFile: node.publicCertificateFile,
privateKeyFile: node.privateKeyFile,
endpoint_must_exist: node.endpointMustExist,
requestedSessionTimeout: node.requestedSessionTimeout,
connectionStrategy: {
maxRetry: node.strategyMaxRetry,
initialDelay: node.strategyInitialDelay,
maxDelay: node.strategyMaxDelay,
randomisationFactor: node.strategyRandomisationFactor
}
}

if (node.loginEnabled) {
if (node.credentials) {
node.userIdentity = {
Expand All @@ -121,6 +104,25 @@ module.exports = function (RED) {

/* ######### CONNECTION ######### */

node.updateServerOptions = function () {
node.opcuaClientOptions = {
securityPolicy: node.securityPolicy || 'None',
securityMode: node.messageSecurityMode || 'NONE',
defaultSecureTokenLifetime: node.defaultSecureTokenLifetime,
keepSessionAlive: node.keepSessionAlive,
certificateFile: node.publicCertificateFile,
privateKeyFile: node.privateKeyFile,
endpoint_must_exist: node.endpointMustExist,
requestedSessionTimeout: node.requestedSessionTimeout,
connectionStrategy: {
maxRetry: node.strategyMaxRetry,
initialDelay: node.strategyInitialDelay,
maxDelay: node.strategyMaxDelay,
randomisationFactor: node.strategyRandomisationFactor
}
}
}

node.connectOPCUAEndpoint = function () {
if (!node.endpoint.includes('opc.tcp:')) {
coreConnector.internalDebugLog('connector endpoint is wrong and needs opc.tcp// ' + node.endpoint)
Expand All @@ -131,6 +133,8 @@ module.exports = function (RED) {
coreConnector.detailDebugLog('Options ' + JSON.stringify(node.opcuaClientOptions))

try {
node.opcuaClient = null
node.updateServerOptions()
node.opcuaClient = new coreConnector.core.nodeOPCUA.OPCUAClient(node.opcuaClientOptions)

if (node.autoSelectRightEndpoint) {
Expand Down Expand Up @@ -210,11 +214,13 @@ module.exports = function (RED) {
if (!node.endpoint.includes('opc.tcp://')) {
coreConnector.internalDebugLog('Endpoint Not Valid -> ' + node.endpoint)
node.error(new Error('endpoint does not include opc.tcp://'), {payload: 'Client Endpoint Error'})
return
}

node.stateMachine.unlock()
node.opcuaClient.connect(node.endpoint, function (err) {
if (err) {
node.stateMachine.lock().end()
node.stateMachine.lock()
node.handleError(err)
} else {
coreConnector.internalDebugLog('client is connected now to ' + node.endpoint)
Expand All @@ -223,19 +229,12 @@ module.exports = function (RED) {
})
}

node.renewConnection = function () {
node.renewConnection = function (done) {
node.stateMachine.lock()
node.opcuaClient.disconnect(function (err) {
if (err) {
coreConnector.internalDebugLog('Disconnected With Error ' + err + ' From ' + node.endpoint)
if (node.showErrors) {
node.error(err, {payload: 'Error On Close Connector For Renew'})
}
} else {
coreConnector.internalDebugLog('Disconnected From ' + node.endpoint)
}
node.disconnectNodeOPCUA(() => {
node.stateMachine.unlock()
node.connectToClient()
node.connectOPCUAEndpoint()
done()
})
}

Expand Down Expand Up @@ -454,10 +453,44 @@ module.exports = function (RED) {
}

node.on('close', function (done) {
node.stateMachine.lock().end()
node.stateMachine.close().lock().end()
node.disconnectNodeOPCUA(done)
})

node.restartWithNewSettings = function (parameters, done) {
coreConnector.internalDebugLog('Renew With Flex Connector Request On State ' + node.stateMachine.getMachineState())
node.stateMachine.close()
node.setNewParameters(parameters)

node.closeSession(() => {
setTimeout(() => {
node.renewConnection(done)
}, node.connectionStartDelay)
})
}

node.setNewParameters = function (parameters) {
node.discoveryUrl = parameters.discoveryUrl || node.discoveryUrl
node.endpoint = parameters.endpoint || node.endpoint
node.keepSessionAlive = parameters.keepSessionAlive || node.keepSessionAlive
node.securityPolicy = parameters.securityPolicy || node.securityPolicy
node.securityMode = parameters.securityMode || node.securityMode
node.name = parameters.name || node.name
node.showErrors = parameters.showErrors || node.showErrors
node.publicCertificateFile = parameters.publicCertificateFile || node.publicCertificateFile
node.privateKeyFile = parameters.privateKeyFile || node.privateKeyFile
node.defaultSecureTokenLifetime = parameters.defaultSecureTokenLifetime || node.defaultSecureTokenLifetime
node.endpointMustExist = parameters.endpointMustExist || node.endpointMustExist
node.autoSelectRightEndpoint = parameters.autoSelectRightEndpoint || node.autoSelectRightEndpoint
node.strategyMaxRetry = parameters.strategyMaxRetry || node.strategyMaxRetry
node.strategyInitialDelay = parameters.strategyInitialDelay || node.strategyInitialDelay
node.strategyMaxDelay = parameters.strategyMaxDelay || node.strategyMaxDelay
node.strategyRandomisationFactor = parameters.strategyRandomisationFactor || node.strategyRandomisationFactor
node.requestedSessionTimeout = parameters.requestedSessionTimeout || node.requestedSessionTimeout
node.connectionStartDelay = parameters.connectionStartDelay || node.connectionStartDelay
node.reconnectDelay = parameters.reconnectDelay || node.reconnectDelay
}

/* ######### FSM EVENTS ######### */

node.stateMachine.onIDLE = function (event, oldState, newState) {
Expand Down Expand Up @@ -535,7 +568,10 @@ module.exports = function (RED) {

node.stateMachine.onEND = function (event, oldState, newState) {
coreConnector.detailDebugLog('Connector End Event FSM')
node.resetAllTimer()
}

node.resetAllTimer = function () {
if (clientStartTimeout) {
clearTimeout(clientStartTimeout)
clientStartTimeout = null
Expand Down
77 changes: 77 additions & 0 deletions src/opcua-iiot-flex-connector.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<!--
The BSD 3-Clause License
Copyright 2018 - Klaus Landsdorf (http://bianco-royal.de/)
All rights reserved.
node-red-contrib-iiot-opcua
-->

<script type="text/javascript">
RED.nodes.registerType('OPCUA-IIoT-Flex-Connector', {
category: 'IIoT',
color: '#ABCDEF',
defaults: {
name: {value: ''},
showStatusActivities: {value: false},
showErrors: {value: false},
connector: {type: 'OPCUA-IIoT-Connector', required: true}
},
inputs: 1,
outputs: 1,
align: 'left',
icon: 'icon.png',
label: function () {
return this.name || 'Flex Connector'
},
labelStyle: function () {
return this.name ? 'node_label_italic' : ''
},
oneditprepare: function () {
let node = this
}
})
</script>

<script type="text/x-red" data-template-name="OPCUA-IIoT-Flex-Connector">
<div class="form-row">
<label for="node-input-connector"><i class="icon-tasks"></i> <span data-i18n="opcua-iiot-contrib.label.connector"></span></label>
<input type="text" id="node-input-connector" placeholder="opc.tcp://localhost:4334">
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" placeholder="">
</div>
<hr>
<div class="form-row">
<label style="min-width:160px" for="node-input-showStatusActivities"><i class="fa fa-th"></i>
<span data-i18n="opcua-iiot-contrib.label.showActivities"></span></label>
<input type="checkbox" id="node-input-showStatusActivities" style="max-width:30px">
</div>
<div class="form-row">
<label style="min-width:160px" for="node-input-showErrors"><i class="fa fa-th"></i>
<span data-i18n="opcua-iiot-contrib.label.showErrors"></span></label>
<input type="checkbox" id="node-input-showErrors" style="max-width:30px">
</div>
</script>

<script type="text/x-red" data-help-name="OPCUA-IIoT-Flex-Connector">
<h2>OPC UA IIoT Flex Connector</h2>

<p>
The Flex Connector node is to set up an event listener with parameters to change a connectors options.
It is to trigger by an Inject of Node-RED or by the OPC UA IIoT Inject.
It could also trigger with incoming events from other nodes.
</p>

<h3>Input</h3>

<p>msg with connector parameters</p>

<h3>Output</h3>

<p>msg with connector parameters and result</p>

<strong>Name</strong>
<p>Name in the flow of Node-RED.</p>

</script>
65 changes: 65 additions & 0 deletions src/opcua-iiot-flex-connector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
The BSD 3-Clause License
Copyright 2018 - Klaus Landsdorf (http://bianco-royal.de/)
All rights reserved.
node-red-contrib-iiot-opcua
*/
'use strict'

/**
* Event Node-RED node.
*
* @param RED
*/
module.exports = function (RED) {
// SOURCE-MAP-REQUIRED
let coreConnector = require('./core/opcua-iiot-core-connector')

function OPCUAIIoTFlexConnector (config) {
RED.nodes.createNode(this, config)
this.name = config.name
this.showStatusActivities = config.showStatusActivities
this.showErrors = config.showErrors
this.connector = RED.nodes.getNode(config.connector)

let node = this

node.status({fill: 'blue', shape: 'ring', text: 'new'})

node.statusLog = function (logMessage) {
if (RED.settings.verbose && node.showStatusActivities) {
node.verboseLog('Status: ' + logMessage)
}
}

node.setNodeStatusTo = function (statusValue) {
node.statusLog(statusValue)
let statusParameter = coreConnector.core.getNodeStatus(statusValue, node.showStatusActivities)
node.status({fill: statusParameter.fill, shape: statusParameter.shape, text: statusParameter.status})
}

node.on('input', function (msg) {
coreConnector.internalDebugLog('connector change request input')

if (node.connector && msg.payload.endpoint && msg.payload.endpoint.includes('opc.tcp:')) {
coreConnector.internalDebugLog('connector change possible')
coreConnector.internalDebugLog(msg.payload)
node.connector.restartWithNewSettings(msg.payload, () => {
coreConnector.internalDebugLog('connector change injected')
node.send(msg)
})
} else {
coreConnector.internalDebugLog('Connector Change Not Possible - Wrong Endpoint')
}
})

coreConnector.core.registerToConnector(node)

node.on('close', function (done) {
node.connector.deregisterForOPCUA(node, done)
})
}

RED.nodes.registerType('OPCUA-IIoT-Flex-Connector', OPCUAIIoTFlexConnector)
}
12 changes: 12 additions & 0 deletions src/opcua-iiot-listener.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,8 +550,20 @@ module.exports = function (RED) {

coreListener.core.registerToConnector(node)

node.connector.on('connection_closed', () => {
coreListener.internalDebugLog('Subscription Is To Terminate On Connection Close')
if (uaSubscription !== null && node.stateMachine.getMachineState() !== 'TERMINATED') {
node.stateMachine.terminatesub()
uaSubscription.terminate(() => {
node.stateMachine.idlesub()
coreListener.internalDebugLog('Subscription Was Terminated')
})
}
})

node.on('close', function (done) {
if (uaSubscription !== null && node.stateMachine.getMachineState() !== 'TERMINATED') {
node.stateMachine.terminatesub()
uaSubscription.terminate(() => {
node.connector.deregisterForOPCUA(node, done)
})
Expand Down
7 changes: 4 additions & 3 deletions src/opcua-iiot-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,10 @@ module.exports = function (RED) {
clearInterval(coreServer.simulatorInterval)
}
coreServer.simulatorInterval = null
let timeoutShutdown = 100
if (node.opcuaServer.engine.subscriptionCount > 0) {
timeoutShutdown += 3000
let timeoutShutdown = 500
if (node.opcuaServer.engine && node.opcuaServer.engine.currentSubscriptionCount > 0) {
coreServer.internalDebugLog('extended shutdown time - subscriptions: ' + node.opcuaServer.engine.currentSubscriptionCount)
timeoutShutdown += 2500
}
setTimeout(() => {
if (node.opcuaServer) {
Expand Down

0 comments on commit 25df528

Please sign in to comment.