From 154f7b9da0acf2b807f21d57dd8f6dd0b3764339 Mon Sep 17 00:00:00 2001 From: Goetz Goerisch Date: Thu, 28 Nov 2024 17:04:30 +0100 Subject: [PATCH] refactor: linting Signed-off-by: Goetz Goerisch --- README.md | 38 +- .../local-discovery-server.ts | 128 +- src/addressspace.ts | 6 +- src/config.ts | 154 +- src/machines/LaserSystem/LaserSystem.ts | 10 +- src/machines/MyControledMachine/enums.ts | 64 +- src/machines/MyControledMachine/interfaces.ts | 60 +- src/machines/MyControledMachine/job.ts | 236 +- src/machines/MyControledMachine/jobcontrol.ts | 1948 +++++++++-------- src/machines/PlasticsRubber/40077.ts | 10 +- src/machines/PlasticsRubber/40079.ts | 10 +- src/machines/PlasticsRubber/40082-1.ts | 11 +- src/machines/PlasticsRubber/40082-2.ts | 10 +- src/machines/PlasticsRubber/40082-3.ts | 10 +- src/machines/PlasticsRubber/40084-11.ts | 10 +- src/machines/PlasticsRubber/40084-3.ts | 10 +- src/machines/PlasticsRubber/40084-9.ts | 10 +- src/machines/PlasticsRubber/generic.ts | 14 +- src/machines/WoodWorking/ww_basic.ts | 296 ++- src/machines/WoodWorking/ww_full.ts | 846 +++++-- .../machinetool/UGGgrindingmachine.ts | 210 +- .../machinetool/brownfieldmachinetool.ts | 10 +- .../machinetool/machinetool-example.ts | 227 +- .../machinetool/showcasemachinetool.ts | 251 ++- .../motiondevicesystem/motiondevicesystem.ts | 109 +- src/machines/mymachine/datasource.ts | 294 +-- src/machines/mymachine/mymachine.ts | 433 ++-- src/permissiongroups.ts | 177 +- src/pubsub.ts | 456 ++-- src/server.ts | 67 +- .../myfinitestatemachinetype.ts | 275 ++- src/serveraddressspace/serveraddressspace.ts | 1380 ++++++------ src/test/test.ts | 53 +- src/user.ts | 45 +- src/utils/log.ts | 71 +- src/utils/userfile.ts | 49 +- tsconfig.json | 39 +- user.json | 36 +- 38 files changed, 4547 insertions(+), 3516 deletions(-) diff --git a/README.md b/README.md index 8e463f5c..98794875 100644 --- a/README.md +++ b/README.md @@ -3,50 +3,50 @@ [![Node.js CI](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/node.js.yml/badge.svg)](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/node.js.yml) [![CodeQL](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/codeql-analysis.yml) [![Lint Code Base](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/linter.yml/badge.svg)](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/linter.yml) -[![Container Build](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/container_build.yml/badge.svg)](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/container_build.yml) +[![Container Build](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/container_build.yml/badge.svg)](https://github.com/AndreasHeine/SampleServer-node-opcua/actions/workflows/container_build.yml) OPC UA Sample Server based on [node-opcua](https://github.com/node-opcua/node-opcua) the official book node-opcua: [node-opcua by example](https://leanpub.com/node-opcuabyexample-edition2024) by [Sterfive](https://www.sterfive.com) -API Docs: [2.32.0](https://node-opcua.github.io/api_doc/2.32.0/index.html) - +API Docs: [2.32.0](https://node-opcua.github.io/api_doc/2.32.0/index.html) + ## Usage -- `download and unpack` -- `open folder in VS Code (or in terminal)` -- `npm install` +- `download and unpack` +- `open folder in VS Code (or in terminal)` +- `npm install` - `npm run start` ## Example Users User: `admin` Password: `pw1` User: `operator` Password: `pw2` -User: `guest` Password: `pw3` +User: `guest` Password: `pw3` ## Ephemeral Dev Environment - [Click](https://gitpod.io/#https://github.com/AndreasHeine/SampleServer-node-opcua) - `npm run start` - split terminal: `opcua-commander -e opc.tcp://localhost:4840/UA` to have a local OPC UA client - -## Docker + +## Docker Set "IP" and "PORT" in env: -- `docker run -it -p 4840:4840 -e PORT=4840 -e IP=127.0.0.1 --name sampleserver-node-opcua ghcr.io/andreasheine/sampleserver-node-opcua:main` - -## Online Server Instance +- `docker run -it -p 4840:4840 -e PORT=4840 -e IP=127.0.0.1 --name sampleserver-node-opcua ghcr.io/andreasheine/sampleserver-node-opcua:main` + +## Online Server Instance + +- `opc.tcp://opcua.umati.app:4843` -- `opc.tcp://opcua.umati.app:4843` - ## Implementations of OPC UA Companion Specifications - + ![image](./img/addressspace.PNG) -## OPC UA Pub/Sub over MQTT - +## OPC UA Pub/Sub over MQTT + MQTT-Broker: `mqtt://broker.hivemq.com:1883` -MQTT-Topic: `umati/#` - +MQTT-Topic: `umati/#` + ## License ![GitHub](https://img.shields.io/github/license/AndreasHeine/SampleServer-node-opcua) diff --git a/src/LocalDiscoveryServer/local-discovery-server.ts b/src/LocalDiscoveryServer/local-discovery-server.ts index 7b7ec7a7..4a4b1c0c 100644 --- a/src/LocalDiscoveryServer/local-discovery-server.ts +++ b/src/LocalDiscoveryServer/local-discovery-server.ts @@ -12,60 +12,76 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - OPCUADiscoveryServer, - OPCUAServerEndPoint, - ServerSecureChannelLayer, - OPCUACertificateManager, - } from 'node-opcua' - import { - OPCUADiscoveryServerOptions - } from 'node-opcua-server-discovery' - - import { green, yellow, red } from './../utils/log' - - (async () => { - try { - const config: OPCUADiscoveryServerOptions = { - port: 4840, - serverCertificateManager: new OPCUACertificateManager({ - automaticallyAcceptUnknownCertificate: true, - name: 'discovery_pki', - rootFolder: 'discovery_pki', - }), - serverInfo: { - applicationName: { - text: 'SampleDiscoveryServer-applicationName', - locale: 'en' , - }, - applicationUri: 'urn:SampleDiscoveryServer', - productUri: 'SampleDiscoveryServer-productUri', - } - } - const lds = new OPCUADiscoveryServer(config) - .on('newChannel', (channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint) => { - green(` DiscoveryServer: newChannel! ChannelId:${channel.channelId} - ${channel.remoteAddress}:${channel.remotePort} `) - }) - .on('closeChannel', (channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint) => { - green(` DiscoveryServer: closeChannel! ChannelId:${channel.channelId} - ${channel.remoteAddress}:${channel.remotePort} `) - }) - .on('connectionRefused', (socketData: any, endpoint: OPCUAServerEndPoint) => { - red(` DiscoveryServer: connectionRefused! \n ${endpoint.serverInfo}`) - }) - .on('openSecureChannelFailure', (socketData: any, channelData: any, endpoint: OPCUAServerEndPoint) => { - red(` DiscoveryServer: openSecureChannelFailure! \n ${channelData} \n ${endpoint.serverInfo}`) - }) - .on('error', (e) => { - red(` DiscoveryServer: ${e} `) - }) - .on('debug', (e) => { - yellow(` DiscoveryServer: ${e} `) +import { + OPCUADiscoveryServer, + OPCUAServerEndPoint, + ServerSecureChannelLayer, + OPCUACertificateManager, +} from "node-opcua"; +import { OPCUADiscoveryServerOptions } from "node-opcua-server-discovery"; + +import { green, yellow, red } from "./../utils/log"; + +(async () => { + try { + const config: OPCUADiscoveryServerOptions = { + port: 4840, + serverCertificateManager: new OPCUACertificateManager({ + automaticallyAcceptUnknownCertificate: true, + name: "discovery_pki", + rootFolder: "discovery_pki", + }), + serverInfo: { + applicationName: { + text: "SampleDiscoveryServer-applicationName", + locale: "en", + }, + applicationUri: "urn:SampleDiscoveryServer", + productUri: "SampleDiscoveryServer-productUri", + }, + }; + const lds = new OPCUADiscoveryServer(config) + .on( + "newChannel", + (channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint) => { + green( + ` DiscoveryServer: newChannel! ChannelId:${channel.channelId} - ${channel.remoteAddress}:${channel.remotePort} `, + ); + }, + ) + .on( + "closeChannel", + (channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint) => { + green( + ` DiscoveryServer: closeChannel! ChannelId:${channel.channelId} - ${channel.remoteAddress}:${channel.remotePort} `, + ); + }, + ) + .on( + "connectionRefused", + (socketData: any, endpoint: OPCUAServerEndPoint) => { + red(` DiscoveryServer: connectionRefused! \n ${endpoint.serverInfo}`); + }, + ) + .on( + "openSecureChannelFailure", + (socketData: any, channelData: any, endpoint: OPCUAServerEndPoint) => { + red( + ` DiscoveryServer: openSecureChannelFailure! \n ${channelData} \n ${endpoint.serverInfo}`, + ); + }, + ) + .on("error", (e) => { + red(` DiscoveryServer: ${e} `); }) - yellow(' DiscoveryServer: starting server... ') - await lds.start() - green(' DiscoveryServer: is running! ') - } catch (error) { - red(` DiscoveryServer error: ${error}`) - process.exit(-1) - } - })() \ No newline at end of file + .on("debug", (e) => { + yellow(` DiscoveryServer: ${e} `); + }); + yellow(" DiscoveryServer: starting server... "); + await lds.start(); + green(" DiscoveryServer: is running! "); + } catch (error) { + red(` DiscoveryServer error: ${error}`); + process.exit(-1); + } +})(); diff --git a/src/addressspace.ts b/src/addressspace.ts index c7fc179d..9893ac59 100644 --- a/src/addressspace.ts +++ b/src/addressspace.ts @@ -70,9 +70,9 @@ export const createAddressSpace = async ( green(" Creating AddressSpace done! "); }) .catch((error: Error) => { - red(` Creating AddressSpace failed!`) - console.log(error) - throw error + red(` Creating AddressSpace failed!`); + console.log(error); + throw error; }) : () => { throw new Error( diff --git a/src/config.ts b/src/config.ts index 233c12d8..c46f5dcf 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { readFileSync } from 'fs'; -import yargs from 'yargs'; +import { readFileSync } from "fs"; +import yargs from "yargs"; import { MessageSecurityMode, SecurityPolicy, @@ -22,88 +22,104 @@ import { ApplicationType, OPCUAServerOptions, OPCUACertificateManager, - RegisterServerMethod -} from 'node-opcua'; -import { isValidUserAsync, getUserRoles } from './user'; -import { red } from './utils/log'; - -const argv = yargs(process.argv.slice(2)).options({ - ip: { type: 'string' }, - port: { type: 'number' }, - configpath: { type: 'string' } -}).parseSync(); - -const configPath: string = process.env.CONFIGPATH || argv.configpath || ''; -const configFile: string = 'configuration.json'; + RegisterServerMethod, +} from "node-opcua"; +import { isValidUserAsync, getUserRoles } from "./user"; +import { red } from "./utils/log"; + +const argv = yargs(process.argv.slice(2)) + .options({ + ip: { type: "string" }, + port: { type: "number" }, + configpath: { type: "string" }, + }) + .parseSync(); + +const configPath: string = process.env.CONFIGPATH || argv.configpath || ""; +const configFile: string = "configuration.json"; let configJsonObj: OPCUAServerOptions; try { - const configString = readFileSync(configPath + configFile, 'utf-8'); + const configString = readFileSync(configPath + configFile, "utf-8"); configJsonObj = JSON.parse(configString) || {}; } catch (error) { red(`Error while loading file: ${configFile} -> ${error}`); configJsonObj = {}; -}; +} -const packageString: string = readFileSync('package.json', 'utf-8'); +const packageString: string = readFileSync("package.json", "utf-8"); const packageJsonObj = JSON.parse(packageString) || {}; let config: OPCUAServerOptions = {}; -config.hostname = process.env.IP || argv.ip || configJsonObj.hostname || '127.0.0.1'; +config.hostname = + process.env.IP || argv.ip || configJsonObj.hostname || "127.0.0.1"; if (!configJsonObj.port) { config.port = Number(process.env.PORT) || argv.port || 4840; } else { config.port = Number(process.env.PORT) || argv.port || configJsonObj.port; -}; +} if (config.port != 4840) { config.registerServerMethod = RegisterServerMethod.LDS; // config.registerServerMethod = RegisterServerMethod.MDNS; } else { config.registerServerMethod = RegisterServerMethod.HIDDEN; -}; +} //process.env.HOSTNAMES = "opcua3.umati.app" -config.alternateHostname = process.env.HOSTNAMES?.split(",") || configJsonObj.alternateHostname || []; +config.alternateHostname = + process.env.HOSTNAMES?.split(",") || configJsonObj.alternateHostname || []; // config.alternateEndpoints = configJsonObj.alternateEndpoints || []; -config.maxConnectionsPerEndpoint = configJsonObj.maxConnectionsPerEndpoint || 100; +config.maxConnectionsPerEndpoint = + configJsonObj.maxConnectionsPerEndpoint || 100; config.timeout = configJsonObj.timeout; -config.resourcePath = configJsonObj.resourcePath || '/UA'; +config.resourcePath = configJsonObj.resourcePath || "/UA"; config.allowAnonymous = configJsonObj.allowAnonymous || true; config.disableDiscovery = configJsonObj.disableDiscovery || true; -config.discoveryServerEndpointUrl = configJsonObj.discoveryServerEndpointUrl || 'opc.tcp://127.0.0.1:4840'; +config.discoveryServerEndpointUrl = + configJsonObj.discoveryServerEndpointUrl || "opc.tcp://127.0.0.1:4840"; config.nodeset_filename = configJsonObj.nodeset_filename || []; config.isAuditing = configJsonObj.isAuditing || false; // https://github.com/node-opcua/node-opcua/blob/master/packages/node-opcua-service-discovery/source/server_capabilities.ts // http://www.opcfoundation.org/UA/schemas/1.04/ServerCapabilities.csv -config.capabilitiesForMDNS = configJsonObj.capabilitiesForMDNS || ['NA']; -config.defaultSecureTokenLifetime = configJsonObj.defaultSecureTokenLifetime || 300000; +config.capabilitiesForMDNS = configJsonObj.capabilitiesForMDNS || ["NA"]; +config.defaultSecureTokenLifetime = + configJsonObj.defaultSecureTokenLifetime || 300000; // BuildInfo config.buildInfo = {}; -config.buildInfo.productUri = configJsonObj.buildInfo?.productUri || 'SampleServer-productUri'; -config.buildInfo.productName = configJsonObj.buildInfo?.productName || 'SampleServer-productName'; -config.buildInfo.manufacturerName = configJsonObj.buildInfo?.manufacturerName || -'SampleServer-manufacturerName'; -config.buildInfo.buildNumber = configJsonObj.buildInfo?.buildNumber || 'v1.0.0'; -config.buildInfo.buildDate = new Date(String(configJsonObj.buildInfo?.buildDate)) || new Date(); -config.buildInfo.softwareVersion = `node-opcua: ${packageJsonObj.dependencies['node-opcua']}`; +config.buildInfo.productUri = + configJsonObj.buildInfo?.productUri || "SampleServer-productUri"; +config.buildInfo.productName = + configJsonObj.buildInfo?.productName || "SampleServer-productName"; +config.buildInfo.manufacturerName = + configJsonObj.buildInfo?.manufacturerName || "SampleServer-manufacturerName"; +config.buildInfo.buildNumber = configJsonObj.buildInfo?.buildNumber || "v1.0.0"; +config.buildInfo.buildDate = + new Date(String(configJsonObj.buildInfo?.buildDate)) || new Date(); +config.buildInfo.softwareVersion = `node-opcua: ${packageJsonObj.dependencies["node-opcua"]}`; // ServerInfo -const applicationName = 'SampleServer-applicationName'; +const applicationName = "SampleServer-applicationName"; config.serverInfo = {}; -config.serverInfo.applicationName = configJsonObj.serverInfo?.applicationName || { - 'text': applicationName, - 'locale': 'en-US' +config.serverInfo.applicationName = configJsonObj.serverInfo + ?.applicationName || { + text: applicationName, + locale: "en-US", }; -config.serverInfo.applicationUri = configJsonObj.serverInfo?.applicationUri || 'urn:SampleServer'; -config.serverInfo.productUri = configJsonObj.serverInfo?.productUri || 'SampleServer-productUri'; -config.serverInfo.applicationType = configJsonObj.serverInfo?.applicationType || ApplicationType.Server; -config.serverInfo.gatewayServerUri = configJsonObj.serverInfo?.gatewayServerUri || ''; -config.serverInfo.discoveryProfileUri = configJsonObj.serverInfo?.discoveryProfileUri || ''; +config.serverInfo.applicationUri = + configJsonObj.serverInfo?.applicationUri || "urn:SampleServer"; +config.serverInfo.productUri = + configJsonObj.serverInfo?.productUri || "SampleServer-productUri"; +config.serverInfo.applicationType = + configJsonObj.serverInfo?.applicationType || ApplicationType.Server; +config.serverInfo.gatewayServerUri = + configJsonObj.serverInfo?.gatewayServerUri || ""; +config.serverInfo.discoveryProfileUri = + configJsonObj.serverInfo?.discoveryProfileUri || ""; config.serverInfo.discoveryUrls = configJsonObj.serverInfo?.discoveryUrls || []; // ServerCapabilities and OperationLimits @@ -111,47 +127,55 @@ const operationLimits = configJsonObj.serverCapabilities?.operationLimits; config.serverCapabilities = new ServerCapabilities({ maxSessions: configJsonObj.serverCapabilities?.maxSessions || 100, localeIdArray: configJsonObj.serverCapabilities?.localeIdArray || ["en-Us"], - maxBrowseContinuationPoints: configJsonObj.serverCapabilities?.maxBrowseContinuationPoints || 10, + maxBrowseContinuationPoints: + configJsonObj.serverCapabilities?.maxBrowseContinuationPoints || 10, maxArrayLength: configJsonObj.serverCapabilities?.maxArrayLength || 1000, // minSupportedSampleRate: configJsonObj.serverCapabilities?.minSupportedSampleRate || 100, // maxByteStringLength: configJsonObj.serverCapabilities?.maxByteStringLength || undefined, // maxStringLength: configJsonObj.serverCapabilities?.maxStringLength || undefined, - maxHistoryContinuationPoints: configJsonObj.serverCapabilities?.maxHistoryContinuationPoints || 10, - operationLimits: ({ + maxHistoryContinuationPoints: + configJsonObj.serverCapabilities?.maxHistoryContinuationPoints || 10, + operationLimits: { maxMonitoredItemsPerCall: operationLimits?.maxMonitoredItemsPerCall || 1000, maxNodesPerBrowse: operationLimits?.maxNodesPerBrowse || 1000, - maxNodesPerHistoryReadData: operationLimits?.maxNodesPerHistoryReadData || 1000, - maxNodesPerHistoryReadEvents: operationLimits?.maxNodesPerHistoryReadEvents || 1000, - maxNodesPerHistoryUpdateData: operationLimits?.maxNodesPerHistoryUpdateData || 1000, - maxNodesPerHistoryUpdateEvents: operationLimits?.maxNodesPerHistoryUpdateEvents || 1000, + maxNodesPerHistoryReadData: + operationLimits?.maxNodesPerHistoryReadData || 1000, + maxNodesPerHistoryReadEvents: + operationLimits?.maxNodesPerHistoryReadEvents || 1000, + maxNodesPerHistoryUpdateData: + operationLimits?.maxNodesPerHistoryUpdateData || 1000, + maxNodesPerHistoryUpdateEvents: + operationLimits?.maxNodesPerHistoryUpdateEvents || 1000, maxNodesPerMethodCall: operationLimits?.maxNodesPerMethodCall || 100, - maxNodesPerNodeManagement: operationLimits?.maxNodesPerNodeManagement || 100, + maxNodesPerNodeManagement: + operationLimits?.maxNodesPerNodeManagement || 100, maxNodesPerRead: operationLimits?.maxNodesPerRead || 1000, maxNodesPerRegisterNodes: operationLimits?.maxNodesPerRegisterNodes || 1000, - maxNodesPerTranslateBrowsePathsToNodeIds: operationLimits?.maxNodesPerTranslateBrowsePathsToNodeIds || 1000, + maxNodesPerTranslateBrowsePathsToNodeIds: + operationLimits?.maxNodesPerTranslateBrowsePathsToNodeIds || 1000, maxNodesPerWrite: operationLimits?.maxNodesPerWrite || 1000, - - } as IOperationLimits2), + } as IOperationLimits2, // https://profiles.opcfoundation.org/v104/Reporting/ // https://reference.opcfoundation.org/v104/Core/docs/Part7/6.2/ - serverProfileArray: configJsonObj.serverCapabilities?.serverProfileArray || [], + serverProfileArray: + configJsonObj.serverCapabilities?.serverProfileArray || [], softwareCertificates: [], // To Do! create SignedSoftwareCertificate[] from string[] }); const userManager = { isValidUserAsync: isValidUserAsync, - getUserRoles: getUserRoles + getUserRoles: getUserRoles, }; config.userManager = userManager; -OPCUACertificateManager.defaultCertificateSubject = `/CN=${applicationName}@${config.hostname}/ST=HE/OU=E/DC=${config.alternateHostname}/O=Umati/L=Frankfurt/C=DE` +OPCUACertificateManager.defaultCertificateSubject = `/CN=${applicationName}@${config.hostname}/ST=HE/OU=E/DC=${config.alternateHostname}/O=Umati/L=Frankfurt/C=DE`; const serverCertificateManager = new OPCUACertificateManager({ automaticallyAcceptUnknownCertificate: true, - name: 'PKI', - rootFolder: './pki', - keySize: 2048 + name: "PKI", + rootFolder: "./pki", + keySize: 2048, }); // const serverCertFile = './pki/own/certs/server_cert.pem'; @@ -162,9 +186,9 @@ const serverCertificateManager = new OPCUACertificateManager({ const userCertificateManager = new OPCUACertificateManager({ automaticallyAcceptUnknownCertificate: false, - name: 'UserPKI', - rootFolder: './user_pki', - keySize: 2048 + name: "UserPKI", + rootFolder: "./user_pki", + keySize: 2048, }); config.userCertificateManager = userCertificateManager; @@ -173,13 +197,13 @@ config.serverCertificateManager = serverCertificateManager; config.securityModes = [ MessageSecurityMode.None, MessageSecurityMode.Sign, - MessageSecurityMode.SignAndEncrypt + MessageSecurityMode.SignAndEncrypt, ]; config.securityPolicies = [ SecurityPolicy.None, SecurityPolicy.Basic128Rsa15, - SecurityPolicy.Basic256Sha256 + SecurityPolicy.Basic256Sha256, ]; export { config }; diff --git a/src/machines/LaserSystem/LaserSystem.ts b/src/machines/LaserSystem/LaserSystem.ts index 1fd9956f..d6449fac 100644 --- a/src/machines/LaserSystem/LaserSystem.ts +++ b/src/machines/LaserSystem/LaserSystem.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const createLaserSystemLogic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const createLaserSystemLogic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/MyControledMachine/enums.ts b/src/machines/MyControledMachine/enums.ts index eccc9cf6..a2c958b7 100644 --- a/src/machines/MyControledMachine/enums.ts +++ b/src/machines/MyControledMachine/enums.ts @@ -10,49 +10,49 @@ // distributed under the License is distributed on an 'AS IS' BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and -// limitations under the License. +// limitations under the License. export enum ISA95_Method_ReturnCode { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/B.2#_Ref58414046 - NoError = 0, - UnknownJobOrderId = 1, - InvalidJobOrderStatus = 3, - UnableToAcceptJobOrder = 4, - // Reserved = 5-31 - InvalidRequest = 32 - // Implementation-specific = 33-63 + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/B.2#_Ref58414046 + NoError = 0, + UnknownJobOrderId = 1, + InvalidJobOrderStatus = 3, + UnableToAcceptJobOrder = 4, + // Reserved = 5-31 + InvalidRequest = 32, + // Implementation-specific = 33-63 } export enum JobExecutionMode { - // https://reference.opcfoundation.org/Machinery/Jobs/v100/docs/9.1 - SimulationMode = 0, - TestMode = 1, - ProductionMode = 2 + // https://reference.opcfoundation.org/Machinery/Jobs/v100/docs/9.1 + SimulationMode = 0, + TestMode = 1, + ProductionMode = 2, } export enum JobResult { - // https://reference.opcfoundation.org/Machinery/Jobs/v100/docs/9.2 - Unknown = 0, - Successful = 1, - Unsuccessful = 2 + // https://reference.opcfoundation.org/Machinery/Jobs/v100/docs/9.2 + Unknown = 0, + Successful = 1, + Unsuccessful = 2, } export enum JobState { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.2.1.2#_Ref53493741 - NotAllowedToStart = "NotAllowedToStart", - AllowedToStart = "AllowedToStart", - Running = "Running", - Interrupted = "Interrupted", - Ended = "Ended", - Aborted = "Aborted" + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.2.1.2#_Ref53493741 + NotAllowedToStart = "NotAllowedToStart", + AllowedToStart = "AllowedToStart", + Running = "Running", + Interrupted = "Interrupted", + Ended = "Ended", + Aborted = "Aborted", } export enum JobStateNumber { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.2.1.2#_Ref53493741 - NotAllowedToStart = 1, - AllowedToStart = 2, - Running = 3, - Interrupted = 4, - Ended = 5, - Aborted = 6 -} \ No newline at end of file + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.2.1.2#_Ref53493741 + NotAllowedToStart = 1, + AllowedToStart = 2, + Running = 3, + Interrupted = 4, + Ended = 5, + Aborted = 6, +} diff --git a/src/machines/MyControledMachine/interfaces.ts b/src/machines/MyControledMachine/interfaces.ts index c64060a6..7fca6699 100644 --- a/src/machines/MyControledMachine/interfaces.ts +++ b/src/machines/MyControledMachine/interfaces.ts @@ -14,34 +14,34 @@ import { DateTime, LocalizedText } from "node-opcua"; -export interface ISA95JobOrderDataType { - jobOrderID: string, - description: LocalizedText[], - /** - * ISA95WorkMasterDataType[] - */ - workMasterID: any[] - startTime: DateTime, - endTime: DateTime, - priority: number, - /** - * ISA95ParameterDataType[] - */ - jobOrderParameters: any[] - /** - * ISA95PersonnelDataType[] - */ - personnelRequirements: any[] - /** - * ISA95EquipmentDataType[] - */ - equipmentRequirements: any[] - /** - * ISA95PhysicalAssetDataType[] - */ - physicalAssetRequirements: any[] - /** - * ISA95MaterialDataType[] - */ - materialRequirements: any[] +export interface ISA95JobOrderDataType { + jobOrderID: string; + description: LocalizedText[]; + /** + * ISA95WorkMasterDataType[] + */ + workMasterID: any[]; + startTime: DateTime; + endTime: DateTime; + priority: number; + /** + * ISA95ParameterDataType[] + */ + jobOrderParameters: any[]; + /** + * ISA95PersonnelDataType[] + */ + personnelRequirements: any[]; + /** + * ISA95EquipmentDataType[] + */ + equipmentRequirements: any[]; + /** + * ISA95PhysicalAssetDataType[] + */ + physicalAssetRequirements: any[]; + /** + * ISA95MaterialDataType[] + */ + materialRequirements: any[]; } diff --git a/src/machines/MyControledMachine/job.ts b/src/machines/MyControledMachine/job.ts index 3600f7be..311c51c6 100644 --- a/src/machines/MyControledMachine/job.ts +++ b/src/machines/MyControledMachine/job.ts @@ -12,138 +12,140 @@ // See the License for the specific language governing permissions and // limitations under the License. -import EventEmitter from "events" -import { JobState, JobStateNumber } from "./enums" -import { ISA95JobOrderDataType } from "./interfaces" +import EventEmitter from "events"; +import { JobState, JobStateNumber } from "./enums"; +import { ISA95JobOrderDataType } from "./interfaces"; export class Job extends EventEmitter { + state: JobState = JobState.NotAllowedToStart; + stateNumber: JobStateNumber = JobStateNumber.NotAllowedToStart; + jobOrder: ISA95JobOrderDataType; + startTime: Date | undefined = undefined; + endTime: Date | undefined = undefined; - state: JobState = JobState.NotAllowedToStart - stateNumber: JobStateNumber = JobStateNumber.NotAllowedToStart - jobOrder: ISA95JobOrderDataType - startTime: Date | undefined = undefined - endTime: Date | undefined = undefined + constructor(jobOrder: ISA95JobOrderDataType) { + super(); + this.jobOrder = jobOrder; + this.emit("changed", this.jobOrder); + } - constructor (jobOrder: ISA95JobOrderDataType) { - super() - this.jobOrder = jobOrder - this.emit("changed", this.jobOrder) + update(jobOrder: ISA95JobOrderDataType): boolean { + if ( + this.state === JobState.AllowedToStart || + this.state === JobState.NotAllowedToStart + ) { + this.jobOrder = jobOrder; + this.emit("changed", this.jobOrder); + return true; + } else { + return false; } + } - update(jobOrder: ISA95JobOrderDataType): boolean { - if (this.state === JobState.AllowedToStart || this.state === JobState.NotAllowedToStart) { - this.jobOrder = jobOrder - this.emit("changed", this.jobOrder) - return true - } else { - return false - } + revokeStart(): boolean { + switch (this.state) { + case JobState.AllowedToStart: + this.state = JobState.NotAllowedToStart; + this.stateNumber = JobStateNumber.NotAllowedToStart; + this.emit("changed", this.jobOrder); + return true; + default: + return false; } + } - revokeStart(): boolean { - switch (this.state) { - case JobState.AllowedToStart: - this.state = JobState.NotAllowedToStart - this.stateNumber = JobStateNumber.NotAllowedToStart - this.emit("changed", this.jobOrder) - return true - default: - return false - } + start(): boolean { + switch (this.state) { + case JobState.AllowedToStart: + this.state = JobState.Running; + this.stateNumber = JobStateNumber.Running; + this.startTime = new Date(); + this.emit("changed", this.jobOrder); + return true; + case JobState.NotAllowedToStart: + this.state = JobState.AllowedToStart; + this.stateNumber = JobStateNumber.AllowedToStart; + this.emit("changed", this.jobOrder); + return true; + default: + return false; } + } - start(): boolean { - switch (this.state) { - case JobState.AllowedToStart: - this.state = JobState.Running - this.stateNumber = JobStateNumber.Running - this.startTime = new Date() - this.emit("changed", this.jobOrder) - return true - case JobState.NotAllowedToStart: - this.state = JobState.AllowedToStart - this.stateNumber = JobStateNumber.AllowedToStart - this.emit("changed", this.jobOrder) - return true - default: - return false - } + stop(): boolean { + switch (this.state) { + case JobState.Running: + this.state = JobState.Ended; + this.stateNumber = JobStateNumber.Ended; + this.endTime = new Date(); + this.emit("changed", this.jobOrder); + return true; + case JobState.Interrupted: + this.state = JobState.Ended; + this.stateNumber = JobStateNumber.Ended; + this.endTime = new Date(); + this.emit("changed", this.jobOrder); + return true; + default: + return false; } + } - stop(): boolean { - switch (this.state) { - case JobState.Running: - this.state = JobState.Ended - this.stateNumber = JobStateNumber.Ended - this.endTime = new Date() - this.emit("changed", this.jobOrder) - return true - case JobState.Interrupted: - this.state = JobState.Ended - this.stateNumber = JobStateNumber.Ended - this.endTime = new Date() - this.emit("changed", this.jobOrder) - return true - default: - return false - } + abort(): boolean { + switch (this.state) { + case JobState.AllowedToStart: + this.state = JobState.Aborted; + this.stateNumber = JobStateNumber.Aborted; + this.emit("changed", this.jobOrder); + return true; + case JobState.NotAllowedToStart: + this.state = JobState.Aborted; + this.stateNumber = JobStateNumber.Aborted; + this.emit("changed", this.jobOrder); + return true; + case JobState.Running: + this.state = JobState.Aborted; + this.stateNumber = JobStateNumber.Aborted; + this.emit("changed", this.jobOrder); + return true; + case JobState.Interrupted: + this.state = JobState.Aborted; + this.stateNumber = JobStateNumber.Aborted; + this.emit("changed", this.jobOrder); + return true; + default: + return false; } + } - abort(): boolean { - switch (this.state) { - case JobState.AllowedToStart: - this.state = JobState.Aborted - this.stateNumber = JobStateNumber.Aborted - this.emit("changed", this.jobOrder) - return true - case JobState.NotAllowedToStart: - this.state = JobState.Aborted - this.stateNumber = JobStateNumber.Aborted - this.emit("changed", this.jobOrder) - return true - case JobState.Running: - this.state = JobState.Aborted - this.stateNumber = JobStateNumber.Aborted - this.emit("changed", this.jobOrder) - return true - case JobState.Interrupted: - this.state = JobState.Aborted - this.stateNumber = JobStateNumber.Aborted - this.emit("changed", this.jobOrder) - return true - default: - return false - } + pause(): boolean { + switch (this.state) { + case JobState.Running: + this.state = JobState.Interrupted; + this.stateNumber = JobStateNumber.Interrupted; + this.emit("changed", this.jobOrder); + return true; + default: + return false; } + } - pause(): boolean { - switch (this.state) { - case JobState.Running: - this.state = JobState.Interrupted - this.stateNumber = JobStateNumber.Interrupted - this.emit("changed", this.jobOrder) - return true - default: - return false - } + resume(): boolean { + switch (this.state) { + case JobState.Interrupted: + this.state = JobState.Running; + this.stateNumber = JobStateNumber.Running; + this.emit("changed", this.jobOrder); + return true; + default: + return false; } + } - resume(): boolean { - switch (this.state) { - case JobState.Interrupted: - this.state = JobState.Running - this.stateNumber = JobStateNumber.Running - this.emit("changed", this.jobOrder) - return true - default: - return false - } - } - - cancel(): boolean { - this.state = JobState.NotAllowedToStart - this.stateNumber = JobStateNumber.NotAllowedToStart - this.emit("changed", this.jobOrder) - return true - } -} \ No newline at end of file + cancel(): boolean { + this.state = JobState.NotAllowedToStart; + this.stateNumber = JobStateNumber.NotAllowedToStart; + this.emit("changed", this.jobOrder); + return true; + } +} diff --git a/src/machines/MyControledMachine/jobcontrol.ts b/src/machines/MyControledMachine/jobcontrol.ts index ce62962b..cfcf244f 100644 --- a/src/machines/MyControledMachine/jobcontrol.ts +++ b/src/machines/MyControledMachine/jobcontrol.ts @@ -12,319 +12,417 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, - DataType, - InstantiateObjectOptions, - LocalizedText, - setNamespaceMetaData, - UADataType, - UAObject, - UAObjectType, - UAVariable, - Variant, - standardUnits, - UAMethod, - ISessionContext, - CallbackT, - CallMethodResultOptions, - StatusCodes, - DataValue, - EventNotifierFlags, - AddReferenceOpts, - ReferenceTypeIds, - UAEventType, - coerceNodeId, - coerceLocalizedText, - coerceDateTime -} from 'node-opcua' -import { ServerRolePermissionGroup } from '../../permissiongroups' -import { ISA95JobOrderDataType } from './interfaces' -import { ISA95_Method_ReturnCode, JobState, JobStateNumber } from './enums' -import { green, yellow } from '../../utils/log' -import { randomUUID } from 'node:crypto' -import { Job } from './job' - -export const createJobContolLogic = async (addressSpace: AddressSpace): Promise => { - const machineryIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/Machinery/') - const machinesFolder = addressSpace?.findNode(`ns=${machineryIdx};i=1001`) as UAObject - - const namespace = addressSpace?.registerNamespace('http://MyControledMachine-Namespace/UA') - namespace.setDefaultRolePermissions(ServerRolePermissionGroup.DEFAULT) - setNamespaceMetaData(namespace) - - const controledMachine = namespace?.addObject({ - browseName: 'MyControledMachine', - nodeId: `ns=${namespace.index};s=MyControledMachine`, - organizedBy: machinesFolder, - }) - - const machineryIdentificationType = addressSpace?.findNode(`ns=${machineryIdx};i=1012`) as UAObjectType - const myMachineIdentification = machineryIdentificationType?.instantiate({ - browseName: { - name: 'Identification', - namespaceIndex: machineryIdx - }, - namespace: namespace, - optionals: [], // array of string - }) - myMachineIdentification.addReference({ - referenceType: 'HasAddIn', - nodeId: controledMachine, - isForward: false, - }) - const manufacturer = myMachineIdentification?.getChildByName('Manufacturer') as UAVariable - manufacturer?.setValueFromSource({ - dataType: DataType.LocalizedText, - value: coerceLocalizedText('Andreas Heine'), - }) - const uri = myMachineIdentification?.getChildByName('ProductInstanceUri') as UAVariable - uri?.setValueFromSource({ - dataType: DataType.String, - value: 'ProductInstanceUri-123', - }) - const serial = myMachineIdentification?.getChildByName('SerialNumber') as UAVariable - serial?.setValueFromSource({ - dataType: DataType.String, - value: 'SerialNumber-123', - }) - - const jobIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/Machinery/Jobs/') - const jobManagementType = addressSpace?.findNode(`ns=${jobIdx};i=1003`) as UAObjectType - - const jobManager = jobManagementType.instantiate({ - componentOf: controledMachine, - browseName: `JobManager`, - namespace: namespace, - optionals: [ - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.2.1 - "JobOrderControl.StoreAndStart", - "JobOrderControl.Store", - "JobOrderControl.Start", - "JobOrderControl.Update", - "JobOrderControl.Stop", - "JobOrderControl.Cancel", - "JobOrderControl.Clear", - "JobOrderControl.RevokeStart", - "JobOrderControl.Pause", - "JobOrderControl.Abort", - "JobOrderControl.Resume", - ] - } as InstantiateObjectOptions) - - const ISA95Idx = addressSpace.getNamespaceIndex("http://opcfoundation.org/UA/ISA95-JOBCONTROL_V2/") - - const ISA95WorkMasterDataType = addressSpace!.findNode(`ns=${ISA95Idx};i=3007`) as UADataType - const ISA95ParameterDataType = addressSpace!.findNode(`ns=${ISA95Idx};i=3003`) as UADataType - const ISA95JobOrderDataType = addressSpace!.findNode(`ns=${ISA95Idx};i=3008`) as UADataType - const ISA95JobResponseDataType = addressSpace!.findNode(`ns=${ISA95Idx};i=3013`) as UADataType - const ISA95StateDataType = addressSpace!.findNode(`ns=${ISA95Idx};i=3006`) as UADataType - - const JobOrderControl = jobManager.getComponentByName("JobOrderControl") as UAObject - const JobOrderResults = jobManager.getComponentByName("JobOrderResults") as UAObject - - const ISA95JobOrderStatusEventType = addressSpace!.findNode(`ns=${ISA95Idx};i=1006`) as UAEventType - - const MyControledMachineJobOrderResultStatusEventType = namespace.addEventType({ - browseName: 'MyControledMachineJobOrderResultStatusEventType', - subtypeOf: ISA95JobOrderStatusEventType, - isAbstract: false - }) - - ISA95JobOrderStatusEventType.addReference({ - referenceType: `GeneratesEvent`, - nodeId: JobOrderResults.nodeId, - isForward: false, - } as AddReferenceOpts) - - const severObject = addressSpace.findNode(coerceNodeId(`ns=0;i=2253`))! - - severObject.addReference({ - referenceType: `HasEventSource`, - nodeId: JobOrderResults.nodeId, - isForward: true, - } as AddReferenceOpts) - - function emitISA95JobOrderStatusEvent(JobOrderId: string): void { - if (JobOrderMap.has(JobOrderId) === false) return - const job = JobOrderMap.get(JobOrderId) - green(`JobOrderControl(MyControledMachine): raise ISA95JobOrderStatusEvent for JobOrderId='${JobOrderId}' JobState='${job!.state}'`) - JobOrderResults.raiseEvent( - MyControledMachineJobOrderResultStatusEventType, +import { + AddressSpace, + DataType, + InstantiateObjectOptions, + LocalizedText, + setNamespaceMetaData, + UADataType, + UAObject, + UAObjectType, + UAVariable, + Variant, + standardUnits, + UAMethod, + ISessionContext, + CallbackT, + CallMethodResultOptions, + StatusCodes, + DataValue, + EventNotifierFlags, + AddReferenceOpts, + ReferenceTypeIds, + UAEventType, + coerceNodeId, + coerceLocalizedText, + coerceDateTime, +} from "node-opcua"; +import { ServerRolePermissionGroup } from "../../permissiongroups"; +import { ISA95JobOrderDataType } from "./interfaces"; +import { ISA95_Method_ReturnCode, JobState, JobStateNumber } from "./enums"; +import { green, yellow } from "../../utils/log"; +import { randomUUID } from "node:crypto"; +import { Job } from "./job"; + +export const createJobContolLogic = async ( + addressSpace: AddressSpace, +): Promise => { + const machineryIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/Machinery/", + ); + const machinesFolder = addressSpace?.findNode( + `ns=${machineryIdx};i=1001`, + ) as UAObject; + + const namespace = addressSpace?.registerNamespace( + "http://MyControledMachine-Namespace/UA", + ); + namespace.setDefaultRolePermissions(ServerRolePermissionGroup.DEFAULT); + setNamespaceMetaData(namespace); + + const controledMachine = namespace?.addObject({ + browseName: "MyControledMachine", + nodeId: `ns=${namespace.index};s=MyControledMachine`, + organizedBy: machinesFolder, + }); + + const machineryIdentificationType = addressSpace?.findNode( + `ns=${machineryIdx};i=1012`, + ) as UAObjectType; + const myMachineIdentification = machineryIdentificationType?.instantiate({ + browseName: { + name: "Identification", + namespaceIndex: machineryIdx, + }, + namespace: namespace, + optionals: [], // array of string + }); + myMachineIdentification.addReference({ + referenceType: "HasAddIn", + nodeId: controledMachine, + isForward: false, + }); + const manufacturer = myMachineIdentification?.getChildByName( + "Manufacturer", + ) as UAVariable; + manufacturer?.setValueFromSource({ + dataType: DataType.LocalizedText, + value: coerceLocalizedText("Andreas Heine"), + }); + const uri = myMachineIdentification?.getChildByName( + "ProductInstanceUri", + ) as UAVariable; + uri?.setValueFromSource({ + dataType: DataType.String, + value: "ProductInstanceUri-123", + }); + const serial = myMachineIdentification?.getChildByName( + "SerialNumber", + ) as UAVariable; + serial?.setValueFromSource({ + dataType: DataType.String, + value: "SerialNumber-123", + }); + + const jobIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/Machinery/Jobs/", + ); + const jobManagementType = addressSpace?.findNode( + `ns=${jobIdx};i=1003`, + ) as UAObjectType; + + const jobManager = jobManagementType.instantiate({ + componentOf: controledMachine, + browseName: `JobManager`, + namespace: namespace, + optionals: [ + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.2.1 + "JobOrderControl.StoreAndStart", + "JobOrderControl.Store", + "JobOrderControl.Start", + "JobOrderControl.Update", + "JobOrderControl.Stop", + "JobOrderControl.Cancel", + "JobOrderControl.Clear", + "JobOrderControl.RevokeStart", + "JobOrderControl.Pause", + "JobOrderControl.Abort", + "JobOrderControl.Resume", + ], + } as InstantiateObjectOptions); + + const ISA95Idx = addressSpace.getNamespaceIndex( + "http://opcfoundation.org/UA/ISA95-JOBCONTROL_V2/", + ); + + const ISA95WorkMasterDataType = addressSpace!.findNode( + `ns=${ISA95Idx};i=3007`, + ) as UADataType; + const ISA95ParameterDataType = addressSpace!.findNode( + `ns=${ISA95Idx};i=3003`, + ) as UADataType; + const ISA95JobOrderDataType = addressSpace!.findNode( + `ns=${ISA95Idx};i=3008`, + ) as UADataType; + const ISA95JobResponseDataType = addressSpace!.findNode( + `ns=${ISA95Idx};i=3013`, + ) as UADataType; + const ISA95StateDataType = addressSpace!.findNode( + `ns=${ISA95Idx};i=3006`, + ) as UADataType; + + const JobOrderControl = jobManager.getComponentByName( + "JobOrderControl", + ) as UAObject; + const JobOrderResults = jobManager.getComponentByName( + "JobOrderResults", + ) as UAObject; + + const ISA95JobOrderStatusEventType = addressSpace!.findNode( + `ns=${ISA95Idx};i=1006`, + ) as UAEventType; + + const MyControledMachineJobOrderResultStatusEventType = + namespace.addEventType({ + browseName: "MyControledMachineJobOrderResultStatusEventType", + subtypeOf: ISA95JobOrderStatusEventType, + isAbstract: false, + }); + + ISA95JobOrderStatusEventType.addReference({ + referenceType: `GeneratesEvent`, + nodeId: JobOrderResults.nodeId, + isForward: false, + } as AddReferenceOpts); + + const severObject = addressSpace.findNode(coerceNodeId(`ns=0;i=2253`))!; + + severObject.addReference({ + referenceType: `HasEventSource`, + nodeId: JobOrderResults.nodeId, + isForward: true, + } as AddReferenceOpts); + + function emitISA95JobOrderStatusEvent(JobOrderId: string): void { + if (JobOrderMap.has(JobOrderId) === false) return; + const job = JobOrderMap.get(JobOrderId); + green( + `JobOrderControl(MyControledMachine): raise ISA95JobOrderStatusEvent for JobOrderId='${JobOrderId}' JobState='${job!.state}'`, + ); + JobOrderResults.raiseEvent( + MyControledMachineJobOrderResultStatusEventType, + { + jobOrder: new Variant({ + value: addressSpace.constructExtensionObject( + ISA95JobOrderDataType, + job!.jobOrder as any, + ), + dataType: DataType.ExtensionObject, + }), + jobResponse: new Variant({ + value: addressSpace.constructExtensionObject( + ISA95JobResponseDataType, { - jobOrder: new Variant({ - value: addressSpace.constructExtensionObject(ISA95JobOrderDataType, (job!.jobOrder as any)), - dataType: DataType.ExtensionObject + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.5 + ID: `${randomUUID()}`, + Description: coerceLocalizedText(null), + JobOrderID: JobOrderId, + StartTime: coerceDateTime(job!.startTime), + EndTime: coerceDateTime(job!.endTime), + JobState: [ + addressSpace.constructExtensionObject(ISA95StateDataType, { + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.2 + BrowsePath: null, + StateText: new LocalizedText({ + locale: "en-EN", + text: job!.state, + }), + StateNumber: job!.stateNumber, }), - jobResponse: new Variant({ - value: addressSpace.constructExtensionObject(ISA95JobResponseDataType, { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.5 - ID: `${randomUUID()}`, - Description: coerceLocalizedText(null), - JobOrderID: JobOrderId, - StartTime: coerceDateTime(job!.startTime), - EndTime: coerceDateTime(job!.endTime), - JobState: [ - addressSpace.constructExtensionObject(ISA95StateDataType, { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.2 - BrowsePath: null, - StateText: new LocalizedText({locale: "en-EN", text: job!.state}), - StateNumber: job!.stateNumber - }) - ], // ISA95StateDataType[] - JobResponseData: [], // ISA95ParameterDataType[] - PersonnelActuals: [], // ISA95PersonnelDataType[] - EquipmentActuals: [], // ISA95EquipmentDataType[] - PhysicalAssetActuals: [], // ISA95PhysicalAssetDataType[] - MaterialActuals: [], // ISA95MaterialDataType[] - }), - dataType: DataType.ExtensionObject - }), - jobState: new Variant({ - value: [ - addressSpace.constructExtensionObject(ISA95StateDataType, { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.2 - BrowsePath: null, - StateText: new LocalizedText({locale: "en-EN", text: job!.state}), - StateNumber: job!.stateNumber - }) - ], - dataType: DataType.ExtensionObject - }) - } - ) - } + ], // ISA95StateDataType[] + JobResponseData: [], // ISA95ParameterDataType[] + PersonnelActuals: [], // ISA95PersonnelDataType[] + EquipmentActuals: [], // ISA95EquipmentDataType[] + PhysicalAssetActuals: [], // ISA95PhysicalAssetDataType[] + MaterialActuals: [], // ISA95MaterialDataType[] + }, + ), + dataType: DataType.ExtensionObject, + }), + jobState: new Variant({ + value: [ + addressSpace.constructExtensionObject(ISA95StateDataType, { + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.2 + BrowsePath: null, + StateText: new LocalizedText({ + locale: "en-EN", + text: job!.state, + }), + StateNumber: job!.stateNumber, + }), + ], + dataType: DataType.ExtensionObject, + }), + }, + ); + } + + const WorkMaster = JobOrderControl.getComponentByName( + "WorkMaster", + ) as UAVariable; - const WorkMaster = JobOrderControl.getComponentByName("WorkMaster") as UAVariable - - const JobOrderControlCurrentState = JobOrderControl.getComponentByName("CurrentState") as UAVariable - JobOrderControlCurrentState.setValueFromSource({ - value: coerceLocalizedText(JobState.Running), - dataType: DataType.LocalizedText - }) - const JobOrderControlCurrentStateId = JobOrderControlCurrentState.getPropertyByName("Id") as UAVariable - JobOrderControlCurrentStateId.setValueFromSource({ - value: coerceNodeId(`ns=${ISA95Idx};i=5037`), - dataType: DataType.NodeId - }) - - const JobOrderMap = new Map() - - function startJobOrder(JobOrderId: string, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrderId) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`) - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - const job = JobOrderMap.get(JobOrderId) - const result = job!.start() - if (result === true) { - return ISA95_Method_ReturnCode.NoError - } else { - return ISA95_Method_ReturnCode.InvalidRequest - } + const JobOrderControlCurrentState = JobOrderControl.getComponentByName( + "CurrentState", + ) as UAVariable; + JobOrderControlCurrentState.setValueFromSource({ + value: coerceLocalizedText(JobState.Running), + dataType: DataType.LocalizedText, + }); + const JobOrderControlCurrentStateId = + JobOrderControlCurrentState.getPropertyByName("Id") as UAVariable; + JobOrderControlCurrentStateId.setValueFromSource({ + value: coerceNodeId(`ns=${ISA95Idx};i=5037`), + dataType: DataType.NodeId, + }); + + const JobOrderMap = new Map(); + + function startJobOrder( + JobOrderId: string, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrderId) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`, + ); + return ISA95_Method_ReturnCode.UnknownJobOrderId; + } + const job = JobOrderMap.get(JobOrderId); + const result = job!.start(); + if (result === true) { + return ISA95_Method_ReturnCode.NoError; + } else { + return ISA95_Method_ReturnCode.InvalidRequest; } + } - function stopJobOrder(JobOrderId: string, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrderId) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`) - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - const job = JobOrderMap.get(JobOrderId) - const result = job!.stop() - if (result === true) { - return ISA95_Method_ReturnCode.NoError - } else { - return ISA95_Method_ReturnCode.InvalidRequest - } + function stopJobOrder( + JobOrderId: string, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrderId) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`, + ); + return ISA95_Method_ReturnCode.UnknownJobOrderId; } + const job = JobOrderMap.get(JobOrderId); + const result = job!.stop(); + if (result === true) { + return ISA95_Method_ReturnCode.NoError; + } else { + return ISA95_Method_ReturnCode.InvalidRequest; + } + } - function cancelJobOrder(JobOrderId: string, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrderId) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`) - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - const job = JobOrderMap.get(JobOrderId) - const result = job!.cancel() - if (result === true) { - return clearJobOrder(JobOrderId, Comment) - } else { - return ISA95_Method_ReturnCode.InvalidRequest - } - + function cancelJobOrder( + JobOrderId: string, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrderId) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`, + ); + return ISA95_Method_ReturnCode.UnknownJobOrderId; + } + const job = JobOrderMap.get(JobOrderId); + const result = job!.cancel(); + if (result === true) { + return clearJobOrder(JobOrderId, Comment); + } else { + return ISA95_Method_ReturnCode.InvalidRequest; } + } - function revokeStartJobOrder(JobOrderId: string, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrderId) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`) - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - const job = JobOrderMap.get(JobOrderId) - const result = job!.revokeStart() - if (result === true) { - return ISA95_Method_ReturnCode.NoError - } else { - return ISA95_Method_ReturnCode.InvalidRequest - } + function revokeStartJobOrder( + JobOrderId: string, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrderId) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`, + ); + return ISA95_Method_ReturnCode.UnknownJobOrderId; } + const job = JobOrderMap.get(JobOrderId); + const result = job!.revokeStart(); + if (result === true) { + return ISA95_Method_ReturnCode.NoError; + } else { + return ISA95_Method_ReturnCode.InvalidRequest; + } + } - function pauseJobOrder(JobOrderId: string, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrderId) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`) - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - const job = JobOrderMap.get(JobOrderId) - const result = job!.pause() - if (result === true) { - return ISA95_Method_ReturnCode.NoError - } else { - return ISA95_Method_ReturnCode.InvalidRequest - } + function pauseJobOrder( + JobOrderId: string, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrderId) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`, + ); + return ISA95_Method_ReturnCode.UnknownJobOrderId; + } + const job = JobOrderMap.get(JobOrderId); + const result = job!.pause(); + if (result === true) { + return ISA95_Method_ReturnCode.NoError; + } else { + return ISA95_Method_ReturnCode.InvalidRequest; } + } - function abortJobOrder(JobOrderId: string, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrderId) === false) { - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - const job = JobOrderMap.get(JobOrderId) - const result = job!.abort() - if (result === true) { - return ISA95_Method_ReturnCode.NoError - } else { - return ISA95_Method_ReturnCode.InvalidRequest - } + function abortJobOrder( + JobOrderId: string, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrderId) === false) { + return ISA95_Method_ReturnCode.UnknownJobOrderId; + } + const job = JobOrderMap.get(JobOrderId); + const result = job!.abort(); + if (result === true) { + return ISA95_Method_ReturnCode.NoError; + } else { + return ISA95_Method_ReturnCode.InvalidRequest; } + } - function resumeJobOrder(JobOrderId: string, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrderId) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`) - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - const job = JobOrderMap.get(JobOrderId) - const result = job!.resume() - if (result === true) { - return ISA95_Method_ReturnCode.NoError - } else { - return ISA95_Method_ReturnCode.InvalidRequest - } + function resumeJobOrder( + JobOrderId: string, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrderId) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`, + ); + return ISA95_Method_ReturnCode.UnknownJobOrderId; } + const job = JobOrderMap.get(JobOrderId); + const result = job!.resume(); + if (result === true) { + return ISA95_Method_ReturnCode.NoError; + } else { + return ISA95_Method_ReturnCode.InvalidRequest; + } + } - function updateJobOrder(JobOrder: ISA95JobOrderDataType, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrder.jobOrderID) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrder.jobOrderID}'`) - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - const job = JobOrderMap.get(JobOrder.jobOrderID) - const result = job!.update(JobOrder) - if (result === true) { - return ISA95_Method_ReturnCode.NoError - } else { - return ISA95_Method_ReturnCode.InvalidRequest - } + function updateJobOrder( + JobOrder: ISA95JobOrderDataType, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrder.jobOrderID) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrder.jobOrderID}'`, + ); + return ISA95_Method_ReturnCode.UnknownJobOrderId; + } + const job = JobOrderMap.get(JobOrder.jobOrderID); + const result = job!.update(JobOrder); + if (result === true) { + return ISA95_Method_ReturnCode.NoError; + } else { + return ISA95_Method_ReturnCode.InvalidRequest; } + } - function storeJobOrder(JobOrder: ISA95JobOrderDataType, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v100/docs/6.3.2 - /* + function storeJobOrder( + JobOrder: ISA95JobOrderDataType, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v100/docs/6.3.2 + /* ISA95JobOrderDataType { jobOrderID: 'asdf', description: undefined, @@ -339,79 +437,102 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< materialRequirements: undefined } */ - if (JobOrderMap.has(JobOrder.jobOrderID)) { - yellow(`JobOrderControl(MyControledMachine): JobOrderId='${JobOrder.jobOrderID}' already exist!`) - return ISA95_Method_ReturnCode.UnableToAcceptJobOrder - } - const job = new Job(JobOrder) - job.on("changed", (jobOrder) => { - updateJobOrderList() - emitISA95JobOrderStatusEvent(jobOrder.jobOrderID) - }) - JobOrderMap.set(JobOrder.jobOrderID, job) - updateJobOrderList() - return ISA95_Method_ReturnCode.NoError + if (JobOrderMap.has(JobOrder.jobOrderID)) { + yellow( + `JobOrderControl(MyControledMachine): JobOrderId='${JobOrder.jobOrderID}' already exist!`, + ); + return ISA95_Method_ReturnCode.UnableToAcceptJobOrder; } + const job = new Job(JobOrder); + job.on("changed", (jobOrder) => { + updateJobOrderList(); + emitISA95JobOrderStatusEvent(jobOrder.jobOrderID); + }); + JobOrderMap.set(JobOrder.jobOrderID, job); + updateJobOrderList(); + return ISA95_Method_ReturnCode.NoError; + } - function clearJobOrder(JobOrderId: string, Comment: LocalizedText[]): ISA95_Method_ReturnCode { - if (JobOrderMap.has(JobOrderId) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`) - return ISA95_Method_ReturnCode.UnknownJobOrderId - } - JobOrderMap.delete(JobOrderId) - updateJobOrderList() - return ISA95_Method_ReturnCode.NoError + function clearJobOrder( + JobOrderId: string, + Comment: LocalizedText[], + ): ISA95_Method_ReturnCode { + if (JobOrderMap.has(JobOrderId) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`, + ); + return ISA95_Method_ReturnCode.UnknownJobOrderId; } + JobOrderMap.delete(JobOrderId); + updateJobOrderList(); + return ISA95_Method_ReturnCode.NoError; + } - function getJobOrderList(): ISA95JobOrderDataType[] { - return Array.from(JobOrderMap.values()).map((job: Job) => { return job.jobOrder }) - } + function getJobOrderList(): ISA95JobOrderDataType[] { + return Array.from(JobOrderMap.values()).map((job: Job) => { + return job.jobOrder; + }); + } - function getJobList(): Job[] { - return Array.from(JobOrderMap.values()).map((job: Job) => { return job }) - } + function getJobList(): Job[] { + return Array.from(JobOrderMap.values()).map((job: Job) => { + return job; + }); + } - setInterval(() => { - const jobs = getJobList() - jobs.forEach((job) => { - switch (job.state) { - case JobState.AllowedToStart: - job.start() - break; - case JobState.Running: - setTimeout(() => { - job.stop() - }, 10 * 1000) - break; - default: - break; - } - }) - }, 1 * 1000) + setInterval(() => { + const jobs = getJobList(); + jobs.forEach((job) => { + switch (job.state) { + case JobState.AllowedToStart: + job.start(); + break; + case JobState.Running: + setTimeout(() => { + job.stop(); + }, 10 * 1000); + break; + default: + break; + } + }); + }, 1 * 1000); - // JobOrderList - let jobs: ISA95JobOrderDataType[] + // JobOrderList + let jobs: ISA95JobOrderDataType[]; - function updateJobOrderList() { - green(`JobOrderControl(MyControledMachine): Updating JobOrderList`) - jobs = getJobOrderList() - } + function updateJobOrderList() { + green(`JobOrderControl(MyControledMachine): Updating JobOrderList`); + jobs = getJobOrderList(); + } + + const JobOrderList = JobOrderControl.getComponentByName( + "JobOrderList", + ) as UAVariable; + JobOrderList.bindVariable( + { + get: function (this: UAVariable): Variant { + return new Variant({ + value: jobs, + dataType: DataType.ExtensionObject, + }); + }, + }, + true, + ); - const JobOrderList = JobOrderControl.getComponentByName("JobOrderList") as UAVariable - JobOrderList.bindVariable({ - get: function(this: UAVariable): Variant { - return new Variant({ - value: jobs, - dataType: DataType.ExtensionObject - }) - }, - }, true) - - // Methods - - const StoreAndStart = JobOrderControl.getMethodByName("StoreAndStart") as UAMethod - StoreAndStart.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + // Methods + + const StoreAndStart = JobOrderControl.getMethodByName( + "StoreAndStart", + ) as UAMethod; + StoreAndStart.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method receives a new job order and stores the new job order in local storage, and start it as soon as the Job Order receiver is ready to start. After successful execution of the method, the JobOrderList shall have a new entry in state AllowedToStart. Note: the system may internally start executing the job order immediately, so potentially the job order is already in a different state when accessed the first time. The signature of this Method is specified below. Table 17 and Table 18 specify the Arguments and AddressSpace representation, respectively. StoreAndStart ( @@ -420,40 +541,50 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).StoreAndStart: sessionId='${context.session?.getSessionId()} jobOrderId='${(inputArguments[0].value as ISA95JobOrderDataType).jobOrderID}'`) - try { - let rc - rc = storeJobOrder(inputArguments[0].value, inputArguments[1].value) - if (rc === ISA95_Method_ReturnCode.NoError) { - rc = startJobOrder((inputArguments[0].value as ISA95JobOrderDataType).jobOrderID, inputArguments[1].value) - } - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Store = JobOrderControl.getMethodByName("Store") as UAMethod - Store.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).StoreAndStart: sessionId='${context.session?.getSessionId()} jobOrderId='${(inputArguments[0].value as ISA95JobOrderDataType).jobOrderID}'`, + ); + try { + let rc; + rc = storeJobOrder(inputArguments[0].value, inputArguments[1].value); + if (rc === ISA95_Method_ReturnCode.NoError) { + rc = startJobOrder( + (inputArguments[0].value as ISA95JobOrderDataType).jobOrderID, + inputArguments[1].value, + ); + } + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Store = JobOrderControl.getMethodByName("Store") as UAMethod; + Store.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method receives a new job order and stores the new job order in local storage, but does not start the job order. After successful execution of the method, the JobOrderList shall have a new entry in state NotAllowedToStart. The signature of this Method is specified below. Table 15 and Table 16 specify the Arguments and AddressSpace representation, respectively. Store ( @@ -462,36 +593,46 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Store: sessionId='${context.session?.getSessionId()}' jobOrderId='${(inputArguments[0].value as ISA95JobOrderDataType).jobOrderID}'`) - try { - const rc = storeJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Start = JobOrderControl.getMethodByName("Start") as UAMethod - Start.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Store: sessionId='${context.session?.getSessionId()}' jobOrderId='${(inputArguments[0].value as ISA95JobOrderDataType).jobOrderID}'`, + ); + try { + const rc = storeJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Start = JobOrderControl.getMethodByName("Start") as UAMethod; + Start.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method starts a job order as soon as the Job Order receiver is ready to start. After successful execution of the method, job order in the JobOrderList shall be in state AllowedToStart. If multiple job orders have been commanded to start, then the priority and timing values in the job orders shall be used to determine the order of execution of the job orders. The signature of this Method is specified below. Table 19 and Table 20 specify the Arguments and AddressSpace representation, respectively. @@ -501,36 +642,46 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Start: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`) - try { - const rc = startJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Update = JobOrderControl.getMethodByName("Update") as UAMethod - Update.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Start: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`, + ); + try { + const rc = startJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Update = JobOrderControl.getMethodByName("Update") as UAMethod; + Update.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method updates an existing job order that has not yet been started, with the new order information. All previously stored information is replaced. The signature of this Method is specified below. Table 27 and Table 28 specify the Arguments and AddressSpace representation, respectively. Update ( @@ -539,36 +690,46 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Update: sessionId='${context.session?.getSessionId()}' jobOrderId='${(inputArguments[0].value as ISA95JobOrderDataType).jobOrderID}'`) - try { - const rc = updateJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Stop = JobOrderControl.getMethodByName("Stop") as UAMethod - Stop.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Update: sessionId='${context.session?.getSessionId()}' jobOrderId='${(inputArguments[0].value as ISA95JobOrderDataType).jobOrderID}'`, + ); + try { + const rc = updateJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Stop = JobOrderControl.getMethodByName("Stop") as UAMethod; + Stop.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method stops a started job order. After successful execution of the method, job order in the JobOrderList shall be in state Ended. The signature of this Method is specified below. Table 31 and Table 32 specify the Arguments and AddressSpace representation, respectively. Stop ( @@ -577,36 +738,43 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Stop: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`) - try { - const rc = stopJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Cancel = JobOrderControl.getMethodByName("Cancel") as UAMethod - Cancel.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Stop: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`, + ); + try { + const rc = stopJobOrder(inputArguments[0].value, inputArguments[1].value); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Cancel = JobOrderControl.getMethodByName("Cancel") as UAMethod; + Cancel.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method cancels a not started job order (in AllowedToStart or NotAllowedToStart) and removes the stored information. After successful execution of the method, there shall be no job order with the JobOrderID in the JobOrderList. The signature of this Method is specified below. Table 33 and Table 34 specify the Arguments and AddressSpace representation, respectively. Cancel ( @@ -615,36 +783,46 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Cancel: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`) - try { - const rc = cancelJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Clear = JobOrderControl.getMethodByName("Clear") as UAMethod - Clear.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Cancel: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`, + ); + try { + const rc = cancelJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Clear = JobOrderControl.getMethodByName("Clear") as UAMethod; + Clear.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method clears any maintained information on the Job Order (usually sent after a receipt of a Job Response with a status of Finished.). After successful execution of the method, there shall be no job order with the JobOrderID in the JobOrderList. Note: It is server-specific whether Job Orders get cleared by the Server automatically when it runs out of resources or after a period of time or other reasons. The signature of this Method is specified below. Table 35 and Table 36 specify the Arguments and AddressSpace representation, respectively. @@ -654,36 +832,48 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Clear: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`) - try { - const rc = clearJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const RevokeStart = JobOrderControl.getMethodByName("RevokeStart") as UAMethod - RevokeStart.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Clear: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`, + ); + try { + const rc = clearJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const RevokeStart = JobOrderControl.getMethodByName( + "RevokeStart", + ) as UAMethod; + RevokeStart.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method revokes a not started job (in AllowedToStart). After successful execution of the method, job order in the JobOrderList shall be in state NotAllowedToStart. The signature of this Method is specified below. Table 21 and Table 22 specify the Arguments and AddressSpace representation, respectively. RevokeStart ( @@ -692,36 +882,46 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).RevokeStart: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`) - try { - const rc = revokeStartJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Pause = JobOrderControl.getMethodByName("Pause") as UAMethod - Pause.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).RevokeStart: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`, + ); + try { + const rc = revokeStartJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Pause = JobOrderControl.getMethodByName("Pause") as UAMethod; + Pause.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method pauses a started job. After successful execution of the method, job order in the JobOrderList shall be in state Interrupted. The signature of this Method is specified below. Table 23 and Table 24 specify the Arguments and AddressSpace representation, respectively. Pause ( @@ -730,36 +930,46 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Pause: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`) - try { - const rc = pauseJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Abort = JobOrderControl.getMethodByName("Abort") as UAMethod - Abort.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Pause: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`, + ); + try { + const rc = pauseJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Abort = JobOrderControl.getMethodByName("Abort") as UAMethod; + Abort.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method aborts a job order. After successful execution of the method, job order in the JobOrderList shall be in state Aborted. The signature of this Method is specified below. Table 29 and Table 30 specify the Arguments and AddressSpace representation, respectively. Abort ( @@ -768,36 +978,46 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Abort: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`) - try { - const rc = abortJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - const Resume = JobOrderControl.getMethodByName("Resume") as UAMethod - Resume.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Abort: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`, + ); + try { + const rc = abortJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + const Resume = JobOrderControl.getMethodByName("Resume") as UAMethod; + Resume.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method resumes an interrupted job (in state Interrupted). After successful execution of the method, job order in the JobOrderList shall be in state Running. The signature of this Method is specified below. Table 25 and Table 26 specify the Arguments and AddressSpace representation, respectively. Resume ( @@ -806,37 +1026,49 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - green(`JobOrderControl(MyControledMachine).Resume: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`) - try { - const rc = resumeJobOrder(inputArguments[0].value, inputArguments[1].value) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - - const RequestJobResponseByJobOrderID = JobOrderResults.getMethodByName("RequestJobResponseByJobOrderID") as UAMethod - RequestJobResponseByJobOrderID.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + green( + `JobOrderControl(MyControledMachine).Resume: sessionId='${context.session?.getSessionId()}' jobOrderId='${inputArguments[0].value}'`, + ); + try { + const rc = resumeJobOrder( + inputArguments[0].value, + inputArguments[1].value, + ); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + + const RequestJobResponseByJobOrderID = JobOrderResults.getMethodByName( + "RequestJobResponseByJobOrderID", + ) as UAMethod; + RequestJobResponseByJobOrderID.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method is used to return Job Responses for unsolicited requests for responses from a job order. The signature of this Method is specified below. Table 51 and Table 52 specify the Arguments and AddressSpace representation, respectively. RequestJobResponseByJobOrderID ( @@ -845,85 +1077,103 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - try { - const JobOrderId = inputArguments[0].value - let rc = ISA95_Method_ReturnCode.NoError - if (JobOrderMap.has(JobOrderId) === false) { - yellow(`JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`) - rc = ISA95_Method_ReturnCode.UnknownJobOrderId - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: addressSpace.constructExtensionObject(ISA95JobResponseDataType, {}), - dataType: DataType.ExtensionObject - }), - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } + try { + const JobOrderId = inputArguments[0].value; + let rc = ISA95_Method_ReturnCode.NoError; + if (JobOrderMap.has(JobOrderId) === false) { + yellow( + `JobOrderControl(MyControledMachine): Unknown JobOrderId='${JobOrderId}'`, + ); + rc = ISA95_Method_ReturnCode.UnknownJobOrderId; + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: addressSpace.constructExtensionObject( + ISA95JobResponseDataType, + {}, + ), + dataType: DataType.ExtensionObject, + }), + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } - const job = JobOrderMap.get(JobOrderId) - - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.Good, - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - outputArguments: [ - new Variant({ - value: addressSpace.constructExtensionObject(ISA95JobResponseDataType, { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.5 - ID: `${randomUUID()}`, - Description: coerceLocalizedText(null), - JobOrderID: JobOrderId, - StartTime: coerceDateTime(job!.startTime), - EndTime: coerceDateTime(job!.endTime), - JobState: [ - addressSpace.constructExtensionObject(ISA95StateDataType, { - // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.2 - BrowsePath: null, - StateText: new LocalizedText({locale: "en-EN", text: job!.state}), - StateNumber: job!.stateNumber - }) - ], // ISA95StateDataType[] - JobResponseData: [], // ISA95ParameterDataType[] - PersonnelActuals: [], // ISA95PersonnelDataType[] - EquipmentActuals: [], // ISA95EquipmentDataType[] - PhysicalAssetActuals: [], // ISA95PhysicalAssetDataType[] - MaterialActuals: [], // ISA95MaterialDataType[] - }), - dataType: DataType.ExtensionObject + const job = JobOrderMap.get(JobOrderId); + + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.Good, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + outputArguments: [ + new Variant({ + value: addressSpace.constructExtensionObject( + ISA95JobResponseDataType, + { + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.5 + ID: `${randomUUID()}`, + Description: coerceLocalizedText(null), + JobOrderID: JobOrderId, + StartTime: coerceDateTime(job!.startTime), + EndTime: coerceDateTime(job!.endTime), + JobState: [ + addressSpace.constructExtensionObject(ISA95StateDataType, { + // https://reference.opcfoundation.org/ISA95JOBCONTROL/v200/docs/6.3.2 + BrowsePath: null, + StateText: new LocalizedText({ + locale: "en-EN", + text: job!.state, }), - new Variant({ - value: rc, - dataType: DataType.UInt64 - }) - ] - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - - const RequestJobResponseByJobOrderState = JobOrderResults.getMethodByName("RequestJobResponseByJobOrderState") as UAMethod - RequestJobResponseByJobOrderState.bindMethod(function (this: UAMethod, inputArguments: Variant[], context: ISessionContext, callback: CallbackT): void { - /* + StateNumber: job!.stateNumber, + }), + ], // ISA95StateDataType[] + JobResponseData: [], // ISA95ParameterDataType[] + PersonnelActuals: [], // ISA95PersonnelDataType[] + EquipmentActuals: [], // ISA95EquipmentDataType[] + PhysicalAssetActuals: [], // ISA95PhysicalAssetDataType[] + MaterialActuals: [], // ISA95MaterialDataType[] + }, + ), + dataType: DataType.ExtensionObject, + }), + new Variant({ + value: rc, + dataType: DataType.UInt64, + }), + ], + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + + const RequestJobResponseByJobOrderState = JobOrderResults.getMethodByName( + "RequestJobResponseByJobOrderState", + ) as UAMethod; + RequestJobResponseByJobOrderState.bindMethod(function ( + this: UAMethod, + inputArguments: Variant[], + context: ISessionContext, + callback: CallbackT, + ): void { + /* This Method is used to return Job Responses for unsolicited requests for responses from a job order. The signature of this Method is specified below. Table 53 and Table 54 specify the Arguments and AddressSpace representation, respectively. RequestJobResponseByJobOrderState ( @@ -932,86 +1182,78 @@ export const createJobContolLogic = async (addressSpace: AddressSpace): Promise< [out]0:UInt64 ReturnStatus ); */ - try { - // TODO !!! - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadNotImplemented - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } catch (error) { - console.log(error) - callback(null, { - // statusCode?: StatusCode; - statusCode: StatusCodes.BadInternalError - // inputArgumentResults?: StatusCode[] | null; - // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; - // outputArguments?: (VariantLike | null)[] | null; - } as CallMethodResultOptions) - } - }) - - // Available WorkMasters - - const subpobj1 = addressSpace.constructExtensionObject(ISA95ParameterDataType, { - ID: "Sub1", - description: [ - new LocalizedText({locale: "de-DE", text: "SubParameter1"}), - ], - value: new Variant({value: 60.1, dataType: DataType.Double}), - engineeringUnits: standardUnits.degree_fahrenheit, - subparameters: [] - }) - - const pobj1 = addressSpace.constructExtensionObject(ISA95ParameterDataType, { - ID: "P1", - description: [ - new LocalizedText({locale: "de-DE", text: "Parameter1"}), - ], - value: new Variant({value: 23.5, dataType: DataType.Double}), - engineeringUnits: standardUnits.degree_celsius, - subparameters: [ - subpobj1 - ] - }) - - const pobj2 = addressSpace.constructExtensionObject(ISA95ParameterDataType, { - ID: "P2", - description: [ - new LocalizedText({locale: "de-DE", text: "Parameter2"}), - ], - value: new Variant({value: 23.5, dataType: DataType.Double}), - engineeringUnits: standardUnits.degree_celsius, - subparameters: [ - subpobj1 - ] - }) - - const wmObj1 = addressSpace.constructExtensionObject(ISA95WorkMasterDataType, { - ID: "Recipe_1", - description: new LocalizedText({locale: "de-DE", text: "Rezept 1"}), - parameters: [ - pobj1, - pobj1 - ] - }) - - const wmObj2 = addressSpace.constructExtensionObject(ISA95WorkMasterDataType, { - ID: "Recipe_2", - description: new LocalizedText({locale: "de-DE", text: "Rezept 2"}), - parameters: [ - pobj2, - pobj2 - ] - }) - - WorkMaster.setValueFromSource({ - value: [ - wmObj1, - wmObj2 - ], - dataType: DataType.ExtensionObject - }) -} \ No newline at end of file + try { + // TODO !!! + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadNotImplemented, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } catch (error) { + console.log(error); + callback(null, { + // statusCode?: StatusCode; + statusCode: StatusCodes.BadInternalError, + // inputArgumentResults?: StatusCode[] | null; + // inputArgumentDiagnosticInfos?: (DiagnosticInfo | null)[] | null; + // outputArguments?: (VariantLike | null)[] | null; + } as CallMethodResultOptions); + } + }); + + // Available WorkMasters + + const subpobj1 = addressSpace.constructExtensionObject( + ISA95ParameterDataType, + { + ID: "Sub1", + description: [ + new LocalizedText({ locale: "de-DE", text: "SubParameter1" }), + ], + value: new Variant({ value: 60.1, dataType: DataType.Double }), + engineeringUnits: standardUnits.degree_fahrenheit, + subparameters: [], + }, + ); + + const pobj1 = addressSpace.constructExtensionObject(ISA95ParameterDataType, { + ID: "P1", + description: [new LocalizedText({ locale: "de-DE", text: "Parameter1" })], + value: new Variant({ value: 23.5, dataType: DataType.Double }), + engineeringUnits: standardUnits.degree_celsius, + subparameters: [subpobj1], + }); + + const pobj2 = addressSpace.constructExtensionObject(ISA95ParameterDataType, { + ID: "P2", + description: [new LocalizedText({ locale: "de-DE", text: "Parameter2" })], + value: new Variant({ value: 23.5, dataType: DataType.Double }), + engineeringUnits: standardUnits.degree_celsius, + subparameters: [subpobj1], + }); + + const wmObj1 = addressSpace.constructExtensionObject( + ISA95WorkMasterDataType, + { + ID: "Recipe_1", + description: new LocalizedText({ locale: "de-DE", text: "Rezept 1" }), + parameters: [pobj1, pobj1], + }, + ); + + const wmObj2 = addressSpace.constructExtensionObject( + ISA95WorkMasterDataType, + { + ID: "Recipe_2", + description: new LocalizedText({ locale: "de-DE", text: "Rezept 2" }), + parameters: [pobj2, pobj2], + }, + ); + + WorkMaster.setValueFromSource({ + value: [wmObj1, wmObj2], + dataType: DataType.ExtensionObject, + }); +}; diff --git a/src/machines/PlasticsRubber/40077.ts b/src/machines/PlasticsRubber/40077.ts index d6e763aa..2a68648b 100644 --- a/src/machines/PlasticsRubber/40077.ts +++ b/src/machines/PlasticsRubber/40077.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const create40077Logic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const create40077Logic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/PlasticsRubber/40079.ts b/src/machines/PlasticsRubber/40079.ts index b1c4a3c8..2eda0a8e 100644 --- a/src/machines/PlasticsRubber/40079.ts +++ b/src/machines/PlasticsRubber/40079.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const create40079Logic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const create40079Logic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/PlasticsRubber/40082-1.ts b/src/machines/PlasticsRubber/40082-1.ts index 7bd6b7c5..3e2d36cf 100644 --- a/src/machines/PlasticsRubber/40082-1.ts +++ b/src/machines/PlasticsRubber/40082-1.ts @@ -12,11 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const create40082_1Logic = async (addressSpace: AddressSpace): Promise => { - - -} \ No newline at end of file +export const create40082_1Logic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/PlasticsRubber/40082-2.ts b/src/machines/PlasticsRubber/40082-2.ts index 236c74b3..10bbee81 100644 --- a/src/machines/PlasticsRubber/40082-2.ts +++ b/src/machines/PlasticsRubber/40082-2.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const create40082_2Logic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const create40082_2Logic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/PlasticsRubber/40082-3.ts b/src/machines/PlasticsRubber/40082-3.ts index 3b234e5c..e2507833 100644 --- a/src/machines/PlasticsRubber/40082-3.ts +++ b/src/machines/PlasticsRubber/40082-3.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const create40082_3Logic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const create40082_3Logic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/PlasticsRubber/40084-11.ts b/src/machines/PlasticsRubber/40084-11.ts index 8d2c3e06..18243d7f 100644 --- a/src/machines/PlasticsRubber/40084-11.ts +++ b/src/machines/PlasticsRubber/40084-11.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const create40084_11Logic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const create40084_11Logic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/PlasticsRubber/40084-3.ts b/src/machines/PlasticsRubber/40084-3.ts index eac96af9..83c47698 100644 --- a/src/machines/PlasticsRubber/40084-3.ts +++ b/src/machines/PlasticsRubber/40084-3.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const create40084_3Logic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const create40084_3Logic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/PlasticsRubber/40084-9.ts b/src/machines/PlasticsRubber/40084-9.ts index 1ce61604..6d91ba20 100644 --- a/src/machines/PlasticsRubber/40084-9.ts +++ b/src/machines/PlasticsRubber/40084-9.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const create40084_9Logic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const create40084_9Logic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/PlasticsRubber/generic.ts b/src/machines/PlasticsRubber/generic.ts index 64475b6e..345b9358 100644 --- a/src/machines/PlasticsRubber/generic.ts +++ b/src/machines/PlasticsRubber/generic.ts @@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const createGenericPRLogic = async (addressSpace: AddressSpace): Promise => { - - /* +export const createGenericPRLogic = async ( + addressSpace: AddressSpace, +): Promise => { + /* machinelogic here: bind opc ua variables to a getter/setter functions or to an js variable -> https://node-opcua.github.io/api_doc/2.32.0/interfaces/node_opcua.uavariable.html#bindvariable @@ -49,5 +48,4 @@ export const createGenericPRLogic = async (addressSpace: AddressSpace): Promise< timestamped_set: myVariableSetter }, true); */ - -} \ No newline at end of file +}; diff --git a/src/machines/WoodWorking/ww_basic.ts b/src/machines/WoodWorking/ww_basic.ts index b9abed3d..2f21077b 100644 --- a/src/machines/WoodWorking/ww_basic.ts +++ b/src/machines/WoodWorking/ww_basic.ts @@ -12,105 +12,221 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - DataType, - UAVariable, - AddressSpace -} from 'node-opcua' +import { DataType, UAVariable, AddressSpace } from "node-opcua"; -export const createWoodWorkingBasicLogic = async (addressSpace: AddressSpace): Promise => { +export const createWoodWorkingBasicLogic = async ( + addressSpace: AddressSpace, +): Promise => { + const nsIdx = addressSpace?.getNamespaceIndex( + "http://basyskom.com/woodworking_demo/", + ); - const nsIdx = addressSpace?.getNamespaceIndex('http://basyskom.com/woodworking_demo/') + // Define basic "bs..." woodworking IDENTIFICATION nodes + const bsDeviceClassNode = addressSpace?.findNode( + `ns=${nsIdx};i=6001`, + ) as UAVariable; + const bsManufacturerNode = addressSpace?.findNode( + `ns=${nsIdx};i=6002`, + ) as UAVariable; + const bsModelNode = addressSpace?.findNode( + `ns=${nsIdx};i=6003`, + ) as UAVariable; + const bsProductInstanceUriNode = addressSpace?.findNode( + `ns=${nsIdx};i=6004`, + ) as UAVariable; + const bsSerialNumberNode = addressSpace?.findNode( + `ns=${nsIdx};i=6005`, + ) as UAVariable; + const bsYearOfConstructionNode = addressSpace?.findNode( + `ns=${nsIdx};i=6006`, + ) as UAVariable; - // Define basic "bs..." woodworking IDENTIFICATION nodes - const bsDeviceClassNode = addressSpace?.findNode(`ns=${nsIdx};i=6001`) as UAVariable; - const bsManufacturerNode = addressSpace?.findNode(`ns=${nsIdx};i=6002`) as UAVariable; - const bsModelNode = addressSpace?.findNode(`ns=${nsIdx};i=6003`) as UAVariable; - const bsProductInstanceUriNode = addressSpace?.findNode(`ns=${nsIdx};i=6004`) as UAVariable; - const bsSerialNumberNode = addressSpace?.findNode(`ns=${nsIdx};i=6005`) as UAVariable; - const bsYearOfConstructionNode = addressSpace?.findNode(`ns=${nsIdx};i=6006`) as UAVariable; + // Define basic "bs..." woodworking STATE - MACHINE -FLAGS nodes + const bsAlarmNode = addressSpace?.findNode( + `ns=${nsIdx};i=6009`, + ) as UAVariable; + const bsCalibratedNode = addressSpace?.findNode( + `ns=${nsIdx};i=6010`, + ) as UAVariable; + const bsEmergencyNode = addressSpace?.findNode( + `ns=${nsIdx};i=6011`, + ) as UAVariable; + const bsErrorNode = addressSpace?.findNode( + `ns=${nsIdx};i=6012`, + ) as UAVariable; + const bsMachineInitNode = addressSpace?.findNode( + `ns=${nsIdx};i=6013`, + ) as UAVariable; + const bsMachineOnNode = addressSpace?.findNode( + `ns=${nsIdx};i=6014`, + ) as UAVariable; + const bsPowerPresentNode = addressSpace?.findNode( + `ns=${nsIdx};i=6015`, + ) as UAVariable; + const bsRecipeInRunNode = addressSpace?.findNode( + `ns=${nsIdx};i=6016`, + ) as UAVariable; + const bsWarningNode = addressSpace?.findNode( + `ns=${nsIdx};i=6017`, + ) as UAVariable; - // Define basic "bs..." woodworking STATE - MACHINE -FLAGS nodes - const bsAlarmNode = addressSpace?.findNode(`ns=${nsIdx};i=6009`) as UAVariable; - const bsCalibratedNode = addressSpace?.findNode(`ns=${nsIdx};i=6010`) as UAVariable; - const bsEmergencyNode = addressSpace?.findNode(`ns=${nsIdx};i=6011`) as UAVariable; - const bsErrorNode = addressSpace?.findNode(`ns=${nsIdx};i=6012`) as UAVariable; - const bsMachineInitNode = addressSpace?.findNode(`ns=${nsIdx};i=6013`) as UAVariable; - const bsMachineOnNode = addressSpace?.findNode(`ns=${nsIdx};i=6014`) as UAVariable; - const bsPowerPresentNode = addressSpace?.findNode(`ns=${nsIdx};i=6015`) as UAVariable; - const bsRecipeInRunNode = addressSpace?.findNode(`ns=${nsIdx};i=6016`) as UAVariable; - const bsWarningNode = addressSpace?.findNode(`ns=${nsIdx};i=6017`) as UAVariable; + // Define basic "bs..." woodworking STATE - MACHINE - OVERVIEW nodes + const bsCurrentModeNode = addressSpace.findNode( + `ns=${nsIdx};i=6007`, + ) as UAVariable; + const bsCurrentStateNode = addressSpace.findNode( + `ns=${nsIdx};i=6008`, + ) as UAVariable; - // Define basic "bs..." woodworking STATE - MACHINE - OVERVIEW nodes - const bsCurrentModeNode = addressSpace.findNode(`ns=${nsIdx};i=6007`) as UAVariable; - const bsCurrentStateNode = addressSpace.findNode(`ns=${nsIdx};i=6008`) as UAVariable; + // Set basic woodworking IDENTIFICATION nodes + bsDeviceClassNode?.setValueFromSource({ + dataType: DataType.String, + value: "Class A12", + }); + bsProductInstanceUriNode?.setValueFromSource({ + dataType: DataType.String, + value: "https://www.example.com", + }); + bsSerialNumberNode?.setValueFromSource({ + dataType: DataType.String, + value: "378485745354392", + }); + bsYearOfConstructionNode?.setValueFromSource({ + dataType: DataType.UInt16, + value: 2023, + }); - // Set basic woodworking IDENTIFICATION nodes - bsDeviceClassNode?.setValueFromSource({ dataType: DataType.String, value: "Class A12" }); - bsProductInstanceUriNode?.setValueFromSource({ dataType: DataType.String, value: "https://www.example.com" }); - bsSerialNumberNode?.setValueFromSource({ dataType: DataType.String, value: "378485745354392" }); - bsYearOfConstructionNode?.setValueFromSource({ dataType: DataType.UInt16, value: 2023 }); + // Set basic woodworking STATE - MACHINE - FLAGS nodes + bsAlarmNode?.setValueFromSource({ dataType: DataType.Boolean, value: false }); + bsCalibratedNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: true, + }); + bsEmergencyNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: false, + }); + bsMachineInitNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: false, + }); + bsMachineOnNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: true, + }); + bsPowerPresentNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: true, + }); + bsRecipeInRunNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: true, + }); + bsWarningNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: false, + }); - // Set basic woodworking STATE - MACHINE - FLAGS nodes - bsAlarmNode?.setValueFromSource({ dataType: DataType.Boolean, value: false }); - bsCalibratedNode?.setValueFromSource({ dataType: DataType.Boolean, value: true }); - bsEmergencyNode?.setValueFromSource({ dataType: DataType.Boolean, value: false }); - bsMachineInitNode?.setValueFromSource({ dataType: DataType.Boolean, value: false }); - bsMachineOnNode?.setValueFromSource({ dataType: DataType.Boolean, value: true }); - bsPowerPresentNode?.setValueFromSource({ dataType: DataType.Boolean, value: true }); - bsRecipeInRunNode?.setValueFromSource({ dataType: DataType.Boolean, value: true }); - bsWarningNode?.setValueFromSource({ dataType: DataType.Boolean, value: false }); - - // Intervall to change opc ua node-values - var intervallID = setInterval(function () { - setBasicWwValues(); - }, 2500); - - // Set the identification values for basic woodworking companion specification - function setBasicWwValues() { - let rndmMin = 10; - let rndmMax = 500; - let rndm = getRandomArbitrary(rndmMin, rndmMax); + // Intervall to change opc ua node-values + var intervallID = setInterval(function () { + setBasicWwValues(); + }, 2500); - // Set basic woodworking STATE - MACHINE - FLAGS nodes - bsAlarmNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 450 ? false : true)}); - bsCalibratedNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm > 170 ? false : true) }); - bsEmergencyNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 350 ? false : true) }); - bsMachineInitNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm > 150 ? false : true) }); - bsMachineOnNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm > 40 ? false : true) }); - bsPowerPresentNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm > 130 ? false : true) }); - bsRecipeInRunNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm > 200 ? false : true) }); - bsWarningNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 350 ? false : true) }); + // Set the identification values for basic woodworking companion specification + function setBasicWwValues() { + let rndmMin = 10; + let rndmMax = 500; + let rndm = getRandomArbitrary(rndmMin, rndmMax); - // Set current mode STATE - MACHINE - OVERWIEW - switch (true) { - case (rndm > 0 && rndm < 100): - bsCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 1 }); - bsCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 4 }); - break; - case (rndm > 100 && rndm < 200): - bsCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 2 }); - bsCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 3 }); - break; - case (rndm > 200 && rndm < 300): - bsCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 3 }); - bsCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 2 }); - break; - case (rndm > 300 && rndm < 400): - bsCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 4 }); - bsCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 1 }); - break; - case (rndm > 400 && rndm < 500): - bsCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 5 }); - break; - default: - break; + // Set basic woodworking STATE - MACHINE - FLAGS nodes + bsAlarmNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 450 ? false : true, + }); + bsCalibratedNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm > 170 ? false : true, + }); + bsEmergencyNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 350 ? false : true, + }); + bsMachineInitNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm > 150 ? false : true, + }); + bsMachineOnNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm > 40 ? false : true, + }); + bsPowerPresentNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm > 130 ? false : true, + }); + bsRecipeInRunNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm > 200 ? false : true, + }); + bsWarningNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 350 ? false : true, + }); - } + // Set current mode STATE - MACHINE - OVERWIEW + switch (true) { + case rndm > 0 && rndm < 100: + bsCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 1, + }); + bsCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 4, + }); + break; + case rndm > 100 && rndm < 200: + bsCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 2, + }); + bsCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 3, + }); + break; + case rndm > 200 && rndm < 300: + bsCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 3, + }); + bsCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 2, + }); + break; + case rndm > 300 && rndm < 400: + bsCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 4, + }); + bsCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 1, + }); + break; + case rndm > 400 && rndm < 500: + bsCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 5, + }); + break; + default: + break; } + } - //Returns an randomized value between given range - function getRandomArbitrary(min: number, max: number): number { - return Math.random() * (max - min) + min; - } -} + //Returns an randomized value between given range + function getRandomArbitrary(min: number, max: number): number { + return Math.random() * (max - min) + min; + } +}; diff --git a/src/machines/WoodWorking/ww_full.ts b/src/machines/WoodWorking/ww_full.ts index fc6fe92e..70814767 100644 --- a/src/machines/WoodWorking/ww_full.ts +++ b/src/machines/WoodWorking/ww_full.ts @@ -12,236 +12,642 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - DataType, - UAVariable, - AddressSpace -} from 'node-opcua' +import { DataType, UAVariable, AddressSpace } from "node-opcua"; -export const createWoodWorkingFullLogic = async (addressSpace: AddressSpace): Promise => { +export const createWoodWorkingFullLogic = async ( + addressSpace: AddressSpace, +): Promise => { + const nsIdx = addressSpace?.getNamespaceIndex( + "http://basyskom.com/woodworking_demo/", + ); - const nsIdx = addressSpace?.getNamespaceIndex('http://basyskom.com/woodworking_demo/') + // Define full "fl..." woodworking IDENTIFICATION nodes + const flAssetIdNode = addressSpace?.findNode( + `ns=${nsIdx};i=6026`, + ) as UAVariable; + const flComponentNameNode = addressSpace?.findNode( + `ns=${nsIdx};i=6027`, + ) as UAVariable; + const flCustomerCompNameNode = addressSpace?.findNode( + `ns=${nsIdx};i=6028`, + ) as UAVariable; + const flDeviceClassNode = addressSpace?.findNode( + `ns=${nsIdx};i=6018`, + ) as UAVariable; + const flHardwareRevNode = addressSpace?.findNode( + `ns=${nsIdx};i=6029`, + ) as UAVariable; + const flInitOperDataNode = addressSpace?.findNode( + `ns=${nsIdx};i=6030`, + ) as UAVariable; + const flLocationNode = addressSpace?.findNode( + `ns=${nsIdx};i=6031`, + ) as UAVariable; + const flLocationGpsNode = addressSpace?.findNode( + `ns=${nsIdx};i=6032`, + ) as UAVariable; + const flLocationPlantNode = addressSpace?.findNode( + `ns=${nsIdx};i=6033`, + ) as UAVariable; + const flManufacturerNode = addressSpace?.findNode( + `ns=${nsIdx};i=6019`, + ) as UAVariable; + const flManufacturerUriNode = addressSpace?.findNode( + `ns=${nsIdx};i=6034`, + ) as UAVariable; + const flModelNode = addressSpace?.findNode( + `ns=${nsIdx};i=6020`, + ) as UAVariable; + const flProductCodeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6036`, + ) as UAVariable; + const flProductInstanceUriNode = addressSpace?.findNode( + `ns=${nsIdx};i=6021`, + ) as UAVariable; + const flSerialNumberNode = addressSpace?.findNode( + `ns=${nsIdx};i=6022`, + ) as UAVariable; + const flSoftwareRevisionNode = addressSpace?.findNode( + `ns=${nsIdx};i=6037`, + ) as UAVariable; + const flYearOfConstructionNode = addressSpace?.findNode( + `ns=${nsIdx};i=6023`, + ) as UAVariable; - // Define full "fl..." woodworking IDENTIFICATION nodes - const flAssetIdNode = addressSpace?.findNode(`ns=${nsIdx};i=6026`) as UAVariable; - const flComponentNameNode = addressSpace?.findNode(`ns=${nsIdx};i=6027`) as UAVariable; - const flCustomerCompNameNode = addressSpace?.findNode(`ns=${nsIdx};i=6028`) as UAVariable; - const flDeviceClassNode = addressSpace?.findNode(`ns=${nsIdx};i=6018`) as UAVariable; - const flHardwareRevNode = addressSpace?.findNode(`ns=${nsIdx};i=6029`) as UAVariable; - const flInitOperDataNode = addressSpace?.findNode(`ns=${nsIdx};i=6030`) as UAVariable; - const flLocationNode = addressSpace?.findNode(`ns=${nsIdx};i=6031`) as UAVariable; - const flLocationGpsNode = addressSpace?.findNode(`ns=${nsIdx};i=6032`) as UAVariable; - const flLocationPlantNode = addressSpace?.findNode(`ns=${nsIdx};i=6033`) as UAVariable; - const flManufacturerNode = addressSpace?.findNode(`ns=${nsIdx};i=6019`) as UAVariable; - const flManufacturerUriNode = addressSpace?.findNode(`ns=${nsIdx};i=6034`) as UAVariable; - const flModelNode = addressSpace?.findNode(`ns=${nsIdx};i=6020`) as UAVariable; - const flProductCodeNode = addressSpace?.findNode(`ns=${nsIdx};i=6036`) as UAVariable; - const flProductInstanceUriNode = addressSpace?.findNode(`ns=${nsIdx};i=6021`) as UAVariable; - const flSerialNumberNode = addressSpace?.findNode(`ns=${nsIdx};i=6022`) as UAVariable; - const flSoftwareRevisionNode = addressSpace?.findNode(`ns=${nsIdx};i=6037`) as UAVariable; - const flYearOfConstructionNode = addressSpace?.findNode(`ns=${nsIdx};i=6023`) as UAVariable; + // Define full "fl..." woodworking STATE - MACHINE -FLAGS nodes + const flAairPresentNode = addressSpace?.findNode( + `ns=${nsIdx};i=6048`, + ) as UAVariable; + const flAlarmNode = addressSpace?.findNode( + `ns=${nsIdx};i=6039`, + ) as UAVariable; + const flCalibratedNode = addressSpace?.findNode( + `ns=${nsIdx};i=6040`, + ) as UAVariable; + const flDustChipSuctionNode = addressSpace?.findNode( + `ns=${nsIdx};i=6049`, + ) as UAVariable; + const flEmergencyNode = addressSpace?.findNode( + `ns=${nsIdx};i=6041`, + ) as UAVariable; + const flEnergySafingNode = addressSpace?.findNode( + `ns=${nsIdx};i=60340`, + ) as UAVariable; + const flErrorNode = addressSpace?.findNode( + `ns=${nsIdx};i=6042`, + ) as UAVariable; + const flExternalEmergencyNode = addressSpace?.findNode( + `ns=${nsIdx};i=6051`, + ) as UAVariable; + const flFeedRunsNode = addressSpace?.findNode( + `ns=${nsIdx};i=6052`, + ) as UAVariable; + const flHoldNode = addressSpace?.findNode(`ns=${nsIdx};i=6053`) as UAVariable; + const flLoadingEnabledNode = addressSpace?.findNode( + `ns=${nsIdx};i=6054`, + ) as UAVariable; + const flMachineInitNode = addressSpace?.findNode( + `ns=${nsIdx};i=6043`, + ) as UAVariable; + const flMachineOnNode = addressSpace?.findNode( + `ns=${nsIdx};i=6044`, + ) as UAVariable; + const flMaintananceReqiredNode = addressSpace?.findNode( + `ns=${nsIdx};i=6055`, + ) as UAVariable; + const flManualActivityReqNode = addressSpace?.findNode( + `ns=${nsIdx};i=6056`, + ) as UAVariable; + const flMovingNode = addressSpace?.findNode( + `ns=${nsIdx};i=6057`, + ) as UAVariable; + const flPowerPresentNode = addressSpace?.findNode( + `ns=${nsIdx};i=6045`, + ) as UAVariable; + const flRecipeInHoldNode = addressSpace?.findNode( + `ns=${nsIdx};i=6058`, + ) as UAVariable; + const flRecipeInRunNode = addressSpace?.findNode( + `ns=${nsIdx};i=6046`, + ) as UAVariable; + const flRecipeInSetupNode = addressSpace?.findNode( + `ns=${nsIdx};i=6059`, + ) as UAVariable; + const flRemoteNode = addressSpace?.findNode( + `ns=${nsIdx};i=6060`, + ) as UAVariable; + const flSafetyNode = addressSpace?.findNode( + `ns=${nsIdx};i=6061`, + ) as UAVariable; + const flWaitLoadNode = addressSpace?.findNode( + `ns=${nsIdx};i=6062`, + ) as UAVariable; + const flWaitUnloadNode = addressSpace?.findNode( + `ns=${nsIdx};i=6063`, + ) as UAVariable; + const flWarningNode = addressSpace?.findNode( + `ns=${nsIdx};i=6047`, + ) as UAVariable; + const flWorkPiecePresentNode = addressSpace?.findNode( + `ns=${nsIdx};i=6064`, + ) as UAVariable; - // Define full "fl..." woodworking STATE - MACHINE -FLAGS nodes - const flAairPresentNode = addressSpace?.findNode(`ns=${nsIdx};i=6048`) as UAVariable; - const flAlarmNode = addressSpace?.findNode(`ns=${nsIdx};i=6039`) as UAVariable; - const flCalibratedNode = addressSpace?.findNode(`ns=${nsIdx};i=6040`) as UAVariable; - const flDustChipSuctionNode = addressSpace?.findNode(`ns=${nsIdx};i=6049`) as UAVariable; - const flEmergencyNode = addressSpace?.findNode(`ns=${nsIdx};i=6041`) as UAVariable; - const flEnergySafingNode = addressSpace?.findNode(`ns=${nsIdx};i=60340`) as UAVariable; - const flErrorNode = addressSpace?.findNode(`ns=${nsIdx};i=6042`) as UAVariable; - const flExternalEmergencyNode = addressSpace?.findNode(`ns=${nsIdx};i=6051`) as UAVariable; - const flFeedRunsNode = addressSpace?.findNode(`ns=${nsIdx};i=6052`) as UAVariable; - const flHoldNode = addressSpace?.findNode(`ns=${nsIdx};i=6053`) as UAVariable; - const flLoadingEnabledNode = addressSpace?.findNode(`ns=${nsIdx};i=6054`) as UAVariable; - const flMachineInitNode = addressSpace?.findNode(`ns=${nsIdx};i=6043`) as UAVariable; - const flMachineOnNode = addressSpace?.findNode(`ns=${nsIdx};i=6044`) as UAVariable; - const flMaintananceReqiredNode = addressSpace?.findNode(`ns=${nsIdx};i=6055`) as UAVariable; - const flManualActivityReqNode = addressSpace?.findNode(`ns=${nsIdx};i=6056`) as UAVariable; - const flMovingNode = addressSpace?.findNode(`ns=${nsIdx};i=6057`) as UAVariable; - const flPowerPresentNode = addressSpace?.findNode(`ns=${nsIdx};i=6045`) as UAVariable; - const flRecipeInHoldNode = addressSpace?.findNode(`ns=${nsIdx};i=6058`) as UAVariable; - const flRecipeInRunNode = addressSpace?.findNode(`ns=${nsIdx};i=6046`) as UAVariable; - const flRecipeInSetupNode = addressSpace?.findNode(`ns=${nsIdx};i=6059`) as UAVariable; - const flRemoteNode = addressSpace?.findNode(`ns=${nsIdx};i=6060`) as UAVariable; - const flSafetyNode = addressSpace?.findNode(`ns=${nsIdx};i=6061`) as UAVariable; - const flWaitLoadNode = addressSpace?.findNode(`ns=${nsIdx};i=6062`) as UAVariable; - const flWaitUnloadNode = addressSpace?.findNode(`ns=${nsIdx};i=6063`) as UAVariable; - const flWarningNode = addressSpace?.findNode(`ns=${nsIdx};i=6047`) as UAVariable; - const flWorkPiecePresentNode = addressSpace?.findNode(`ns=${nsIdx};i=6064`) as UAVariable; + // Define full "fl..." woodworking STATE - MACHINE -OVERVIEW nodes + const flCurrentModeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6024`, + ) as UAVariable; + const flCurrentStateNode = addressSpace?.findNode( + `ns=${nsIdx};i=6025`, + ) as UAVariable; - // Define full "fl..." woodworking STATE - MACHINE -OVERVIEW nodes - const flCurrentModeNode = addressSpace?.findNode(`ns=${nsIdx};i=6024`) as UAVariable; - const flCurrentStateNode = addressSpace?.findNode(`ns=${nsIdx};i=6025`) as UAVariable; + // Define full "fl..." woodworking STATE - MACHINE -VALUES nodes + const flAbsErrorTime = addressSpace?.findNode( + `ns=${nsIdx};i=6065`, + ) as UAVariable; + const flAbsLength = addressSpace?.findNode( + `ns=${nsIdx};i=6066`, + ) as UAVariable; + const flAbsMachOffTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6067`, + ) as UAVariable; + const flAbsMachOnTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6068`, + ) as UAVariable; + const flAbsPiecesInNode = addressSpace?.findNode( + `ns=${nsIdx};i=6069`, + ) as UAVariable; + const flAbsPiecesOutNode = addressSpace?.findNode( + `ns=${nsIdx};i=6070`, + ) as UAVariable; + const flAbsPowerPrsntTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6071`, + ) as UAVariable; + const flAbsProdTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6072`, + ) as UAVariable; + const flAbsProdWaitWorkpTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6073`, + ) as UAVariable; + const flAbsProdWoutWorkpTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6074`, + ) as UAVariable; + const flAbsReadyTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6075`, + ) as UAVariable; + const flAbsRunsAbortedNode = addressSpace?.findNode( + `ns=${nsIdx};i=6076`, + ) as UAVariable; + const flAbsRunsGoodNode = addressSpace?.findNode( + `ns=${nsIdx};i=6077`, + ) as UAVariable; + const flAbsRunsTotalNode = addressSpace?.findNode( + `ns=${nsIdx};i=6078`, + ) as UAVariable; + const flAbsStandbyTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6079`, + ) as UAVariable; + const flAbsWorkingTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6080`, + ) as UAVariable; + const flActCycleNode = addressSpace?.findNode( + `ns=${nsIdx};i=6081`, + ) as UAVariable; + const flAxisOverrideNode = addressSpace?.findNode( + `ns=${nsIdx};i=6082`, + ) as UAVariable; + const flFeedSpeedNode = addressSpace?.findNode( + `ns=${nsIdx};i=6083`, + ) as UAVariable; + const flRelErrorTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6084`, + ) as UAVariable; + const flRelLengthNode = addressSpace?.findNode( + `ns=${nsIdx};i=6085`, + ) as UAVariable; + const flRelMachOnTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6086`, + ) as UAVariable; + const flRelPiecesInNode = addressSpace?.findNode( + `ns=${nsIdx};i=6087`, + ) as UAVariable; + const flRelPiecesOutNode = addressSpace?.findNode( + `ns=${nsIdx};i=6088`, + ) as UAVariable; + const flRelPowerPrsntTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6089`, + ) as UAVariable; + const flRelProdTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6090`, + ) as UAVariable; + const flRelProdWaitWorkpTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6091`, + ) as UAVariable; + const flRelProdWoutWorkpTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6092`, + ) as UAVariable; + const flRelReadyTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6093`, + ) as UAVariable; + const flRelRunsAbortedNode = addressSpace?.findNode( + `ns=${nsIdx};i=6094`, + ) as UAVariable; + const flRelRunsGoodNode = addressSpace?.findNode( + `ns=${nsIdx};i=6095`, + ) as UAVariable; + const flRelRunsTotalNode = addressSpace?.findNode( + `ns=${nsIdx};i=6096`, + ) as UAVariable; + const flRelStandbyTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6097`, + ) as UAVariable; + const flRelWorkingTimeNode = addressSpace?.findNode( + `ns=${nsIdx};i=6098`, + ) as UAVariable; + const flSpindleOverrideNode = addressSpace?.findNode( + `ns=${nsIdx};i=6099`, + ) as UAVariable; - // Define full "fl..." woodworking STATE - MACHINE -VALUES nodes - const flAbsErrorTime = addressSpace?.findNode(`ns=${nsIdx};i=6065`) as UAVariable; - const flAbsLength = addressSpace?.findNode(`ns=${nsIdx};i=6066`) as UAVariable; - const flAbsMachOffTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6067`) as UAVariable; - const flAbsMachOnTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6068`) as UAVariable; - const flAbsPiecesInNode = addressSpace?.findNode(`ns=${nsIdx};i=6069`) as UAVariable; - const flAbsPiecesOutNode = addressSpace?.findNode(`ns=${nsIdx};i=6070`) as UAVariable; - const flAbsPowerPrsntTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6071`) as UAVariable; - const flAbsProdTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6072`) as UAVariable; - const flAbsProdWaitWorkpTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6073`) as UAVariable; - const flAbsProdWoutWorkpTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6074`) as UAVariable; - const flAbsReadyTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6075`) as UAVariable; - const flAbsRunsAbortedNode = addressSpace?.findNode(`ns=${nsIdx};i=6076`) as UAVariable; - const flAbsRunsGoodNode = addressSpace?.findNode(`ns=${nsIdx};i=6077`) as UAVariable; - const flAbsRunsTotalNode = addressSpace?.findNode(`ns=${nsIdx};i=6078`) as UAVariable; - const flAbsStandbyTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6079`) as UAVariable; - const flAbsWorkingTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6080`) as UAVariable; - const flActCycleNode = addressSpace?.findNode(`ns=${nsIdx};i=6081`) as UAVariable; - const flAxisOverrideNode = addressSpace?.findNode(`ns=${nsIdx};i=6082`) as UAVariable; - const flFeedSpeedNode = addressSpace?.findNode(`ns=${nsIdx};i=6083`) as UAVariable; - const flRelErrorTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6084`) as UAVariable; - const flRelLengthNode = addressSpace?.findNode(`ns=${nsIdx};i=6085`) as UAVariable; - const flRelMachOnTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6086`) as UAVariable; - const flRelPiecesInNode = addressSpace?.findNode(`ns=${nsIdx};i=6087`) as UAVariable; - const flRelPiecesOutNode = addressSpace?.findNode(`ns=${nsIdx};i=6088`) as UAVariable; - const flRelPowerPrsntTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6089`) as UAVariable; - const flRelProdTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6090`) as UAVariable; - const flRelProdWaitWorkpTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6091`) as UAVariable; - const flRelProdWoutWorkpTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6092`) as UAVariable; - const flRelReadyTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6093`) as UAVariable; - const flRelRunsAbortedNode = addressSpace?.findNode(`ns=${nsIdx};i=6094`) as UAVariable; - const flRelRunsGoodNode = addressSpace?.findNode(`ns=${nsIdx};i=6095`) as UAVariable; - const flRelRunsTotalNode = addressSpace?.findNode(`ns=${nsIdx};i=6096`) as UAVariable; - const flRelStandbyTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6097`) as UAVariable; - const flRelWorkingTimeNode = addressSpace?.findNode(`ns=${nsIdx};i=6098`) as UAVariable; - const flSpindleOverrideNode = addressSpace?.findNode(`ns=${nsIdx};i=6099`) as UAVariable; + // Set full woodworking IDENTIFICATION nodes + flAssetIdNode?.setValueFromSource({ dataType: DataType.String, value: "12" }); + flDeviceClassNode?.setValueFromSource({ + dataType: DataType.String, + value: "Class A12", + }); + flHardwareRevNode?.setValueFromSource({ + dataType: DataType.String, + value: "V. 4.6", + }); + //initOperDataNode?.setValueFromSource( {dataType: DataType.DateTime, value: Date.now}); + flLocationNode?.setValueFromSource({ + dataType: DataType.String, + value: "Darmstadt", + }); + flLocationGpsNode?.setValueFromSource({ + dataType: DataType.String, + value: "S33�51'25.07\", E151�12'54.57\"", + }); + flLocationPlantNode?.setValueFromSource({ + dataType: DataType.String, + value: "Darmstadt", + }); + flLocationPlantNode?.setValueFromSource({ + dataType: DataType.String, + value: "Darmstadt", + }); + flManufacturerUriNode?.setValueFromSource({ + dataType: DataType.String, + value: "https://www.basyskom.com", + }); + flProductCodeNode?.setValueFromSource({ + dataType: DataType.String, + value: "WW0636C48H3261", + }); + flProductInstanceUriNode?.setValueFromSource({ + dataType: DataType.String, + value: "https://www.example.com", + }); + flSerialNumberNode?.setValueFromSource({ + dataType: DataType.String, + value: "378485745354392", + }); + flSoftwareRevisionNode?.setValueFromSource({ + dataType: DataType.String, + value: "2.6.23", + }); + flYearOfConstructionNode?.setValueFromSource({ + dataType: DataType.UInt16, + value: "2023", + }); + // Intervall to change opc ua node-values + var intervallID = setInterval(function () { + setBasicWwValues(); + }, 2500); - // Set full woodworking IDENTIFICATION nodes - flAssetIdNode?.setValueFromSource({ dataType: DataType.String, value: "12" }); - flDeviceClassNode?.setValueFromSource({ dataType: DataType.String, value: "Class A12" }); - flHardwareRevNode?.setValueFromSource({ dataType: DataType.String, value: "V. 4.6" }); - //initOperDataNode?.setValueFromSource( {dataType: DataType.DateTime, value: Date.now}); - flLocationNode?.setValueFromSource({ dataType: DataType.String, value: "Darmstadt" }); - flLocationGpsNode?.setValueFromSource({ dataType: DataType.String, value: "S33�51'25.07\", E151�12'54.57\"" }); - flLocationPlantNode?.setValueFromSource({ dataType: DataType.String, value: "Darmstadt" }); - flLocationPlantNode?.setValueFromSource({ dataType: DataType.String, value: "Darmstadt" }); - flManufacturerUriNode?.setValueFromSource({ dataType: DataType.String, value: "https://www.basyskom.com" }); - flProductCodeNode?.setValueFromSource({ dataType: DataType.String, value: "WW0636C48H3261" }); - flProductInstanceUriNode?.setValueFromSource({ dataType: DataType.String, value: "https://www.example.com" }); - flSerialNumberNode?.setValueFromSource({ dataType: DataType.String, value: "378485745354392" }); - flSoftwareRevisionNode?.setValueFromSource({ dataType: DataType.String, value: "2.6.23" }); - flYearOfConstructionNode?.setValueFromSource({ dataType: DataType.UInt16, value: "2023" }); + // Set the identification values for basic woodworking companion specification + function setBasicWwValues() { + let rndmMin = 10; + let rndmMax = 500; + let rndm = getRandomArbitrary(rndmMin, rndmMax); + let rndm1 = getRandomArbitrary(rndmMin, rndmMax); + let rndm2 = getRandomArbitrary(rndmMin, rndmMax); + let rndm3 = getRandomArbitrary(rndmMin, rndmMax); + let rndm4 = getRandomArbitrary(rndmMin, rndmMax); + let rndm5 = getRandomArbitrary(rndmMin, rndmMax); + // Set full woodworking STATE - MACHINE -FLAGS nodes + flAairPresentNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 100 ? false : true, + }); + flAlarmNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 450 ? false : true, + }); + flCalibratedNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 310 ? false : true, + }); + flDustChipSuctionNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 200 ? false : true, + }); + flEmergencyNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 180 ? false : true, + }); + flEnergySafingNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 310 ? false : true, + }); + flErrorNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 120 ? false : true, + }); + flExternalEmergencyNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 80 ? false : true, + }); + flFeedRunsNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 415 ? false : true, + }); + flHoldNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 80 ? false : true, + }); + flLoadingEnabledNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 190 ? false : true, + }); + flMachineInitNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 470 ? false : true, + }); + flMachineOnNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 345 ? false : true, + }); + flMaintananceReqiredNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 66 ? false : true, + }); + flManualActivityReqNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 385 ? false : true, + }); + flMovingNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 99 ? false : true, + }); + flPowerPresentNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 269 ? false : true, + }); + flRecipeInHoldNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 145 ? false : true, + }); + flRecipeInRunNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 488 ? false : true, + }); + flRecipeInSetupNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 372 ? false : true, + }); + flRemoteNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 33 ? false : true, + }); + flSafetyNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 172 ? false : true, + }); + flWaitLoadNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 410 ? false : true, + }); + flWaitUnloadNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 255 ? false : true, + }); + flWarningNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 450 ? false : true, + }); + flWorkPiecePresentNode?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 200 ? false : true, + }); - // Intervall to change opc ua node-values - var intervallID = setInterval(function () { - setBasicWwValues(); - }, 2500); + // Set full woodworking STATE - MACHINE - OVERVIEW nodes + flCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 1, + }); + flCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 2, + }); - // Set the identification values for basic woodworking companion specification - function setBasicWwValues() { - let rndmMin = 10; - let rndmMax = 500; - let rndm = getRandomArbitrary(rndmMin, rndmMax); - let rndm1 = getRandomArbitrary(rndmMin, rndmMax); - let rndm2 = getRandomArbitrary(rndmMin, rndmMax); - let rndm3 = getRandomArbitrary(rndmMin, rndmMax); - let rndm4 = getRandomArbitrary(rndmMin, rndmMax); - let rndm5 = getRandomArbitrary(rndmMin, rndmMax); - - // Set full woodworking STATE - MACHINE -FLAGS nodes - flAairPresentNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 100 ? false : true) }); - flAlarmNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 450 ? false : true) }); - flCalibratedNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 310 ? false : true) }); - flDustChipSuctionNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 200 ? false : true) }); - flEmergencyNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 180 ? false : true) }); - flEnergySafingNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 310 ? false : true) }); - flErrorNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 120 ? false : true) }); - flExternalEmergencyNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 80 ? false : true) }); - flFeedRunsNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 415 ? false : true) }); - flHoldNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 80 ? false : true) }); - flLoadingEnabledNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 190 ? false : true) }); - flMachineInitNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 470 ? false : true) }); - flMachineOnNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 345 ? false : true) }); - flMaintananceReqiredNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 66 ? false : true) }); - flManualActivityReqNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 385 ? false : true) }); - flMovingNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 99 ? false : true) }); - flPowerPresentNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 269 ? false : true) }); - flRecipeInHoldNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 145 ? false : true) }); - flRecipeInRunNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 488 ? false : true) }); - flRecipeInSetupNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 372 ? false : true) }); - flRemoteNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 33 ? false : true) }); - flSafetyNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 172 ? false : true) }); - flWaitLoadNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 410 ? false : true) }); - flWaitUnloadNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 255 ? false : true) }); - flWarningNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 450 ? false : true) }); - flWorkPiecePresentNode?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 200 ? false : true) }); - - // Set full woodworking STATE - MACHINE - OVERVIEW nodes - flCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 1 }); - flCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 2 }); - - // Set current mode STATE - MACHINE - OVERWIEW - switch (true) { - case (rndm > 0 && rndm < 100): - flCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 1 }); - flCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 4 }); - break; - case (rndm > 100 && rndm < 200): - flCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 2 }); - flCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 3 }); - break; - case (rndm > 200 && rndm < 300): - flCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 3 }); - flCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 2 }); - break; - case (rndm > 300 && rndm < 400): - flCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 4 }); - flCurrentStateNode?.setValueFromSource({ dataType: DataType.Int32, value: 1 }); - break; - case (rndm > 400 && rndm < 500): - flCurrentModeNode?.setValueFromSource({ dataType: DataType.Int32, value: 5 }); - break; - default: - break; - - } - - // Set woodworking STATE - MACHINE -OVERVIEW node - flAbsErrorTime?.setValueFromSource({ dataType: DataType.UInt64, value: rndm1 }); - flAbsLength?.setValueFromSource({ dataType: DataType.UInt64, value: rndm2 }); - flAbsMachOffTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm3 }); - flAbsMachOnTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm4 }); - flAbsPiecesInNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm5 }); - flAbsPiecesOutNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm1 }); - flAbsPowerPrsntTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm2 }); - flAbsProdTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm3 }); - flAbsProdWoutWorkpTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm4 }); - flAbsProdWaitWorkpTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm5 }); - flAbsReadyTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm1 }); - flAbsRunsAbortedNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm2 }); - flAbsRunsGoodNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm3 }); - flAbsRunsTotalNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm4 }); - flAbsStandbyTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm5 }); - flAbsWorkingTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm1 }); - flActCycleNode?.setValueFromSource({ dataType: DataType.Double, value: rndm2 }); - flAxisOverrideNode?.setValueFromSource({ dataType: DataType.UInt32, value: rndm3 }); - flFeedSpeedNode?.setValueFromSource({ dataType: DataType.Double, value: rndm4 }); - flRelErrorTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm5 }); - flRelLengthNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm1 }); - flRelMachOnTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm2 }); - flRelPiecesInNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm3 }); - flRelPiecesOutNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm4 }); - flRelPowerPrsntTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm5 }); - flRelProdTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm1 }); - flRelProdWaitWorkpTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm2 }); - flRelProdWoutWorkpTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm3 }); - flRelReadyTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm4 }); - flRelRunsAbortedNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm5 }); - flRelRunsGoodNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm1 }); - flRelRunsTotalNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm2 }); - flRelStandbyTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm3 }); - flRelWorkingTimeNode?.setValueFromSource({ dataType: DataType.UInt64, value: rndm4 }); - flSpindleOverrideNode?.setValueFromSource({ dataType: DataType.UInt32, value: rndm5 }); + // Set current mode STATE - MACHINE - OVERWIEW + switch (true) { + case rndm > 0 && rndm < 100: + flCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 1, + }); + flCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 4, + }); + break; + case rndm > 100 && rndm < 200: + flCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 2, + }); + flCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 3, + }); + break; + case rndm > 200 && rndm < 300: + flCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 3, + }); + flCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 2, + }); + break; + case rndm > 300 && rndm < 400: + flCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 4, + }); + flCurrentStateNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 1, + }); + break; + case rndm > 400 && rndm < 500: + flCurrentModeNode?.setValueFromSource({ + dataType: DataType.Int32, + value: 5, + }); + break; + default: + break; } - //Returns an randomized value between given range - function getRandomArbitrary(min: number, max: number): number { - return Math.random() * (max - min) + min; - } -} + // Set woodworking STATE - MACHINE -OVERVIEW node + flAbsErrorTime?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm1, + }); + flAbsLength?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm2, + }); + flAbsMachOffTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm3, + }); + flAbsMachOnTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm4, + }); + flAbsPiecesInNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm5, + }); + flAbsPiecesOutNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm1, + }); + flAbsPowerPrsntTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm2, + }); + flAbsProdTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm3, + }); + flAbsProdWoutWorkpTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm4, + }); + flAbsProdWaitWorkpTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm5, + }); + flAbsReadyTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm1, + }); + flAbsRunsAbortedNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm2, + }); + flAbsRunsGoodNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm3, + }); + flAbsRunsTotalNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm4, + }); + flAbsStandbyTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm5, + }); + flAbsWorkingTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm1, + }); + flActCycleNode?.setValueFromSource({ + dataType: DataType.Double, + value: rndm2, + }); + flAxisOverrideNode?.setValueFromSource({ + dataType: DataType.UInt32, + value: rndm3, + }); + flFeedSpeedNode?.setValueFromSource({ + dataType: DataType.Double, + value: rndm4, + }); + flRelErrorTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm5, + }); + flRelLengthNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm1, + }); + flRelMachOnTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm2, + }); + flRelPiecesInNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm3, + }); + flRelPiecesOutNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm4, + }); + flRelPowerPrsntTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm5, + }); + flRelProdTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm1, + }); + flRelProdWaitWorkpTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm2, + }); + flRelProdWoutWorkpTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm3, + }); + flRelReadyTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm4, + }); + flRelRunsAbortedNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm5, + }); + flRelRunsGoodNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm1, + }); + flRelRunsTotalNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm2, + }); + flRelStandbyTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm3, + }); + flRelWorkingTimeNode?.setValueFromSource({ + dataType: DataType.UInt64, + value: rndm4, + }); + flSpindleOverrideNode?.setValueFromSource({ + dataType: DataType.UInt32, + value: rndm5, + }); + } + + //Returns an randomized value between given range + function getRandomArbitrary(min: number, max: number): number { + return Math.random() * (max - min) + min; + } +}; diff --git a/src/machines/machinetool/UGGgrindingmachine.ts b/src/machines/machinetool/UGGgrindingmachine.ts index bf8b9bee..fd170507 100644 --- a/src/machines/machinetool/UGGgrindingmachine.ts +++ b/src/machines/machinetool/UGGgrindingmachine.ts @@ -12,103 +12,139 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - coerceLocalizedText, - coerceNodeId, - DataType, - UAVariable, - AddressSpace, - NodeId, - NodeIdType, - LocalizedText, -} from 'node-opcua' - -export const createUGGgrindingMachineLogic = async (addressSpace: AddressSpace): Promise => { - const idx = addressSpace?.getNamespaceIndex('https://www.grinding.ch/UA/instances/umati/') - const iaIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/IA/') - const mtoolIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/MachineTool/') - - - // Set intial state of MachineryOperationMode - const monitoringMachineToolMachineryOperationModeCurrentState = addressSpace?.findNode(`ns=${idx};s=MyMachine.Monitoring.MachineTool.MachineryOperationMode.CurrentState`) as UAVariable - monitoringMachineToolMachineryOperationModeCurrentState?.setValueFromSource({ - //value: coerceLocalizedText('Processing'), - value: new LocalizedText({text: "Processing", locale: "en-en"}), +import { + coerceLocalizedText, + coerceNodeId, + DataType, + UAVariable, + AddressSpace, + NodeId, + NodeIdType, + LocalizedText, +} from "node-opcua"; + +export const createUGGgrindingMachineLogic = async ( + addressSpace: AddressSpace, +): Promise => { + const idx = addressSpace?.getNamespaceIndex( + "https://www.grinding.ch/UA/instances/umati/", + ); + const iaIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/IA/", + ); + const mtoolIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/MachineTool/", + ); + + // Set intial state of MachineryOperationMode + const monitoringMachineToolMachineryOperationModeCurrentState = + addressSpace?.findNode( + `ns=${idx};s=MyMachine.Monitoring.MachineTool.MachineryOperationMode.CurrentState`, + ) as UAVariable; + monitoringMachineToolMachineryOperationModeCurrentState?.setValueFromSource({ + //value: coerceLocalizedText('Processing'), + value: new LocalizedText({ text: "Processing", locale: "en-en" }), + dataType: DataType.LocalizedText, + }); + + // changes CurrentState each 10000 msec from Processing to Setup + setInterval(() => { + const state = addressSpace?.findNode( + `ns=${idx};s=MyMachine.Monitoring.MachineTool.MachineryOperationMode.CurrentState`, + ) as UAVariable; + if (state?.readValue().value.value.text === "Processing") { + state?.setValueFromSource({ + value: new LocalizedText({ text: "Setup", locale: "en-en" }), dataType: DataType.LocalizedText, - }) - - // changes CurrentState each 10000 msec from Processing to Setup - setInterval(() => { - const state = addressSpace?.findNode(`ns=${idx};s=MyMachine.Monitoring.MachineTool.MachineryOperationMode.CurrentState`) as UAVariable - if (state?.readValue().value.value.text === 'Processing') { - state?.setValueFromSource({ - value: new LocalizedText({text: "Setup", locale: "en-en"}), - dataType: DataType.LocalizedText, - }) - } else { - state?.setValueFromSource({ - value: new LocalizedText({text: "Processing", locale: "en-en"}), - dataType: DataType.LocalizedText, - }) - - } - }, 10000) - - // find Stacklight SignalOn - const monitoringStacklightLamp1SignalOn = addressSpace?.findNode(`ns=${idx};s=MyMachine.Monitoring.Stacklight.Lamp1.SignalOn`) as UAVariable; - const monitoringStacklightLamp2SignalOn = addressSpace?.findNode(`ns=${idx};s=MyMachine.Monitoring.Stacklight.Lamp2.SignalOn`) as UAVariable; - const monitoringStacklightLamp3SignalOn = addressSpace?.findNode(`ns=${idx};s=MyMachine.Monitoring.Stacklight.Lamp3.SignalOn`) as UAVariable; - - // Set Stacklight Initial values - monitoringStacklightLamp1SignalOn?.setValueFromSource({ dataType: DataType.Boolean, value: false }); - monitoringStacklightLamp2SignalOn?.setValueFromSource({ dataType: DataType.Boolean, value: false }); - monitoringStacklightLamp3SignalOn?.setValueFromSource({ dataType: DataType.Boolean, value: true }); - - // Intervall to change opc ua node-values - var intervallID = setInterval(function () { - setUGGgrindingmachineValues(); - }, 2500); - - // Set the Grinding Machine values - function setUGGgrindingmachineValues() { - let rndmMin = 10; - let rndmMax = 500; - let rndm = getRandomArbitrary(rndmMin, rndmMax); - + }); + } else { + state?.setValueFromSource({ + value: new LocalizedText({ text: "Processing", locale: "en-en" }), + dataType: DataType.LocalizedText, + }); + } + }, 10000); + + // find Stacklight SignalOn + const monitoringStacklightLamp1SignalOn = addressSpace?.findNode( + `ns=${idx};s=MyMachine.Monitoring.Stacklight.Lamp1.SignalOn`, + ) as UAVariable; + const monitoringStacklightLamp2SignalOn = addressSpace?.findNode( + `ns=${idx};s=MyMachine.Monitoring.Stacklight.Lamp2.SignalOn`, + ) as UAVariable; + const monitoringStacklightLamp3SignalOn = addressSpace?.findNode( + `ns=${idx};s=MyMachine.Monitoring.Stacklight.Lamp3.SignalOn`, + ) as UAVariable; + + // Set Stacklight Initial values + monitoringStacklightLamp1SignalOn?.setValueFromSource({ + dataType: DataType.Boolean, + value: false, + }); + monitoringStacklightLamp2SignalOn?.setValueFromSource({ + dataType: DataType.Boolean, + value: false, + }); + monitoringStacklightLamp3SignalOn?.setValueFromSource({ + dataType: DataType.Boolean, + value: true, + }); + + // Intervall to change opc ua node-values + var intervallID = setInterval(function () { + setUGGgrindingmachineValues(); + }, 2500); + + // Set the Grinding Machine values + function setUGGgrindingmachineValues() { + let rndmMin = 10; + let rndmMax = 500; + let rndm = getRandomArbitrary(rndmMin, rndmMax); // Set Stacklights on and off - monitoringStacklightLamp1SignalOn?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm < 50 ? false : true)}); - monitoringStacklightLamp2SignalOn?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm > 170 ? false : true)}); - monitoringStacklightLamp3SignalOn?.setValueFromSource({ dataType: DataType.Boolean, value: (rndm > 350 ? false : true)}); + monitoringStacklightLamp1SignalOn?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm < 50 ? false : true, + }); + monitoringStacklightLamp2SignalOn?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm > 170 ? false : true, + }); + monitoringStacklightLamp3SignalOn?.setValueFromSource({ + dataType: DataType.Boolean, + value: rndm > 350 ? false : true, + }); //Returns an randomized value between given range function getRandomArbitrary(min: number, max: number): number { - return Math.random() * (max - min) + min; + return Math.random() * (max - min) + min; } // Set intial state of ActiveProgramState - const productionActiveProgramStateCurrentState = addressSpace?.findNode(`ns=${idx};s=MyMachine.Production.ActiveProgram.State.CurrentState`) as UAVariable + const productionActiveProgramStateCurrentState = addressSpace?.findNode( + `ns=${idx};s=MyMachine.Production.ActiveProgram.State.CurrentState`, + ) as UAVariable; productionActiveProgramStateCurrentState?.setValueFromSource({ - value: new LocalizedText({text: "Running", locale: "en-en"}), - dataType: DataType.LocalizedText, - }) + value: new LocalizedText({ text: "Running", locale: "en-en" }), + dataType: DataType.LocalizedText, + }); // changes CurrentState each 10000 msec from Running to Ended setInterval(() => { - const state = addressSpace?.findNode(`ns=${idx};s=MyMachine.Production.ActiveProgram.State.CurrentState`) as UAVariable - if (state?.readValue().value.value.text === 'Running') { - state?.setValueFromSource({ - value: new LocalizedText({text: "Ended", locale: "en-en"}), - dataType: DataType.LocalizedText, - }) - } else { - state?.setValueFromSource({ - value: new LocalizedText({text: "Setup", locale: "en-en"}), - dataType: DataType.LocalizedText, - }) - - } - }, 10000) - -} -} + const state = addressSpace?.findNode( + `ns=${idx};s=MyMachine.Production.ActiveProgram.State.CurrentState`, + ) as UAVariable; + if (state?.readValue().value.value.text === "Running") { + state?.setValueFromSource({ + value: new LocalizedText({ text: "Ended", locale: "en-en" }), + dataType: DataType.LocalizedText, + }); + } else { + state?.setValueFromSource({ + value: new LocalizedText({ text: "Setup", locale: "en-en" }), + dataType: DataType.LocalizedText, + }); + } + }, 10000); + } +}; diff --git a/src/machines/machinetool/brownfieldmachinetool.ts b/src/machines/machinetool/brownfieldmachinetool.ts index 0e60ec70..c239cae8 100644 --- a/src/machines/machinetool/brownfieldmachinetool.ts +++ b/src/machines/machinetool/brownfieldmachinetool.ts @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, -} from 'node-opcua' +import { AddressSpace } from "node-opcua"; -export const createbrownfieldMTLogic = async (addressSpace: AddressSpace): Promise => { - -} \ No newline at end of file +export const createbrownfieldMTLogic = async ( + addressSpace: AddressSpace, +): Promise => {}; diff --git a/src/machines/machinetool/machinetool-example.ts b/src/machines/machinetool/machinetool-example.ts index ea0eea9d..73cf85a0 100644 --- a/src/machines/machinetool/machinetool-example.ts +++ b/src/machines/machinetool/machinetool-example.ts @@ -12,120 +12,137 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - coerceLocalizedText, - coerceNodeId, - DataType, - UAVariable, - AddressSpace, - NodeId, - NodeIdType, -} from 'node-opcua' -import { red } from '../../utils/log' +import { + coerceLocalizedText, + coerceNodeId, + DataType, + UAVariable, + AddressSpace, + NodeId, + NodeIdType, +} from "node-opcua"; +import { red } from "../../utils/log"; -export const createMachineToolExampleLogic = async (addressSpace: AddressSpace): Promise => { +export const createMachineToolExampleLogic = async ( + addressSpace: AddressSpace, +): Promise => { + const idx = addressSpace?.getNamespaceIndex( + "http://yourorganisation.org/MachineTool-Example/", + ); + const iaIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/IA/", + ); + const mtoolIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/MachineTool/", + ); + const activeProgramName = addressSpace?.findNode( + `ns=${idx};i=6026`, + ) as UAVariable; + if (activeProgramName !== null) { + activeProgramName?.setValueFromSource({ + value: "Program_2", + dataType: DataType.String, + }); + } else { + red("activeProgramName does not exist!"); + } -const idx = addressSpace?.getNamespaceIndex('http://yourorganisation.org/MachineTool-Example/') -const iaIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/IA/') -const mtoolIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/MachineTool/') + const activeProgramNumberInList = addressSpace?.findNode( + `ns=${idx};i=6027`, + ) as UAVariable; + if (activeProgramNumberInList !== null) { + activeProgramNumberInList?.setValueFromSource({ + value: 1, + dataType: DataType.UInt16, + }); + } else { + red("activeProgramNumberInList does not exist!"); + } - const activeProgramName = addressSpace?.findNode(`ns=${idx};i=6026`) as UAVariable - if (activeProgramName !== null) { - activeProgramName?.setValueFromSource({ - value: 'Program_2', - dataType: DataType.String, - }) - } else { - red("activeProgramName does not exist!") - } + const productionActiveProgramStateCurrentState = addressSpace?.findNode( + `ns=${idx};i=6028`, + ) as UAVariable; + if (productionActiveProgramStateCurrentState !== null) { + productionActiveProgramStateCurrentState?.setValueFromSource({ + value: coerceLocalizedText("Running"), + dataType: DataType.LocalizedText, + }); + } else { + red("productionActiveProgramStateCurrentState does not exist!"); + } - - const activeProgramNumberInList = addressSpace?.findNode(`ns=${idx};i=6027`) as UAVariable - if (activeProgramNumberInList !== null) { - activeProgramNumberInList?.setValueFromSource({ - value: 1, - dataType: DataType.UInt16, - }) + // changes CurrentState each 10000 msec from Running to Ended + setInterval(() => { + const state = addressSpace?.findNode(`ns=${idx};i=6028`) as UAVariable; + const stateNumber = addressSpace?.findNode( + `ns=${idx};i=6029`, + ) as UAVariable; + if (state?.readValue().value.value.text === "Running") { + state?.setValueFromSource({ + value: coerceLocalizedText("Ended"), + dataType: DataType.LocalizedText, + }); + stateNumber.setValueFromSource({ + value: coerceNodeId(2), + dataType: DataType.NodeId, + }); } else { - red("activeProgramNumberInList does not exist!") + state?.setValueFromSource({ + value: coerceLocalizedText("Running"), + dataType: DataType.LocalizedText, + }); + stateNumber.setValueFromSource({ + value: coerceNodeId(1), + dataType: DataType.NodeId, + }); } + }, 10000); - - const productionActiveProgramStateCurrentState = addressSpace?.findNode(`ns=${idx};i=6028`) as UAVariable - if (productionActiveProgramStateCurrentState !== null) { - productionActiveProgramStateCurrentState?.setValueFromSource({ - value: coerceLocalizedText('Running'), - dataType: DataType.LocalizedText, - }) - } else { - red("productionActiveProgramStateCurrentState does not exist!") + // increments the value of FeedOverride by 5 each sec + let override = 50; + setInterval(() => { + override += 5; + if (override > 120) { + override = 50; } - - - // changes CurrentState each 10000 msec from Running to Ended - setInterval(() => { - const state = addressSpace?.findNode(`ns=${idx};i=6028`) as UAVariable - const stateNumber = addressSpace?.findNode(`ns=${idx};i=6029`) as UAVariable - if (state?.readValue().value.value.text === 'Running') { - state?.setValueFromSource({ - value: coerceLocalizedText('Ended'), - dataType: DataType.LocalizedText, - }) - stateNumber.setValueFromSource({ - value: coerceNodeId(2), - dataType: DataType.NodeId, - }) - } else { - state?.setValueFromSource({ - value: coerceLocalizedText('Running'), - dataType: DataType.LocalizedText, - }) - stateNumber.setValueFromSource({ - value: coerceNodeId(1), - dataType: DataType.NodeId, - }) - } - }, 10000) - - // increments the value of FeedOverride by 5 each sec - let override = 50 - setInterval(() => { - override += 5 - if (override > 120) { - override = 50 - } - const feedOverride = addressSpace?.findNode(`ns=${idx};i=6017`) as UAVariable - feedOverride.setValueFromSource({ - value: override, - dataType: DataType.Double, - }) - }, 1000) + const feedOverride = addressSpace?.findNode( + `ns=${idx};i=6017`, + ) as UAVariable; + feedOverride.setValueFromSource({ + value: override, + dataType: DataType.Double, + }); + }, 1000); - const spindleOverride = addressSpace?.findNode(`ns=${idx};i=6070`) as UAVariable - spindleOverride?.setValueFromSource({ - value: 100, - dataType: DataType.Double, - }) + const spindleOverride = addressSpace?.findNode( + `ns=${idx};i=6070`, + ) as UAVariable; + spindleOverride?.setValueFromSource({ + value: 100, + dataType: DataType.Double, + }); - // writing ExtensionObject (Range) - const spindleEURange = addressSpace?.constructExtensionObject( - new NodeId(NodeIdType.NUMERIC, 884, 0), - { - low: 60.0, - high: 100.0, - } - ) - const spindleOverrideRange = addressSpace?.findNode(`ns=${idx};i=6072`) as UAVariable - spindleOverrideRange?.setValueFromSource({ - value: spindleEURange, - dataType: DataType.ExtensionObject, - }) + // writing ExtensionObject (Range) + const spindleEURange = addressSpace?.constructExtensionObject( + new NodeId(NodeIdType.NUMERIC, 884, 0), + { + low: 60.0, + high: 100.0, + }, + ); + const spindleOverrideRange = addressSpace?.findNode( + `ns=${idx};i=6072`, + ) as UAVariable; + spindleOverrideRange?.setValueFromSource({ + value: spindleEURange, + dataType: DataType.ExtensionObject, + }); - // writing a enum - const channel1 = addressSpace?.findNode(`ns=${idx};i=6061`) as UAVariable - channel1.setValueFromSource({ - value: 1, - dataType: DataType.Int32 - }) -} + // writing a enum + const channel1 = addressSpace?.findNode(`ns=${idx};i=6061`) as UAVariable; + channel1.setValueFromSource({ + value: 1, + dataType: DataType.Int32, + }); +}; diff --git a/src/machines/machinetool/showcasemachinetool.ts b/src/machines/machinetool/showcasemachinetool.ts index 72ea96cf..b5228f74 100644 --- a/src/machines/machinetool/showcasemachinetool.ts +++ b/src/machines/machinetool/showcasemachinetool.ts @@ -12,128 +12,151 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - coerceLocalizedText, - coerceNodeId, - DataType, - UAVariable, - AddressSpace, - NodeId, - NodeIdType, -} from 'node-opcua' +import { + coerceLocalizedText, + coerceNodeId, + DataType, + UAVariable, + AddressSpace, + NodeId, + NodeIdType, +} from "node-opcua"; -export const createShowCaseMachineToolLogic = async (addressSpace: AddressSpace): Promise => { +export const createShowCaseMachineToolLogic = async ( + addressSpace: AddressSpace, +): Promise => { + const idx = addressSpace?.getNamespaceIndex( + "http://example.com/ShowcaseMachineTool/", + ); + const iaIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/IA/", + ); + const mtoolIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/MachineTool/", + ); - const idx = addressSpace?.getNamespaceIndex('http://example.com/ShowcaseMachineTool/') - const iaIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/IA/') - const mtoolIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/MachineTool/') + const activeProgramName = addressSpace?.findNode( + `ns=${idx};i=55186`, + ) as UAVariable; + activeProgramName?.setValueFromSource({ + value: "Program_1", + dataType: DataType.String, + }); - const activeProgramName = addressSpace?.findNode(`ns=${idx};i=55186`) as UAVariable - activeProgramName?.setValueFromSource({ - value: 'Program_1', - dataType: DataType.String, - }) + const activeProgramNumberInList = addressSpace?.findNode( + `ns=${idx};i=55185`, + ) as UAVariable; + activeProgramNumberInList?.setValueFromSource({ + value: 1, + dataType: DataType.UInt16, + }); - const activeProgramNumberInList = addressSpace?.findNode(`ns=${idx};i=55185`) as UAVariable - activeProgramNumberInList?.setValueFromSource({ - value: 1, - dataType: DataType.UInt16, - }) + const productionActiveProgramStateCurrentState = addressSpace?.findNode( + `ns=${idx};i=55188`, + ) as UAVariable; + productionActiveProgramStateCurrentState?.setValueFromSource({ + value: coerceLocalizedText("Running"), + dataType: DataType.LocalizedText, + }); - const productionActiveProgramStateCurrentState = addressSpace?.findNode(`ns=${idx};i=55188`) as UAVariable - productionActiveProgramStateCurrentState?.setValueFromSource({ - value: coerceLocalizedText('Running'), + // changes CurrentState each 10000 msec from Running to Ended + setInterval(() => { + const state = addressSpace?.findNode(`ns=${idx};i=55188`) as UAVariable; + const stateNumber = addressSpace?.findNode( + `ns=${idx};i=55190`, + ) as UAVariable; + if (state?.readValue().value.value.text === "Running") { + state?.setValueFromSource({ + value: coerceLocalizedText("Ended"), dataType: DataType.LocalizedText, - }) - - // changes CurrentState each 10000 msec from Running to Ended - setInterval(() => { - const state = addressSpace?.findNode(`ns=${idx};i=55188`) as UAVariable - const stateNumber = addressSpace?.findNode(`ns=${idx};i=55190`) as UAVariable - if (state?.readValue().value.value.text === 'Running') { - state?.setValueFromSource({ - value: coerceLocalizedText('Ended'), - dataType: DataType.LocalizedText, - }) - stateNumber.setValueFromSource({ - value: coerceNodeId(2), - dataType: DataType.NodeId, - }) - } else { - state?.setValueFromSource({ - value: coerceLocalizedText('Running'), - dataType: DataType.LocalizedText, - }) - stateNumber.setValueFromSource({ - value: coerceNodeId(1), - dataType: DataType.NodeId, - }) - } - }, 10000) + }); + stateNumber.setValueFromSource({ + value: coerceNodeId(2), + dataType: DataType.NodeId, + }); + } else { + state?.setValueFromSource({ + value: coerceLocalizedText("Running"), + dataType: DataType.LocalizedText, + }); + stateNumber.setValueFromSource({ + value: coerceNodeId(1), + dataType: DataType.NodeId, + }); + } + }, 10000); - // changes MachineryItemState each 10000 msec from Executing to NotExecuting - setInterval(() => { - const state = addressSpace?.findNode(`ns=${idx};i=6011`) as UAVariable - const stateNumber = addressSpace?.findNode(`ns=${idx};i=6012`) as UAVariable - if (state?.readValue().value.value.text === 'Executing') { - state?.setValueFromSource({ - value: coerceLocalizedText('NotExecuting'), - dataType: DataType.LocalizedText, - }) - stateNumber.setValueFromSource({ - value: coerceNodeId(2), - dataType: DataType.NodeId, - }) - } else { - state?.setValueFromSource({ - value: coerceLocalizedText('Executing'), - dataType: DataType.LocalizedText, - }) - stateNumber.setValueFromSource({ - value: coerceNodeId(1), - dataType: DataType.NodeId, - }) - } - }, 10000) + // changes MachineryItemState each 10000 msec from Executing to NotExecuting + setInterval(() => { + const state = addressSpace?.findNode(`ns=${idx};i=6011`) as UAVariable; + const stateNumber = addressSpace?.findNode( + `ns=${idx};i=6012`, + ) as UAVariable; + if (state?.readValue().value.value.text === "Executing") { + state?.setValueFromSource({ + value: coerceLocalizedText("NotExecuting"), + dataType: DataType.LocalizedText, + }); + stateNumber.setValueFromSource({ + value: coerceNodeId(2), + dataType: DataType.NodeId, + }); + } else { + state?.setValueFromSource({ + value: coerceLocalizedText("Executing"), + dataType: DataType.LocalizedText, + }); + stateNumber.setValueFromSource({ + value: coerceNodeId(1), + dataType: DataType.NodeId, + }); + } + }, 10000); - // increments the value of FeedOverride by 5 each sec - let override = 50 - setInterval(() => { - override += 5 - if (override > 120) { - override = 50 - } - const feedOverride = addressSpace?.findNode(`ns=${idx};i=55229`) as UAVariable - feedOverride.setValueFromSource({ - value: override, - dataType: DataType.Double, - }) - }, 1000) + // increments the value of FeedOverride by 5 each sec + let override = 50; + setInterval(() => { + override += 5; + if (override > 120) { + override = 50; + } + const feedOverride = addressSpace?.findNode( + `ns=${idx};i=55229`, + ) as UAVariable; + feedOverride.setValueFromSource({ + value: override, + dataType: DataType.Double, + }); + }, 1000); - const spindleOverride = addressSpace?.findNode(`ns=${idx};i=55238`) as UAVariable - spindleOverride?.setValueFromSource({ - value: 100, - dataType: DataType.Double, - }) + const spindleOverride = addressSpace?.findNode( + `ns=${idx};i=55238`, + ) as UAVariable; + spindleOverride?.setValueFromSource({ + value: 100, + dataType: DataType.Double, + }); - // writing ExtensionObject (Range) - const spindleEURange = addressSpace?.constructExtensionObject( - new NodeId(NodeIdType.NUMERIC, 884, 0), - { - low: 60.0, - high: 100.0, - } - ) - const spindleOverrideRange = addressSpace?.findNode(`ns=${idx};i=55240`) as UAVariable - spindleOverrideRange?.setValueFromSource({ - value: spindleEURange, - dataType: DataType.ExtensionObject, - }) + // writing ExtensionObject (Range) + const spindleEURange = addressSpace?.constructExtensionObject( + new NodeId(NodeIdType.NUMERIC, 884, 0), + { + low: 60.0, + high: 100.0, + }, + ); + const spindleOverrideRange = addressSpace?.findNode( + `ns=${idx};i=55240`, + ) as UAVariable; + spindleOverrideRange?.setValueFromSource({ + value: spindleEURange, + dataType: DataType.ExtensionObject, + }); - // writing a enum - const channel1 = addressSpace?.findNode(`ns=${idx};i=55233`) as UAVariable - channel1.setValueFromSource({ - value: 1, - dataType: DataType.Int32 - }) -} + // writing a enum + const channel1 = addressSpace?.findNode(`ns=${idx};i=55233`) as UAVariable; + channel1.setValueFromSource({ + value: 1, + dataType: DataType.Int32, + }); +}; diff --git a/src/machines/motiondevicesystem/motiondevicesystem.ts b/src/machines/motiondevicesystem/motiondevicesystem.ts index 5f58ae9b..cb905756 100644 --- a/src/machines/motiondevicesystem/motiondevicesystem.ts +++ b/src/machines/motiondevicesystem/motiondevicesystem.ts @@ -12,17 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - - DataType, - UAVariable, - AddressSpace, - -} from 'node-opcua' +import { DataType, UAVariable, AddressSpace } from "node-opcua"; -export const createMotionDeviceSystemLogic = async (addressSpace: AddressSpace): Promise => { - - /* +export const createMotionDeviceSystemLogic = async ( + addressSpace: AddressSpace, +): Promise => { + /* machinelogic here: bind opc ua variables to a getter/setter functions or to an js variable -> https://node-opcua.github.io/api_doc/2.32.0/interfaces/node_opcua.uavariable.html#bindvariable @@ -55,53 +50,51 @@ export const createMotionDeviceSystemLogic = async (addressSpace: AddressSpace): timestamped_set: myVariableSetter }, true); */ - const mdsidx = addressSpace?.getNamespaceIndex('http://vdma.org/OPCRoboticsTestServer/') - - let generateNumber = function() { - - var value = 10 + 10 * Math.random(); - return value.toFixed(2); - - }; + const mdsidx = addressSpace?.getNamespaceIndex( + "http://vdma.org/OPCRoboticsTestServer/", + ); - const node1 = addressSpace?.findNode(`ns=${mdsidx};i=6020`) as UAVariable - const node2= addressSpace?.findNode(`ns=${mdsidx};i=6024`) as UAVariable - const node3 = addressSpace?.findNode(`ns=${mdsidx};i=6031`) as UAVariable - const node4 = addressSpace?.findNode(`ns=${mdsidx};i=6027`) as UAVariable - const node5 = addressSpace?.findNode(`ns=${mdsidx};i=6033`) as UAVariable - const node6 = addressSpace?.findNode(`ns=${mdsidx};i=6054`) as UAVariable - const node7 = addressSpace?.findNode(`ns=${mdsidx};i=6022`) as UAVariable - // changes CurrentState each 1000 msec from Running to Stopped - setInterval(() => { - - node1?.setValueFromSource({ - value: generateNumber(), - dataType: DataType.Double, - }) - node2?.setValueFromSource({ - value: generateNumber(), - dataType: DataType.Double, - }) - node3?.setValueFromSource({ - value: generateNumber(), - dataType: DataType.Double, - }) - node4?.setValueFromSource({ - value: generateNumber(), - dataType: DataType.Double, - }) - node5?.setValueFromSource({ - value: generateNumber(), - dataType: DataType.Double, - }) - node6?.setValueFromSource({ - value: generateNumber(), - dataType: DataType.Double, - }) - node7?.setValueFromSource({ - value: generateNumber(), - dataType: DataType.Double, - }) - }, 1000) + let generateNumber = function () { + var value = 10 + 10 * Math.random(); + return value.toFixed(2); + }; -} \ No newline at end of file + const node1 = addressSpace?.findNode(`ns=${mdsidx};i=6020`) as UAVariable; + const node2 = addressSpace?.findNode(`ns=${mdsidx};i=6024`) as UAVariable; + const node3 = addressSpace?.findNode(`ns=${mdsidx};i=6031`) as UAVariable; + const node4 = addressSpace?.findNode(`ns=${mdsidx};i=6027`) as UAVariable; + const node5 = addressSpace?.findNode(`ns=${mdsidx};i=6033`) as UAVariable; + const node6 = addressSpace?.findNode(`ns=${mdsidx};i=6054`) as UAVariable; + const node7 = addressSpace?.findNode(`ns=${mdsidx};i=6022`) as UAVariable; + // changes CurrentState each 1000 msec from Running to Stopped + setInterval(() => { + node1?.setValueFromSource({ + value: generateNumber(), + dataType: DataType.Double, + }); + node2?.setValueFromSource({ + value: generateNumber(), + dataType: DataType.Double, + }); + node3?.setValueFromSource({ + value: generateNumber(), + dataType: DataType.Double, + }); + node4?.setValueFromSource({ + value: generateNumber(), + dataType: DataType.Double, + }); + node5?.setValueFromSource({ + value: generateNumber(), + dataType: DataType.Double, + }); + node6?.setValueFromSource({ + value: generateNumber(), + dataType: DataType.Double, + }); + node7?.setValueFromSource({ + value: generateNumber(), + dataType: DataType.Double, + }); + }, 1000); +}; diff --git a/src/machines/mymachine/datasource.ts b/src/machines/mymachine/datasource.ts index 6c1d8cba..e7278c9e 100644 --- a/src/machines/mymachine/datasource.ts +++ b/src/machines/mymachine/datasource.ts @@ -12,146 +12,192 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, - DataType, - DataValue, - EUInformation, - LocalizedText, - makeEUInformation, - NodeId, - NodeIdType, - standardUnits, - StatusCodes, - UAVariable, - Variant +import { + AddressSpace, + DataType, + DataValue, + EUInformation, + LocalizedText, + makeEUInformation, + NodeId, + NodeIdType, + standardUnits, + StatusCodes, + UAVariable, + Variant, } from "node-opcua"; -const engineeringUnitMap = new Map() -Object.entries(standardUnits).forEach((value: [string, EUInformation], index: number, array: [string, EUInformation][]) => { - const k = value[0] - const v = value[1] - engineeringUnitMap.set(k, v) // "percent", EUInformation - engineeringUnitMap.set(`${v.displayName.text}`, v) // "%", EUInformation -}) +const engineeringUnitMap = new Map(); +Object.entries(standardUnits).forEach( + ( + value: [string, EUInformation], + index: number, + array: [string, EUInformation][], + ) => { + const k = value[0]; + const v = value[1]; + engineeringUnitMap.set(k, v); // "percent", EUInformation + engineeringUnitMap.set(`${v.displayName.text}`, v); // "%", EUInformation + }, +); -const degC = engineeringUnitMap.get("°C")! -const pressure = engineeringUnitMap.get("mbar")! +const degC = engineeringUnitMap.get("°C")!; +const pressure = engineeringUnitMap.get("mbar")!; function delay(time: number) { - return new Promise((resolve) => setTimeout(resolve, time)); - } + return new Promise((resolve) => setTimeout(resolve, time)); +} -const Data = new Map() +const Data = new Map(); export function initializeFakeDataSource(addressSpace: AddressSpace) { - const idx = addressSpace.getNamespaceIndex("http://mynewmachinenamespace/UA") - // Pressure - Data.set(`ns=${idx};i=1018`, new DataValue({ - value: new Variant({ - value: 1013, - dataType: DataType.Double - }), - statusCode: StatusCodes.Good - })) - setInterval(() => { - Data.set(`ns=${idx};i=1018`, new DataValue({ - value: new Variant({ - value: (Math.random() * 1000), - dataType: DataType.Double - }), - statusCode: StatusCodes.Good - })) - }, 2000) - Data.set(`ns=${idx};i=1020`, new DataValue({ + const idx = addressSpace.getNamespaceIndex("http://mynewmachinenamespace/UA"); + // Pressure + Data.set( + `ns=${idx};i=1018`, + new DataValue({ + value: new Variant({ + value: 1013, + dataType: DataType.Double, + }), + statusCode: StatusCodes.Good, + }), + ); + setInterval(() => { + Data.set( + `ns=${idx};i=1018`, + new DataValue({ value: new Variant({ - value: addressSpace.constructExtensionObject(new NodeId(NodeIdType.NUMERIC, 884, 0), { - high: 2000, - low: 500 - }), - dataType: DataType.ExtensionObject + value: Math.random() * 1000, + dataType: DataType.Double, }), - statusCode: StatusCodes.Good - })) - Data.set(`ns=${idx};i=1019`, new DataValue({ - value: new Variant({ - value: addressSpace.constructExtensionObject(new NodeId(NodeIdType.NUMERIC, 887, 0), { - namespaceUri: pressure.namespaceUri, - unitId: pressure.unitId, - displayName: pressure.displayName, - description: pressure.description - }), - dataType: DataType.ExtensionObject - }), - statusCode: StatusCodes.Good - })) + statusCode: StatusCodes.Good, + }), + ); + }, 2000); + Data.set( + `ns=${idx};i=1020`, + new DataValue({ + value: new Variant({ + value: addressSpace.constructExtensionObject( + new NodeId(NodeIdType.NUMERIC, 884, 0), + { + high: 2000, + low: 500, + }, + ), + dataType: DataType.ExtensionObject, + }), + statusCode: StatusCodes.Good, + }), + ); + Data.set( + `ns=${idx};i=1019`, + new DataValue({ + value: new Variant({ + value: addressSpace.constructExtensionObject( + new NodeId(NodeIdType.NUMERIC, 887, 0), + { + namespaceUri: pressure.namespaceUri, + unitId: pressure.unitId, + displayName: pressure.displayName, + description: pressure.description, + }, + ), + dataType: DataType.ExtensionObject, + }), + statusCode: StatusCodes.Good, + }), + ); - // Temperature - Data.set(`ns=${idx};i=1013`, new DataValue({ + // Temperature + Data.set( + `ns=${idx};i=1013`, + new DataValue({ + value: new Variant({ + value: 21, + dataType: DataType.Double, + }), + statusCode: StatusCodes.Good, + }), + ); + setInterval(() => { + Data.set( + `ns=${idx};i=1013`, + new DataValue({ value: new Variant({ - value: 21, - dataType: DataType.Double + value: Math.random() * 100 + 50, + dataType: DataType.Double, }), - statusCode: StatusCodes.Good - })) - setInterval(() => { - Data.set(`ns=${idx};i=1013`, new DataValue({ - value: new Variant({ - value: (Math.random() * 100) + 50, - dataType: DataType.Double - }), - statusCode: StatusCodes.Good - })) - }, 5000) - Data.set(`ns=${idx};i=1015`, new DataValue({ - value: new Variant({ - value: addressSpace.constructExtensionObject(new NodeId(NodeIdType.NUMERIC, 884, 0), { - high: 60, - low: -20 - }), - dataType: DataType.ExtensionObject - }), - statusCode: StatusCodes.Good - })) - Data.set(`ns=${idx};i=1014`, new DataValue({ - value: new Variant({ - value: addressSpace.constructExtensionObject( - new NodeId(NodeIdType.NUMERIC, 887, 0), - { - namespaceUri: degC.namespaceUri, - unitId: degC.unitId, - displayName: degC.displayName, - description: degC.description - } - ), - dataType: DataType.ExtensionObject - }), - statusCode: StatusCodes.Good - })) + statusCode: StatusCodes.Good, + }), + ); + }, 5000); + Data.set( + `ns=${idx};i=1015`, + new DataValue({ + value: new Variant({ + value: addressSpace.constructExtensionObject( + new NodeId(NodeIdType.NUMERIC, 884, 0), + { + high: 60, + low: -20, + }, + ), + dataType: DataType.ExtensionObject, + }), + statusCode: StatusCodes.Good, + }), + ); + Data.set( + `ns=${idx};i=1014`, + new DataValue({ + value: new Variant({ + value: addressSpace.constructExtensionObject( + new NodeId(NodeIdType.NUMERIC, 887, 0), + { + namespaceUri: degC.namespaceUri, + unitId: degC.unitId, + displayName: degC.displayName, + description: degC.description, + }, + ), + dataType: DataType.ExtensionObject, + }), + statusCode: StatusCodes.Good, + }), + ); } async function getDataValue(nodeid: string): Promise { - await delay(500) // fake api call - return Data.get(nodeid) || new DataValue({ - value: new Variant({}), - statusCode: StatusCodes.BadInternalError + await delay(500); // fake api call + return ( + Data.get(nodeid) || + new DataValue({ + value: new Variant({}), + statusCode: StatusCodes.BadInternalError, }) + ); } -export const variableGetter = function( - this: UAVariable, - callback: (err: Error | null, dataValue?: DataValue) => void): void { - getDataValue(this.nodeId.toString()) - .then((value: DataValue) => { - callback(null, value) - }) - .catch((reason: any) => { - callback(null, new DataValue({ - value: new Variant({ - value: null, - dataType: this.dataTypeObj.displayName[0].text?.toString() - }), - statusCode: StatusCodes.BadInternalError, - })) - }) - } \ No newline at end of file +export const variableGetter = function ( + this: UAVariable, + callback: (err: Error | null, dataValue?: DataValue) => void, +): void { + getDataValue(this.nodeId.toString()) + .then((value: DataValue) => { + callback(null, value); + }) + .catch((reason: any) => { + callback( + null, + new DataValue({ + value: new Variant({ + value: null, + dataType: this.dataTypeObj.displayName[0].text?.toString(), + }), + statusCode: StatusCodes.BadInternalError, + }), + ); + }); +}; diff --git a/src/machines/mymachine/mymachine.ts b/src/machines/mymachine/mymachine.ts index 6f8ad74b..7431082c 100644 --- a/src/machines/mymachine/mymachine.ts +++ b/src/machines/mymachine/mymachine.ts @@ -12,201 +12,260 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - coerceLocalizedText, - DataType, - UAVariable, - UAObject, - AddressSpace, - UAObjectType, - setNamespaceMetaData, -} from 'node-opcua' -import { ServerRolePermissionGroup } from '../../permissiongroups' -import { initializeFakeDataSource, variableGetter } from './datasource' +import { + coerceLocalizedText, + DataType, + UAVariable, + UAObject, + AddressSpace, + UAObjectType, + setNamespaceMetaData, +} from "node-opcua"; +import { ServerRolePermissionGroup } from "../../permissiongroups"; +import { initializeFakeDataSource, variableGetter } from "./datasource"; -export const createMyMachineLogic = async (addressSpace: AddressSpace): Promise => { - // Add a machine manually: - const machineryIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/Machinery/') - const machinesFolder = addressSpace?.findNode(`ns=${machineryIdx};i=1001`) as UAObject - const namespace = addressSpace?.registerNamespace('http://mynewmachinenamespace/UA') - namespace.setDefaultRolePermissions(ServerRolePermissionGroup.DEFAULT) - setNamespaceMetaData(namespace) - const myMachine = namespace?.addObject({ - browseName: 'MyMachine', - nodeId: `ns=${namespace.index};s=MyMachine`, - organizedBy: machinesFolder, - }) - const machineryIdentificationType = addressSpace?.findNode(`ns=${machineryIdx};i=1012`) as UAObjectType - const myMachineIdentification = machineryIdentificationType?.instantiate({ - browseName: { - name: 'Identification', - namespaceIndex: machineryIdx - }, - namespace: namespace, - optionals: ['Model'], // array of string - }) - myMachineIdentification.addReference({ - referenceType: 'HasAddIn', - nodeId: myMachine, - isForward: false, - }) - const manufacturer = myMachineIdentification?.getChildByName('Manufacturer') as UAVariable - manufacturer?.setValueFromSource({ - dataType: DataType.LocalizedText, - value: coerceLocalizedText('Andreas Heine'), - }) - const model = myMachineIdentification?.getChildByName('Model') as UAVariable - model?.setValueFromSource({ - dataType: DataType.LocalizedText, - value: coerceLocalizedText('Model-123'), - }) - const uri = myMachineIdentification?.getChildByName('ProductInstanceUri') as UAVariable - uri?.setValueFromSource({ - dataType: DataType.String, - value: 'ProductInstanceUri-123', - }) - const serial = myMachineIdentification?.getChildByName('SerialNumber') as UAVariable - serial?.setValueFromSource({ - dataType: DataType.String, - value: 'SerialNumber-123', - }) - const machineComponentsType = addressSpace?.findNode(`ns=${machineryIdx};i=1006`) as UAObjectType - const myMachineComponents = machineComponentsType?.instantiate({ - browseName: { - name: 'Components', - namespaceIndex: machineryIdx - }, - namespace: namespace, - }) - myMachineComponents.addReference({ - referenceType: 'HasAddIn', - nodeId: myMachine, - isForward: false, - }) +export const createMyMachineLogic = async ( + addressSpace: AddressSpace, +): Promise => { + // Add a machine manually: + const machineryIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/Machinery/", + ); + const machinesFolder = addressSpace?.findNode( + `ns=${machineryIdx};i=1001`, + ) as UAObject; + const namespace = addressSpace?.registerNamespace( + "http://mynewmachinenamespace/UA", + ); + namespace.setDefaultRolePermissions(ServerRolePermissionGroup.DEFAULT); + setNamespaceMetaData(namespace); + const myMachine = namespace?.addObject({ + browseName: "MyMachine", + nodeId: `ns=${namespace.index};s=MyMachine`, + organizedBy: machinesFolder, + }); + const machineryIdentificationType = addressSpace?.findNode( + `ns=${machineryIdx};i=1012`, + ) as UAObjectType; + const myMachineIdentification = machineryIdentificationType?.instantiate({ + browseName: { + name: "Identification", + namespaceIndex: machineryIdx, + }, + namespace: namespace, + optionals: ["Model"], // array of string + }); + myMachineIdentification.addReference({ + referenceType: "HasAddIn", + nodeId: myMachine, + isForward: false, + }); + const manufacturer = myMachineIdentification?.getChildByName( + "Manufacturer", + ) as UAVariable; + manufacturer?.setValueFromSource({ + dataType: DataType.LocalizedText, + value: coerceLocalizedText("Andreas Heine"), + }); + const model = myMachineIdentification?.getChildByName("Model") as UAVariable; + model?.setValueFromSource({ + dataType: DataType.LocalizedText, + value: coerceLocalizedText("Model-123"), + }); + const uri = myMachineIdentification?.getChildByName( + "ProductInstanceUri", + ) as UAVariable; + uri?.setValueFromSource({ + dataType: DataType.String, + value: "ProductInstanceUri-123", + }); + const serial = myMachineIdentification?.getChildByName( + "SerialNumber", + ) as UAVariable; + serial?.setValueFromSource({ + dataType: DataType.String, + value: "SerialNumber-123", + }); + const machineComponentsType = addressSpace?.findNode( + `ns=${machineryIdx};i=1006`, + ) as UAObjectType; + const myMachineComponents = machineComponentsType?.instantiate({ + browseName: { + name: "Components", + namespaceIndex: machineryIdx, + }, + namespace: namespace, + }); + myMachineComponents.addReference({ + referenceType: "HasAddIn", + nodeId: myMachine, + isForward: false, + }); - // ItemState + OperationMode + // ItemState + OperationMode - const machineryBuildingBlocks = namespace.addObject({ - browseName: {name : "MachineryBuildingBlocks", namespaceIndex: machineryIdx}, - typeDefinition: "FolderType", - componentOf: myMachine - }); + const machineryBuildingBlocks = namespace.addObject({ + browseName: { + name: "MachineryBuildingBlocks", + namespaceIndex: machineryIdx, + }, + typeDefinition: "FolderType", + componentOf: myMachine, + }); - const myItemState = (addressSpace!.findNode(`ns=${machineryIdx};i=1002`) as UAObjectType).instantiate({ - browseName: { - name: 'MachineryItemState', - namespaceIndex: machineryIdx - }, - namespace: namespace, - }) - myItemState.addReference({ - referenceType: 'HasAddIn', - nodeId: machineryBuildingBlocks, - isForward: false, - }) - const myItemStateCurrentState = myItemState.getChildByName("CurrentState") as UAVariable - myItemStateCurrentState?.setValueFromSource({ - dataType: DataType.LocalizedText, - value: coerceLocalizedText('Executing'), - }) + const myItemState = ( + addressSpace!.findNode(`ns=${machineryIdx};i=1002`) as UAObjectType + ).instantiate({ + browseName: { + name: "MachineryItemState", + namespaceIndex: machineryIdx, + }, + namespace: namespace, + }); + myItemState.addReference({ + referenceType: "HasAddIn", + nodeId: machineryBuildingBlocks, + isForward: false, + }); + const myItemStateCurrentState = myItemState.getChildByName( + "CurrentState", + ) as UAVariable; + myItemStateCurrentState?.setValueFromSource({ + dataType: DataType.LocalizedText, + value: coerceLocalizedText("Executing"), + }); - const myOperationMode = (addressSpace!.findNode(`ns=${machineryIdx};i=1008`) as UAObjectType).instantiate({ - browseName: { - name: 'MachineryOperationMode', - namespaceIndex: machineryIdx - }, - namespace: namespace, - }) - myOperationMode.addReference({ - referenceType: 'HasAddIn', - nodeId: machineryBuildingBlocks, - isForward: false, - }) - const myOperationModeCurrentState = myOperationMode.getChildByName("CurrentState") as UAVariable - myOperationModeCurrentState?.setValueFromSource({ - dataType: DataType.LocalizedText, - value: coerceLocalizedText('Setup'), - }) + const myOperationMode = ( + addressSpace!.findNode(`ns=${machineryIdx};i=1008`) as UAObjectType + ).instantiate({ + browseName: { + name: "MachineryOperationMode", + namespaceIndex: machineryIdx, + }, + namespace: namespace, + }); + myOperationMode.addReference({ + referenceType: "HasAddIn", + nodeId: machineryBuildingBlocks, + isForward: false, + }); + const myOperationModeCurrentState = myOperationMode.getChildByName( + "CurrentState", + ) as UAVariable; + myOperationModeCurrentState?.setValueFromSource({ + dataType: DataType.LocalizedText, + value: coerceLocalizedText("Setup"), + }); + initializeFakeDataSource(addressSpace); - initializeFakeDataSource(addressSpace) + // ProcessValues - // ProcessValues + const processValuesIdx = addressSpace!.getNamespaceIndex( + "http://opcfoundation.org/UA/Machinery/ProcessValues/", + ); + const processValuesType = addressSpace!.findNode( + `ns=${processValuesIdx};i=1003`, + ) as UAObjectType; + const monitoringObject = namespace!.addObject({ + browseName: "Monitoring", + nodeId: `ns=${namespace.index};s=Monitoring`, + componentOf: myMachine, + }); - const processValuesIdx = addressSpace!.getNamespaceIndex("http://opcfoundation.org/UA/Machinery/ProcessValues/") - const processValuesType = addressSpace!.findNode(`ns=${processValuesIdx};i=1003`) as UAObjectType - const monitoringObject = namespace!.addObject({ - browseName: 'Monitoring', - nodeId: `ns=${namespace.index};s=Monitoring`, - componentOf: myMachine, - }) - - const temperature = processValuesType.instantiate({ - browseName: { - name: 'Temperature', - namespaceIndex: processValuesIdx - }, - namespace: namespace, - }) - temperature.addReference({ - referenceType: 'Organizes', - nodeId: monitoringObject, - isForward: false, - }) - const temperaturTag = temperature.getChildByName("Tag") as UAVariable - temperaturTag?.setValueFromSource({ - dataType: DataType.String, - value: 'Temperature-Tag-123', - }) - const temperatureAnalogSignal = temperature.getChildByName("AnalogSignal") as UAVariable - temperatureAnalogSignal.bindVariable({ - timestamped_get: variableGetter, - // timestamped_set: variableSetter - }, true) - const temperatureAnalogSignalEURange = temperatureAnalogSignal.getChildByName("EURange") as UAVariable - temperatureAnalogSignalEURange.bindVariable({ - timestamped_get: variableGetter, - // timestamped_set: variableSetter - }, true) - const temperatureAnalogSignalEngineeringUnits = temperatureAnalogSignal.getChildByName("EngineeringUnits") as UAVariable - temperatureAnalogSignalEngineeringUnits.bindVariable({ - timestamped_get: variableGetter, - // timestamped_set: variableSetter - }, true) + const temperature = processValuesType.instantiate({ + browseName: { + name: "Temperature", + namespaceIndex: processValuesIdx, + }, + namespace: namespace, + }); + temperature.addReference({ + referenceType: "Organizes", + nodeId: monitoringObject, + isForward: false, + }); + const temperaturTag = temperature.getChildByName("Tag") as UAVariable; + temperaturTag?.setValueFromSource({ + dataType: DataType.String, + value: "Temperature-Tag-123", + }); + const temperatureAnalogSignal = temperature.getChildByName( + "AnalogSignal", + ) as UAVariable; + temperatureAnalogSignal.bindVariable( + { + timestamped_get: variableGetter, + // timestamped_set: variableSetter + }, + true, + ); + const temperatureAnalogSignalEURange = temperatureAnalogSignal.getChildByName( + "EURange", + ) as UAVariable; + temperatureAnalogSignalEURange.bindVariable( + { + timestamped_get: variableGetter, + // timestamped_set: variableSetter + }, + true, + ); + const temperatureAnalogSignalEngineeringUnits = + temperatureAnalogSignal.getChildByName("EngineeringUnits") as UAVariable; + temperatureAnalogSignalEngineeringUnits.bindVariable( + { + timestamped_get: variableGetter, + // timestamped_set: variableSetter + }, + true, + ); - const pressure = processValuesType.instantiate({ - browseName: { - name: 'Pressure', - namespaceIndex: processValuesIdx - }, - namespace: namespace, - }) - pressure.addReference({ - referenceType: "Organizes", - nodeId: monitoringObject, - isForward: false, - }) - const pressureTag = pressure.getChildByName("Tag") as UAVariable - pressureTag?.setValueFromSource({ - dataType: DataType.String, - value: 'Pressure-Tag-123', - }) - const pressureAnalogSignal = pressure.getChildByName("AnalogSignal") as UAVariable - pressureAnalogSignal.bindVariable({ - timestamped_get: variableGetter, - // timestamped_set: variableSetter - }, true) - const pressureAnalogSignalEURange = pressureAnalogSignal.getChildByName("EURange") as UAVariable - pressureAnalogSignalEURange.bindVariable({ - timestamped_get: variableGetter, - // timestamped_set: variableSetter - }, true) - const pressureAnalogSignalEngineeringUnits = pressureAnalogSignal.getChildByName("EngineeringUnits") as UAVariable - pressureAnalogSignalEngineeringUnits.bindVariable({ - timestamped_get: variableGetter, - // timestamped_set: variableSetter - }, true) + const pressure = processValuesType.instantiate({ + browseName: { + name: "Pressure", + namespaceIndex: processValuesIdx, + }, + namespace: namespace, + }); + pressure.addReference({ + referenceType: "Organizes", + nodeId: monitoringObject, + isForward: false, + }); + const pressureTag = pressure.getChildByName("Tag") as UAVariable; + pressureTag?.setValueFromSource({ + dataType: DataType.String, + value: "Pressure-Tag-123", + }); + const pressureAnalogSignal = pressure.getChildByName( + "AnalogSignal", + ) as UAVariable; + pressureAnalogSignal.bindVariable( + { + timestamped_get: variableGetter, + // timestamped_set: variableSetter + }, + true, + ); + const pressureAnalogSignalEURange = pressureAnalogSignal.getChildByName( + "EURange", + ) as UAVariable; + pressureAnalogSignalEURange.bindVariable( + { + timestamped_get: variableGetter, + // timestamped_set: variableSetter + }, + true, + ); + const pressureAnalogSignalEngineeringUnits = + pressureAnalogSignal.getChildByName("EngineeringUnits") as UAVariable; + pressureAnalogSignalEngineeringUnits.bindVariable( + { + timestamped_get: variableGetter, + // timestamped_set: variableSetter + }, + true, + ); - - // instantiate components here -> organizedBy: myMachineComponents -} + // instantiate components here -> organizedBy: myMachineComponents +}; diff --git a/src/permissiongroups.ts b/src/permissiongroups.ts index be4054a9..0b077dd6 100644 --- a/src/permissiongroups.ts +++ b/src/permissiongroups.ts @@ -12,106 +12,101 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - WellKnownRoles, - PermissionType -} from 'node-opcua'; +import { WellKnownRoles, PermissionType } from "node-opcua"; export const ServerRolePermissionGroup = Object.freeze({ // Default -> https://reference.opcfoundation.org/v104/Core/docs/Part3/4.8.2/ DEFAULT: [ - { - roleId: WellKnownRoles.Supervisor, - permissions: - PermissionType.Browse | - PermissionType.ReadRolePermissions | - PermissionType.WriteAttribute | - PermissionType.WriteRolePermissions | - PermissionType.WriteHistorizing | - PermissionType.Read | - PermissionType.Write | - PermissionType.ReadHistory | - PermissionType.InsertHistory | - PermissionType.ModifyHistory | - PermissionType.DeleteHistory | - PermissionType.ReceiveEvents | - PermissionType.Call - // PermissionType.AddReference | - // PermissionType.DeleteNode | - // PermissionType.AddNode + { + roleId: WellKnownRoles.Supervisor, + permissions: + PermissionType.Browse | + PermissionType.ReadRolePermissions | + PermissionType.WriteAttribute | + PermissionType.WriteRolePermissions | + PermissionType.WriteHistorizing | + PermissionType.Read | + PermissionType.Write | + PermissionType.ReadHistory | + PermissionType.InsertHistory | + PermissionType.ModifyHistory | + PermissionType.DeleteHistory | + PermissionType.ReceiveEvents | + PermissionType.Call, + // PermissionType.AddReference | + // PermissionType.DeleteNode | + // PermissionType.AddNode }, - { - roleId: WellKnownRoles.SecurityAdmin, - permissions: - PermissionType.Browse | - PermissionType.ReadRolePermissions | - PermissionType.WriteRolePermissions | - PermissionType.Read | - PermissionType.Write | - PermissionType.ReadHistory | - PermissionType.ReceiveEvents | - PermissionType.Call + { + roleId: WellKnownRoles.SecurityAdmin, + permissions: + PermissionType.Browse | + PermissionType.ReadRolePermissions | + PermissionType.WriteRolePermissions | + PermissionType.Read | + PermissionType.Write | + PermissionType.ReadHistory | + PermissionType.ReceiveEvents | + PermissionType.Call, }, - { - roleId: WellKnownRoles.Operator, - permissions: - PermissionType.Browse | - PermissionType.ReadRolePermissions | - PermissionType.Read | - PermissionType.Write | - PermissionType.ReadHistory | - PermissionType.ReceiveEvents | - PermissionType.Call + { + roleId: WellKnownRoles.Operator, + permissions: + PermissionType.Browse | + PermissionType.ReadRolePermissions | + PermissionType.Read | + PermissionType.Write | + PermissionType.ReadHistory | + PermissionType.ReceiveEvents | + PermissionType.Call, }, - { - roleId: WellKnownRoles.Observer, - permissions: - PermissionType.Browse | - PermissionType.ReadRolePermissions | - PermissionType.Read | - PermissionType.ReadHistory | - PermissionType.ReceiveEvents + { + roleId: WellKnownRoles.Observer, + permissions: + PermissionType.Browse | + PermissionType.ReadRolePermissions | + PermissionType.Read | + PermissionType.ReadHistory | + PermissionType.ReceiveEvents, }, - { - roleId: WellKnownRoles.Engineer, - permissions: - PermissionType.Browse | - PermissionType.ReadRolePermissions | - PermissionType.Read | - PermissionType.Write | - PermissionType.ReadHistory | - PermissionType.ReceiveEvents | - PermissionType.Call + { + roleId: WellKnownRoles.Engineer, + permissions: + PermissionType.Browse | + PermissionType.ReadRolePermissions | + PermissionType.Read | + PermissionType.Write | + PermissionType.ReadHistory | + PermissionType.ReceiveEvents | + PermissionType.Call, }, - { - roleId: WellKnownRoles.ConfigureAdmin, - permissions: - PermissionType.Browse | - PermissionType.ReadRolePermissions | - PermissionType.WriteAttribute | - PermissionType.WriteHistorizing | - PermissionType.Read | - PermissionType.Write | - PermissionType.ReadHistory | - PermissionType.InsertHistory | - PermissionType.ModifyHistory | - PermissionType.ReceiveEvents | - PermissionType.Call + { + roleId: WellKnownRoles.ConfigureAdmin, + permissions: + PermissionType.Browse | + PermissionType.ReadRolePermissions | + PermissionType.WriteAttribute | + PermissionType.WriteHistorizing | + PermissionType.Read | + PermissionType.Write | + PermissionType.ReadHistory | + PermissionType.InsertHistory | + PermissionType.ModifyHistory | + PermissionType.ReceiveEvents | + PermissionType.Call, }, - { - roleId: WellKnownRoles.AuthenticatedUser, - permissions: - PermissionType.Browse | - PermissionType.ReadRolePermissions | - PermissionType.Read | - PermissionType.ReadHistory | - PermissionType.ReceiveEvents + { + roleId: WellKnownRoles.AuthenticatedUser, + permissions: + PermissionType.Browse | + PermissionType.ReadRolePermissions | + PermissionType.Read | + PermissionType.ReadHistory | + PermissionType.ReceiveEvents, }, - { - roleId: WellKnownRoles.Anonymous, - permissions: - PermissionType.Browse | - PermissionType.Read - } -] + { + roleId: WellKnownRoles.Anonymous, + permissions: PermissionType.Browse | PermissionType.Read, + }, + ], }); diff --git a/src/pubsub.ts b/src/pubsub.ts index d4450501..91456e96 100644 --- a/src/pubsub.ts +++ b/src/pubsub.ts @@ -12,244 +12,252 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - DataType, - resolveNodeId, - AttributeIds, - getHostname -} from "node-opcua"; -import { - DataSetFieldContentMask, - JsonDataSetMessageContentMask, - JsonNetworkMessageContentMask, - BrokerTransportQualityOfService, - MyMqttJsonPubSubConnectionDataType, - Transport, - PublishedDataItemsDataType, - MyMqttJsonPubSubConnectionDataTypeOptions, - MyMqttJsonWriterGroupDataTypeOptions, - MyJsonDataSetWriterDataTypeOptions, - PubSubConfigurationDataTypeOptions +import { DataType, resolveNodeId, AttributeIds, getHostname } from "node-opcua"; +import { + DataSetFieldContentMask, + JsonDataSetMessageContentMask, + JsonNetworkMessageContentMask, + BrokerTransportQualityOfService, + MyMqttJsonPubSubConnectionDataType, + Transport, + PublishedDataItemsDataType, + MyMqttJsonPubSubConnectionDataTypeOptions, + MyMqttJsonWriterGroupDataTypeOptions, + MyJsonDataSetWriterDataTypeOptions, + PubSubConfigurationDataTypeOptions, } from "node-opcua-pubsub-expander"; -import { - PubSubConfigurationDataType, - PubSubConnectionDataTypeOptions, - PublishedDataSetDataTypeOptions, - FieldMetaDataOptions +import { + PubSubConfigurationDataType, + PubSubConnectionDataTypeOptions, + PublishedDataSetDataTypeOptions, + FieldMetaDataOptions, } from "node-opcua-types"; +const prefix = "umati"; +const dataPrefix = `${prefix}/json/data/urn:SampleServer-node-opcua-${getHostname()}`; +const metaPrefix = `${prefix}/json/metadata/urn:SampleServer-node-opcua-${getHostname()}`; -const prefix = "umati" -const dataPrefix = `${prefix}/json/data/urn:SampleServer-node-opcua-${getHostname()}` -const metaPrefix = `${prefix}/json/metadata/urn:SampleServer-node-opcua-${getHostname()}` +const createWriterGroup = ( + name: string, + dataSetWriter: MyJsonDataSetWriterDataTypeOptions, +): MyMqttJsonWriterGroupDataTypeOptions => { + const writerGroup: MyMqttJsonWriterGroupDataTypeOptions = { + dataSetWriters: [dataSetWriter], + enabled: true, + publishingInterval: 1000, + name: name, + messageSettings: { + networkMessageContentMask: JsonNetworkMessageContentMask.PublisherId, + }, + transportSettings: { + requestedDeliveryGuarantee: BrokerTransportQualityOfService.AtMostOnce, + }, + }; + return writerGroup; +}; +const createConnection = ( + name: string, + dataSetName: string, + writerGroupName: string, + broker: string, + id: number, +): PubSubConnectionDataTypeOptions => { + const dataSetWriter: MyJsonDataSetWriterDataTypeOptions = { + dataSetFieldContentMask: DataSetFieldContentMask.None, + // DataSetFieldContentMask.SourceTimestamp | + // DataSetFieldContentMask.StatusCode, + dataSetName: dataSetName, + dataSetWriterId: id, + enabled: true, + name: name, + messageSettings: { + // dataSetMessageContentMask?: JsonDataSetMessageContentMask; + dataSetMessageContentMask: JsonDataSetMessageContentMask.None, + // JsonDataSetMessageContentMask.DataSetWriterId | + // JsonDataSetMessageContentMask.MetaDataVersion | + // JsonDataSetMessageContentMask.DataSetWriterName | + // JsonDataSetMessageContentMask.MessageType | + // JsonDataSetMessageContentMask.SequenceNumber | + // JsonDataSetMessageContentMask.Status | + // JsonDataSetMessageContentMask.Timestamp + }, + transportSettings: { + // queueName?: UAString; + // resourceUri?: UAString; + // authenticationProfileUri?: UAString; + // requestedDeliveryGuarantee?: BrokerTransportQualityOfService; + // metaDataQueueName?: UAString; + // metaDataUpdateTime?: Double; + queueName: `${dataPrefix}/${writerGroupName}/VariableDataSetWriter`, + metaDataQueueName: `${metaPrefix}/${writerGroupName}/VariableDataSetWriter`, + metaDataUpdateTime: 5000, + }, + }; -const createWriterGroup = (name: string, dataSetWriter: MyJsonDataSetWriterDataTypeOptions): MyMqttJsonWriterGroupDataTypeOptions => { - const writerGroup: MyMqttJsonWriterGroupDataTypeOptions = { - dataSetWriters: [dataSetWriter], - enabled: true, - publishingInterval: 1000, - name: name, - messageSettings: { - networkMessageContentMask: JsonNetworkMessageContentMask.PublisherId, - }, - transportSettings: { - requestedDeliveryGuarantee: BrokerTransportQualityOfService.AtMostOnce - }, - } - return writerGroup -} - - -const createConnection = (name: string, dataSetName: string, writerGroupName: string, broker: string, id: number): PubSubConnectionDataTypeOptions => { - const dataSetWriter: MyJsonDataSetWriterDataTypeOptions = { - dataSetFieldContentMask: DataSetFieldContentMask.None, - // DataSetFieldContentMask.SourceTimestamp | - // DataSetFieldContentMask.StatusCode, - dataSetName: dataSetName, - dataSetWriterId: id, - enabled: true, - name: name, - messageSettings: { - // dataSetMessageContentMask?: JsonDataSetMessageContentMask; - dataSetMessageContentMask: JsonDataSetMessageContentMask.None - // JsonDataSetMessageContentMask.DataSetWriterId | - // JsonDataSetMessageContentMask.MetaDataVersion | - // JsonDataSetMessageContentMask.DataSetWriterName | - // JsonDataSetMessageContentMask.MessageType | - // JsonDataSetMessageContentMask.SequenceNumber | - // JsonDataSetMessageContentMask.Status | - // JsonDataSetMessageContentMask.Timestamp - }, - transportSettings: { - // queueName?: UAString; - // resourceUri?: UAString; - // authenticationProfileUri?: UAString; - // requestedDeliveryGuarantee?: BrokerTransportQualityOfService; - // metaDataQueueName?: UAString; - // metaDataUpdateTime?: Double; - queueName: `${dataPrefix}/${writerGroupName}/VariableDataSetWriter`, - metaDataQueueName: `${metaPrefix}/${writerGroupName}/VariableDataSetWriter`, - metaDataUpdateTime: 5000 - }, - }; - - const writerGroup: MyMqttJsonWriterGroupDataTypeOptions = createWriterGroup(writerGroupName, dataSetWriter) - - const opts: MyMqttJsonPubSubConnectionDataTypeOptions = { - enabled: true, - name: `Connection_${id}_${broker}`, - transportProfileUri: Transport.MQTT_JSON, - transportSettings: { - // resourceUri?: UAString; - // authenticationProfileUri?: UAString; - }, - address: { - url: broker, - }, - writerGroups: [writerGroup], - readerGroups: [] - } - return new MyMqttJsonPubSubConnectionDataType(opts) -} + const writerGroup: MyMqttJsonWriterGroupDataTypeOptions = createWriterGroup( + writerGroupName, + dataSetWriter, + ); + const opts: MyMqttJsonPubSubConnectionDataTypeOptions = { + enabled: true, + name: `Connection_${id}_${broker}`, + transportProfileUri: Transport.MQTT_JSON, + transportSettings: { + // resourceUri?: UAString; + // authenticationProfileUri?: UAString; + }, + address: { + url: broker, + }, + writerGroups: [writerGroup], + readerGroups: [], + }; + return new MyMqttJsonPubSubConnectionDataType(opts); +}; const createPublishedDataSet1 = (): PublishedDataSetDataTypeOptions => { + const fields: FieldMetaDataOptions[] = [ + // { + // name?: UAString; + // description?: (LocalizedTextLike | null); + // fieldFlags?: DataSetFieldFlags; + // builtInType?: Byte; + // dataType?: (NodeIdLike | null); + // valueRank?: Int32; + // arrayDimensions?: UInt32[] | null; + // maxStringLength?: UInt32; + // dataSetFieldId?: Guid; + // properties?: KeyValuePairOptions[] | null; + // } + { + name: "MyHistoricalSetpointVar", + builtInType: DataType.Double, + dataType: resolveNodeId("Double"), + }, + { + name: "MyHistoricalVar", + builtInType: DataType.Double, + dataType: resolveNodeId("Double"), + }, + ]; - const fields: FieldMetaDataOptions[] = [ - // { - // name?: UAString; - // description?: (LocalizedTextLike | null); - // fieldFlags?: DataSetFieldFlags; - // builtInType?: Byte; - // dataType?: (NodeIdLike | null); - // valueRank?: Int32; - // arrayDimensions?: UInt32[] | null; - // maxStringLength?: UInt32; - // dataSetFieldId?: Guid; - // properties?: KeyValuePairOptions[] | null; - // } - { - name: "MyHistoricalSetpointVar", - builtInType: DataType.Double, - dataType: resolveNodeId("Double"), - }, - { - name: "MyHistoricalVar", - builtInType: DataType.Double, - dataType: resolveNodeId("Double"), - }, - ] - - const publishedData = [ - // { - // publishedVariable?: (NodeIdLike | null); - // attributeId?: UInt32; - // samplingIntervalHint?: Double; - // deadbandType?: UInt32; - // deadbandValue?: Double; - // indexRange?: NumericRange; - // substituteValue?: (VariantLike | null); - // metaDataProperties?: (QualifiedNameLike | null)[] | null; - // } - { - attributeId: AttributeIds.Value, - samplingIntervalHint: 1000, - publishedVariable: `ns=1;i=1321`, - }, - { - attributeId: AttributeIds.Value, - samplingIntervalHint: 1000, - publishedVariable: `ns=1;i=1320`, - }, - ] - - const publishedDataSet: PublishedDataSetDataTypeOptions = { - name: "PublishedDataSet1", - dataSetMetaData: { - fields: fields, - }, - dataSetSource: new PublishedDataItemsDataType({ - publishedData: publishedData, - }), - }; - return publishedDataSet; -} + const publishedData = [ + // { + // publishedVariable?: (NodeIdLike | null); + // attributeId?: UInt32; + // samplingIntervalHint?: Double; + // deadbandType?: UInt32; + // deadbandValue?: Double; + // indexRange?: NumericRange; + // substituteValue?: (VariantLike | null); + // metaDataProperties?: (QualifiedNameLike | null)[] | null; + // } + { + attributeId: AttributeIds.Value, + samplingIntervalHint: 1000, + publishedVariable: `ns=1;i=1321`, + }, + { + attributeId: AttributeIds.Value, + samplingIntervalHint: 1000, + publishedVariable: `ns=1;i=1320`, + }, + ]; + const publishedDataSet: PublishedDataSetDataTypeOptions = { + name: "PublishedDataSet1", + dataSetMetaData: { + fields: fields, + }, + dataSetSource: new PublishedDataItemsDataType({ + publishedData: publishedData, + }), + }; + return publishedDataSet; +}; const createPublishedDataSet2 = (): PublishedDataSetDataTypeOptions => { + const fields: FieldMetaDataOptions[] = [ + // { + // name?: UAString; + // description?: (LocalizedTextLike | null); + // fieldFlags?: DataSetFieldFlags; + // builtInType?: Byte; + // dataType?: (NodeIdLike | null); + // valueRank?: Int32; + // arrayDimensions?: UInt32[] | null; + // maxStringLength?: UInt32; + // dataSetFieldId?: Guid; + // properties?: KeyValuePairOptions[] | null; + // } + { + name: "MyVar", + builtInType: DataType.Double, + dataType: resolveNodeId("Double"), + }, + { + name: "normalStateNode", + builtInType: DataType.Double, + dataType: resolveNodeId("Number"), + }, + ]; - const fields: FieldMetaDataOptions[] = [ - // { - // name?: UAString; - // description?: (LocalizedTextLike | null); - // fieldFlags?: DataSetFieldFlags; - // builtInType?: Byte; - // dataType?: (NodeIdLike | null); - // valueRank?: Int32; - // arrayDimensions?: UInt32[] | null; - // maxStringLength?: UInt32; - // dataSetFieldId?: Guid; - // properties?: KeyValuePairOptions[] | null; - // } - { - name: "MyVar", - builtInType: DataType.Double, - dataType: resolveNodeId("Double"), - }, - { - name: "normalStateNode", - builtInType: DataType.Double, - dataType: resolveNodeId("Number"), - }, - ] - - const publishedData = [ - // { - // publishedVariable?: (NodeIdLike | null); - // attributeId?: UInt32; - // samplingIntervalHint?: Double; - // deadbandType?: UInt32; - // deadbandValue?: Double; - // indexRange?: NumericRange; - // substituteValue?: (VariantLike | null); - // metaDataProperties?: (QualifiedNameLike | null)[] | null; - // } - { - attributeId: AttributeIds.Value, - samplingIntervalHint: 1000, - publishedVariable: `ns=1;i=1032`, - }, - { - attributeId: AttributeIds.Value, - samplingIntervalHint: 1000, - publishedVariable: `ns=1;i=1068`, - }, - ] - - const publishedDataSet: PublishedDataSetDataTypeOptions = { - name: "PublishedDataSet2", - dataSetMetaData: { - fields: fields, - }, - dataSetSource: new PublishedDataItemsDataType({ - publishedData: publishedData, - }), - }; - return publishedDataSet; -} + const publishedData = [ + // { + // publishedVariable?: (NodeIdLike | null); + // attributeId?: UInt32; + // samplingIntervalHint?: Double; + // deadbandType?: UInt32; + // deadbandValue?: Double; + // indexRange?: NumericRange; + // substituteValue?: (VariantLike | null); + // metaDataProperties?: (QualifiedNameLike | null)[] | null; + // } + { + attributeId: AttributeIds.Value, + samplingIntervalHint: 1000, + publishedVariable: `ns=1;i=1032`, + }, + { + attributeId: AttributeIds.Value, + samplingIntervalHint: 1000, + publishedVariable: `ns=1;i=1068`, + }, + ]; + const publishedDataSet: PublishedDataSetDataTypeOptions = { + name: "PublishedDataSet2", + dataSetMetaData: { + fields: fields, + }, + dataSetSource: new PublishedDataItemsDataType({ + publishedData: publishedData, + }), + }; + return publishedDataSet; +}; export const constructMqttJsonPubSubConfiguration = (broker: string) => { - const opts: PubSubConfigurationDataTypeOptions = { - connections: [ - createConnection("dataSetWriter1", "PublishedDataSet1", "WriterGroup1", broker, 1), - createConnection("dataSetWriter2", "PublishedDataSet2", "WriterGroup2", broker, 2) - ], - publishedDataSets: [ - createPublishedDataSet1(), - createPublishedDataSet2() - ] - } - return new PubSubConfigurationDataType(opts); -} + const opts: PubSubConfigurationDataTypeOptions = { + connections: [ + createConnection( + "dataSetWriter1", + "PublishedDataSet1", + "WriterGroup1", + broker, + 1, + ), + createConnection( + "dataSetWriter2", + "PublishedDataSet2", + "WriterGroup2", + broker, + 2, + ), + ], + publishedDataSets: [createPublishedDataSet1(), createPublishedDataSet2()], + }; + return new PubSubConfigurationDataType(opts); +}; diff --git a/src/server.ts b/src/server.ts index 88968eba..e8b1303d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -16,65 +16,70 @@ import { OPCUAServer, ServerState, coerceLocalizedText, - OPCUAServerEndPoint -} from 'node-opcua'; + OPCUAServerEndPoint, +} from "node-opcua"; import { InstallPubSubOptions, installPubSub } from "node-opcua-pubsub-server"; -import { constructMqttJsonPubSubConfiguration } from "./pubsub" +import { constructMqttJsonPubSubConfiguration } from "./pubsub"; -import { green, yellow, red } from './utils/log'; -import { config } from './config'; -import { createAddressSpace } from './addressspace'; +import { green, yellow, red } from "./utils/log"; +import { config } from "./config"; +import { createAddressSpace } from "./addressspace"; const server = new OPCUAServer(config) - .on('serverRegistered', () => { - green(' serverRegistered! '); + .on("serverRegistered", () => { + green(" serverRegistered! "); }) - .on('serverUnregistered', () => { - red(' serverUnregistered! '); + .on("serverUnregistered", () => { + red(" serverUnregistered! "); }) - .on('serverRegistrationRenewed', () => { - green(' serverRegistrationRenewed! '); + .on("serverRegistrationRenewed", () => { + green(" serverRegistrationRenewed! "); }) - .on('serverRegistrationPending', () => { - yellow(' serverRegistrationPending! '); + .on("serverRegistrationPending", () => { + yellow(" serverRegistrationPending! "); }) - .on('connectionRefused', (socketData: any, endpoint: OPCUAServerEndPoint) => { - red(' connectionRefused!'); + .on("connectionRefused", (socketData: any, endpoint: OPCUAServerEndPoint) => { + red(" connectionRefused!"); }) - .on('openSecureChannelFailure', (socketData: any, channelData: any, endpoint: OPCUAServerEndPoint) => { - red(' openSecureChannelFailure!'); - }); + .on( + "openSecureChannelFailure", + (socketData: any, channelData: any, endpoint: OPCUAServerEndPoint) => { + red(" openSecureChannelFailure!"); + }, + ); const shutDown = (): void => { if (server.engine.serverStatus.state === ServerState.Shutdown) { - yellow(` Server shutdown already requested... shutdown will happen in ${server.engine.serverStatus.secondsTillShutdown} second`); + yellow( + ` Server shutdown already requested... shutdown will happen in ${server.engine.serverStatus.secondsTillShutdown} second`, + ); return; } - yellow(' Received server interruption from user '); - yellow(' shutting down ...'); - const reason = coerceLocalizedText('Shutdown by administrator'); - reason ? server.engine.serverStatus.shutdownReason = reason : null; + yellow(" Received server interruption from user "); + yellow(" shutting down ..."); + const reason = coerceLocalizedText("Shutdown by administrator"); + reason ? (server.engine.serverStatus.shutdownReason = reason) : null; server.shutdown(10000, () => { - yellow(' shutting down completed '); - yellow(' done '); + yellow(" shutting down completed "); + yellow(" done "); process.exit(0); }); }; const startUp = async (server: OPCUAServer): Promise => { await server.start(); - green(' server started and ready on: '); + green(" server started and ready on: "); green(` |--> ${server.getEndpointUrl()} `); green(` AlternateHostnames: ${config.alternateHostname} `); - green(' CTRL+C to stop '); - process.on('SIGINT', shutDown); - process.on('SIGTERM', shutDown); + green(" CTRL+C to stop "); + process.on("SIGINT", shutDown); + process.on("SIGTERM", shutDown); }; (async () => { try { - yellow(' starting server... '); + yellow(" starting server... "); await server.initialize(); await createAddressSpace(server); server.engine.addressSpace?.installAlarmsAndConditionsService(); diff --git a/src/serveraddressspace/myfinitestatemachinetype.ts b/src/serveraddressspace/myfinitestatemachinetype.ts index 054c69e5..cb963133 100644 --- a/src/serveraddressspace/myfinitestatemachinetype.ts +++ b/src/serveraddressspace/myfinitestatemachinetype.ts @@ -1,123 +1,162 @@ -import { - AddressSpace, - UAFiniteStateMachineType, - UAReferenceType, - UAEventType -} from 'node-opcua' +import { + AddressSpace, + UAFiniteStateMachineType, + UAReferenceType, + UAEventType, +} from "node-opcua"; -export const createMyFiniteStateMachineType = async (addressSpace: AddressSpace): Promise => { +export const createMyFiniteStateMachineType = async ( + addressSpace: AddressSpace, +): Promise => { + const namespace = addressSpace?.getOwnNamespace(); - const namespace = addressSpace?.getOwnNamespace() + const myFiniteStateMachine = namespace.addObjectType({ + browseName: "MyFiniteStateMachineType", + subtypeOf: "FiniteStateMachineType", + }) as UAFiniteStateMachineType; - const myFiniteStateMachine = namespace.addObjectType({ - browseName: 'MyFiniteStateMachineType', - subtypeOf: 'FiniteStateMachineType' - }) as UAFiniteStateMachineType + const hasEffect = addressSpace.findNode("ns=0;i=54") as UAReferenceType; + const transitionEventType = addressSpace.findNode( + "ns=0;i=2311", + ) as UAEventType; + const modellingRuleRef = addressSpace.findNode( + "ns=0;i=37", + ) as UAReferenceType; + const modellingRuleMandatory = addressSpace.findNode("ns=0;i=78"); - const hasEffect = addressSpace.findNode('ns=0;i=54') as UAReferenceType - const transitionEventType = addressSpace.findNode('ns=0;i=2311') as UAEventType - const modellingRuleRef = addressSpace.findNode('ns=0;i=37') as UAReferenceType - const modellingRuleMandatory = addressSpace.findNode('ns=0;i=78') + const initState = namespace.addState( + myFiniteStateMachine, + "Initializing", + 100, + true, + ); + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // initState.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } + const idleState = namespace.addState(myFiniteStateMachine, "Idle", 200); + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // idleState.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } + const prepareState = namespace.addState(myFiniteStateMachine, "Prepare", 300); + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // prepareState.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } + const processingState = namespace.addState( + myFiniteStateMachine, + "Processing", + 400, + ); + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // processingState.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } + const doneState = namespace.addState(myFiniteStateMachine, "Done", 500); + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // doneState.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } - const initState = namespace.addState(myFiniteStateMachine, 'Initializing', 100, true) - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // initState.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - const idleState = namespace.addState(myFiniteStateMachine, 'Idle', 200) - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // idleState.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - const prepareState = namespace.addState(myFiniteStateMachine, 'Prepare', 300) - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // prepareState.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - const processingState = namespace.addState(myFiniteStateMachine, 'Processing', 400) - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // processingState.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - const doneState = namespace.addState(myFiniteStateMachine, 'Done', 500) - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // doneState.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - - const initToIdle = namespace.addTransition(myFiniteStateMachine, 'Initializing', 'Idle', 1) - if (hasEffect != null && transitionEventType != null) { - initToIdle.addReference({ - referenceType: hasEffect, - nodeId: transitionEventType, - }) - } - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // initToIdle.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - const idleToPrepare = namespace.addTransition(myFiniteStateMachine, 'Idle', 'Prepare', 2) - if (hasEffect != null && transitionEventType != null) { - idleToPrepare.addReference({ - referenceType: hasEffect, - nodeId: transitionEventType, - }) - } - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // idleToPrepare.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - const prepareToProcessing = namespace.addTransition(myFiniteStateMachine, 'Prepare', 'Processing', 3) - if (hasEffect != null && transitionEventType != null) { - prepareToProcessing.addReference({ - referenceType: hasEffect, - nodeId: transitionEventType, - }) - } - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // prepareToProcessing.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - const processingToDone = namespace.addTransition(myFiniteStateMachine, 'Processing', 'Done', 4) - if (hasEffect != null && transitionEventType != null) { - processingToDone.addReference({ - referenceType: hasEffect, - nodeId: transitionEventType, - }) - } - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // processingToDone.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } - const doneToIdle = namespace.addTransition(myFiniteStateMachine, 'Done', 'Idle', 5) - if (hasEffect != null && transitionEventType != null) { - doneToIdle.addReference({ - referenceType: hasEffect, - nodeId: transitionEventType, - }) - } - // if (modellingRuleRef != null && modellingRuleMandatory != null) { - // doneToIdle.addReference({ - // referenceType: modellingRuleRef, - // nodeId: modellingRuleMandatory, - // }) - // } -} + const initToIdle = namespace.addTransition( + myFiniteStateMachine, + "Initializing", + "Idle", + 1, + ); + if (hasEffect != null && transitionEventType != null) { + initToIdle.addReference({ + referenceType: hasEffect, + nodeId: transitionEventType, + }); + } + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // initToIdle.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } + const idleToPrepare = namespace.addTransition( + myFiniteStateMachine, + "Idle", + "Prepare", + 2, + ); + if (hasEffect != null && transitionEventType != null) { + idleToPrepare.addReference({ + referenceType: hasEffect, + nodeId: transitionEventType, + }); + } + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // idleToPrepare.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } + const prepareToProcessing = namespace.addTransition( + myFiniteStateMachine, + "Prepare", + "Processing", + 3, + ); + if (hasEffect != null && transitionEventType != null) { + prepareToProcessing.addReference({ + referenceType: hasEffect, + nodeId: transitionEventType, + }); + } + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // prepareToProcessing.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } + const processingToDone = namespace.addTransition( + myFiniteStateMachine, + "Processing", + "Done", + 4, + ); + if (hasEffect != null && transitionEventType != null) { + processingToDone.addReference({ + referenceType: hasEffect, + nodeId: transitionEventType, + }); + } + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // processingToDone.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } + const doneToIdle = namespace.addTransition( + myFiniteStateMachine, + "Done", + "Idle", + 5, + ); + if (hasEffect != null && transitionEventType != null) { + doneToIdle.addReference({ + referenceType: hasEffect, + nodeId: transitionEventType, + }); + } + // if (modellingRuleRef != null && modellingRuleMandatory != null) { + // doneToIdle.addReference({ + // referenceType: modellingRuleRef, + // nodeId: modellingRuleMandatory, + // }) + // } +}; diff --git a/src/serveraddressspace/serveraddressspace.ts b/src/serveraddressspace/serveraddressspace.ts index 74590c32..4e12f35e 100644 --- a/src/serveraddressspace/serveraddressspace.ts +++ b/src/serveraddressspace/serveraddressspace.ts @@ -12,713 +12,735 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { - AddressSpace, - DataType, - RaiseEventData, - Variant, - StatusCodes, - UAVariable, - StatusCode, - AddReferenceOpts, - LocalizedText, - UAObject, - promoteToStateMachine, - UATransitionEx, - UAState, - ConditionInfoOptions, - coerceLocalizedText -} from 'node-opcua' - - -import { ServerRolePermissionGroup } from './../permissiongroups' -import { createMyFiniteStateMachineType } from './myfinitestatemachinetype' - -export const createOwnServerAddressspaceLogic = async (addressSpace: AddressSpace): Promise => { - - /* +import { + AddressSpace, + DataType, + RaiseEventData, + Variant, + StatusCodes, + UAVariable, + StatusCode, + AddReferenceOpts, + LocalizedText, + UAObject, + promoteToStateMachine, + UATransitionEx, + UAState, + ConditionInfoOptions, + coerceLocalizedText, +} from "node-opcua"; + +import { ServerRolePermissionGroup } from "./../permissiongroups"; +import { createMyFiniteStateMachineType } from "./myfinitestatemachinetype"; + +export const createOwnServerAddressspaceLogic = async ( + addressSpace: AddressSpace, +): Promise => { + /* General Stuff: */ - const namespace = addressSpace?.getOwnNamespace() - const diIdx = addressSpace?.getNamespaceIndex('http://opcfoundation.org/UA/DI/') - - const contributorType = namespace.addObjectType({ - browseName: 'ContributorType', - subtypeOf: 'BaseObjectType' - }) - - namespace.addVariable({ - propertyOf: contributorType, - browseName: 'Company', - dataType: DataType.String, - modellingRule: 'Mandatory' - }) - - namespace.addVariable({ - propertyOf: contributorType, - browseName: 'Country', - dataType: DataType.String, - modellingRule: 'Mandatory' - }) - - namespace.addVariable({ - propertyOf: contributorType, - browseName: 'Mail', - dataType: DataType.String, - modellingRule: 'Mandatory' - }) - - const contributorFolder = namespace.addFolder(addressSpace.rootFolder.objects, { - browseName: 'Contributors', - }) - - let contributor: UAObject - let company: UAVariable - let country: UAVariable - let mail: UAVariable - - // Andreas Heine - contributor = contributorType.instantiate({ - componentOf: contributorFolder, - browseName: 'Andreas Heine', - displayName: new LocalizedText({text: 'Andreas Heine'}) - }) - company = contributor.getChildByName('Company') as UAVariable - company.setValueFromSource({ - value: 'konzeptpark GmbH', - dataType: DataType.String - }) - country = contributor.getChildByName('Country') as UAVariable - country.setValueFromSource({ - value: 'Germany', - dataType: DataType.String - }) - mail = contributor.getChildByName('Mail') as UAVariable - mail.setValueFromSource({ - value: 'info@andreas-heine.net', - dataType: DataType.String - }) - - // Götz Görisch - contributor = contributorType.instantiate({ - componentOf: contributorFolder, - browseName: 'Götz Görisch', - displayName: new LocalizedText({text: 'Götz Görisch'}) - }) - company = contributor.getChildByName('Company') as UAVariable - company.setValueFromSource({ - value: 'VDW - Verein Deutscher Werkzeugmaschinenfabriken e.V.', - dataType: DataType.String - }) - country = contributor.getChildByName('Country') as UAVariable - country.setValueFromSource({ - value: 'Germany', - dataType: DataType.String - }) - mail = contributor.getChildByName('Mail') as UAVariable - mail.setValueFromSource({ - value: 'g.goerisch@vdw.de', - dataType: DataType.String - }) - - // Harald Weber - contributor = contributorType.instantiate({ - componentOf: contributorFolder, - browseName: 'Harald Weber', - displayName: new LocalizedText({text: 'Harald Weber'}) - }) - company = contributor.getChildByName('Company') as UAVariable - company.setValueFromSource({ - value: 'VDMA', - dataType: DataType.String - }) - country = contributor.getChildByName('Country') as UAVariable - country.setValueFromSource({ - value: 'Germany', - dataType: DataType.String - }) - mail = contributor.getChildByName('Mail') as UAVariable - mail.setValueFromSource({ - value: 'harald.weber@vdma.org', - dataType: DataType.String - }) - - // Etienne Rossignon - contributor = contributorType.instantiate({ - componentOf: contributorFolder, - browseName: 'Etienne Rossignon', - displayName: new LocalizedText({text: 'Etienne Rossignon'}) - }) - company = contributor.getChildByName('Company') as UAVariable - company.setValueFromSource({ - value: 'Sterfive', - dataType: DataType.String - }) - country = contributor.getChildByName('Country') as UAVariable - country.setValueFromSource({ - value: 'France', - dataType: DataType.String - }) - mail = contributor.getChildByName('Mail') as UAVariable - mail.setValueFromSource({ - value: 'etienne.rossignon@sterfive.com', - dataType: DataType.String - }) - - // Suprateek Banerjee - contributor = contributorType.instantiate({ - componentOf: contributorFolder, - browseName: 'Suprateek Banerjee', - displayName: new LocalizedText({text: 'Suprateek Banerjee'}) - }) - company = contributor.getChildByName('Company') as UAVariable - company.setValueFromSource({ - value: 'VDMA', - dataType: DataType.String - }) - country = contributor.getChildByName('Country') as UAVariable - country.setValueFromSource({ - value: 'Germany', - dataType: DataType.String - }) - mail = contributor.getChildByName('Mail') as UAVariable - mail.setValueFromSource({ - value: 'suprateek.banerjee@vdma.org', - dataType: DataType.String - }) - - /* + const namespace = addressSpace?.getOwnNamespace(); + const diIdx = addressSpace?.getNamespaceIndex( + "http://opcfoundation.org/UA/DI/", + ); + + const contributorType = namespace.addObjectType({ + browseName: "ContributorType", + subtypeOf: "BaseObjectType", + }); + + namespace.addVariable({ + propertyOf: contributorType, + browseName: "Company", + dataType: DataType.String, + modellingRule: "Mandatory", + }); + + namespace.addVariable({ + propertyOf: contributorType, + browseName: "Country", + dataType: DataType.String, + modellingRule: "Mandatory", + }); + + namespace.addVariable({ + propertyOf: contributorType, + browseName: "Mail", + dataType: DataType.String, + modellingRule: "Mandatory", + }); + + const contributorFolder = namespace.addFolder( + addressSpace.rootFolder.objects, + { + browseName: "Contributors", + }, + ); + + let contributor: UAObject; + let company: UAVariable; + let country: UAVariable; + let mail: UAVariable; + + // Andreas Heine + contributor = contributorType.instantiate({ + componentOf: contributorFolder, + browseName: "Andreas Heine", + displayName: new LocalizedText({ text: "Andreas Heine" }), + }); + company = contributor.getChildByName("Company") as UAVariable; + company.setValueFromSource({ + value: "konzeptpark GmbH", + dataType: DataType.String, + }); + country = contributor.getChildByName("Country") as UAVariable; + country.setValueFromSource({ + value: "Germany", + dataType: DataType.String, + }); + mail = contributor.getChildByName("Mail") as UAVariable; + mail.setValueFromSource({ + value: "info@andreas-heine.net", + dataType: DataType.String, + }); + + // Götz Görisch + contributor = contributorType.instantiate({ + componentOf: contributorFolder, + browseName: "Götz Görisch", + displayName: new LocalizedText({ text: "Götz Görisch" }), + }); + company = contributor.getChildByName("Company") as UAVariable; + company.setValueFromSource({ + value: "VDW - Verein Deutscher Werkzeugmaschinenfabriken e.V.", + dataType: DataType.String, + }); + country = contributor.getChildByName("Country") as UAVariable; + country.setValueFromSource({ + value: "Germany", + dataType: DataType.String, + }); + mail = contributor.getChildByName("Mail") as UAVariable; + mail.setValueFromSource({ + value: "g.goerisch@vdw.de", + dataType: DataType.String, + }); + + // Harald Weber + contributor = contributorType.instantiate({ + componentOf: contributorFolder, + browseName: "Harald Weber", + displayName: new LocalizedText({ text: "Harald Weber" }), + }); + company = contributor.getChildByName("Company") as UAVariable; + company.setValueFromSource({ + value: "VDMA", + dataType: DataType.String, + }); + country = contributor.getChildByName("Country") as UAVariable; + country.setValueFromSource({ + value: "Germany", + dataType: DataType.String, + }); + mail = contributor.getChildByName("Mail") as UAVariable; + mail.setValueFromSource({ + value: "harald.weber@vdma.org", + dataType: DataType.String, + }); + + // Etienne Rossignon + contributor = contributorType.instantiate({ + componentOf: contributorFolder, + browseName: "Etienne Rossignon", + displayName: new LocalizedText({ text: "Etienne Rossignon" }), + }); + company = contributor.getChildByName("Company") as UAVariable; + company.setValueFromSource({ + value: "Sterfive", + dataType: DataType.String, + }); + country = contributor.getChildByName("Country") as UAVariable; + country.setValueFromSource({ + value: "France", + dataType: DataType.String, + }); + mail = contributor.getChildByName("Mail") as UAVariable; + mail.setValueFromSource({ + value: "etienne.rossignon@sterfive.com", + dataType: DataType.String, + }); + + // Suprateek Banerjee + contributor = contributorType.instantiate({ + componentOf: contributorFolder, + browseName: "Suprateek Banerjee", + displayName: new LocalizedText({ text: "Suprateek Banerjee" }), + }); + company = contributor.getChildByName("Company") as UAVariable; + company.setValueFromSource({ + value: "VDMA", + dataType: DataType.String, + }); + country = contributor.getChildByName("Country") as UAVariable; + country.setValueFromSource({ + value: "Germany", + dataType: DataType.String, + }); + mail = contributor.getChildByName("Mail") as UAVariable; + mail.setValueFromSource({ + value: "suprateek.banerjee@vdma.org", + dataType: DataType.String, + }); + + /* Showcase */ - const showcaseFolder = namespace.addFolder(addressSpace.rootFolder.objects, { - browseName: 'Showcases', - }) - - /* + const showcaseFolder = namespace.addFolder(addressSpace.rootFolder.objects, { + browseName: "Showcases", + }); + + /* Showcase: Events */ - const showcaseEV = namespace.addObject({ - browseName: 'Events', - organizedBy: showcaseFolder, - notifierOf: addressSpace.rootFolder.objects.server - }) - - const demoEvent = namespace.addEventType({ - browseName: 'DemoEventType', - subtypeOf: 'BaseEventType', - isAbstract: false - }) - - const myEventRefs: AddReferenceOpts[] = [ - { - nodeId: demoEvent, - referenceType: 'GeneratesEvent' - } - ] - - const myEvent = namespace.addObject({ - browseName: 'myEventNotifier', - componentOf: showcaseEV, - eventSourceOf: showcaseEV, - eventNotifier: 1, // 0:None, 1:SubscribeToEvents, 2:HistoryRead, 3:HistoryWrite - references: myEventRefs - }) - - namespace.addVariable({ - browseName: 'CustomDemoEventPropertie1', - propertyOf: demoEvent, - dataType: DataType.UInt64, - modellingRule: 'Mandatory', - value: new Variant({ - value: 0, - dataType: DataType.UInt64 - }) - }) - - namespace.addVariable({ - browseName: 'CustomDemoEventPropertie2', - propertyOf: demoEvent, - dataType: DataType.DateTime, - modellingRule: 'Mandatory', - value: new Variant({ - value: null, - dataType: DataType.DateTime - }) - }) - - demoEvent.install_extra_properties() - - let count: number = 100 - setInterval(() => { - count = count + 50 - if (count > 1000) { - count = 100 - } - const eventData: RaiseEventData = { - message: new Variant({ - value: `New Event with Severity: ${count}`, - dataType: DataType.String, - }), - severity: new Variant({ - value: count, - dataType: DataType.Int32, - }), - customDemoEventPropertie1: new Variant({ - value: 1234, - dataType: DataType.UInt64, - }), - customDemoEventPropertie2: new Variant({ - value: new Date(), - dataType: DataType.DateTime, - }) - } - myEvent.raiseEvent(demoEvent, eventData) - }, 5000) - - /* + const showcaseEV = namespace.addObject({ + browseName: "Events", + organizedBy: showcaseFolder, + notifierOf: addressSpace.rootFolder.objects.server, + }); + + const demoEvent = namespace.addEventType({ + browseName: "DemoEventType", + subtypeOf: "BaseEventType", + isAbstract: false, + }); + + const myEventRefs: AddReferenceOpts[] = [ + { + nodeId: demoEvent, + referenceType: "GeneratesEvent", + }, + ]; + + const myEvent = namespace.addObject({ + browseName: "myEventNotifier", + componentOf: showcaseEV, + eventSourceOf: showcaseEV, + eventNotifier: 1, // 0:None, 1:SubscribeToEvents, 2:HistoryRead, 3:HistoryWrite + references: myEventRefs, + }); + + namespace.addVariable({ + browseName: "CustomDemoEventPropertie1", + propertyOf: demoEvent, + dataType: DataType.UInt64, + modellingRule: "Mandatory", + value: new Variant({ + value: 0, + dataType: DataType.UInt64, + }), + }); + + namespace.addVariable({ + browseName: "CustomDemoEventPropertie2", + propertyOf: demoEvent, + dataType: DataType.DateTime, + modellingRule: "Mandatory", + value: new Variant({ + value: null, + dataType: DataType.DateTime, + }), + }); + + demoEvent.install_extra_properties(); + + let count: number = 100; + setInterval(() => { + count = count + 50; + if (count > 1000) { + count = 100; + } + const eventData: RaiseEventData = { + message: new Variant({ + value: `New Event with Severity: ${count}`, + dataType: DataType.String, + }), + severity: new Variant({ + value: count, + dataType: DataType.Int32, + }), + customDemoEventPropertie1: new Variant({ + value: 1234, + dataType: DataType.UInt64, + }), + customDemoEventPropertie2: new Variant({ + value: new Date(), + dataType: DataType.DateTime, + }), + }; + myEvent.raiseEvent(demoEvent, eventData); + }, 5000); + + /* Showcase: Alarms and Conditions */ - const showcaseAC = namespace.addObject({ - browseName: 'Alarms&Conditions', - organizedBy: showcaseFolder, - eventSourceOf: addressSpace.rootFolder.objects.server, - eventNotifier: 1 - }) - - let myValue = 25 - setInterval(()=>{ - myValue+=1 - if (myValue >= 60) { - myValue = -25; - } - }, 1000) - - const myVar = namespace.addVariable({ - browseName: 'MyVar', - componentOf: showcaseAC, - dataType: DataType.Double, - value: { - get: function (this: UAVariable): Variant { - return new Variant({ - value: myValue, - dataType: DataType.Double - })}, - set: function(this: UAVariable, value: Variant): StatusCode { - myValue = value.value - return StatusCodes.Good - } - - }, - minimumSamplingInterval: 1000, - eventSourceOf: showcaseAC, - }) - - const ownConditionEventType = namespace.addEventType({ - browseName: 'ownConditionEventType', - subtypeOf: 'ConditionType', - isAbstract: false - }) - - const cond = namespace.instantiateCondition(ownConditionEventType, { - browseName: 'MyCondition', - conditionName: 'MyCondition', - componentOf: showcaseAC, - conditionSource: showcaseAC, - }) - - cond.severity.setValueFromSource({ - value: 150, - dataType: DataType.UInt16 - }) - - cond.message.setValueFromSource({ - value: 'MyCondition is Good!', - dataType: DataType.LocalizedText - }) - - cond.retain.setValueFromSource({ - value: true, - dataType: DataType.Boolean - }) - - cond.time.setValueFromSource({ - value: new Date(), - dataType: DataType.DateTime - }) - - setInterval(() => { - let condInfo: ConditionInfoOptions - if (cond.message.readValue().value.value.text == 'MyCondition is Good!') { - cond.severity.setValueFromSource({ - value: 800, - dataType: DataType.UInt16 - }) - - cond.message.setValueFromSource({ - value: 'MyCondition is Bad!', - dataType: DataType.LocalizedText - }) - - cond.time.setValueFromSource({ - value: new Date(), - dataType: DataType.DateTime - }) - condInfo = { - retain: true, - message: coerceLocalizedText('MyCondition is Bad!'), - severity: 800 - } - } else { - cond.severity.setValueFromSource({ - value: 150, - dataType: DataType.UInt16 - }) - - cond.message.setValueFromSource({ - value: 'MyCondition is Good!', - dataType: DataType.LocalizedText - }) - - cond.time.setValueFromSource({ - value: new Date(), - dataType: DataType.DateTime - }) - condInfo = { - retain: true, - message: coerceLocalizedText('MyCondition is Good!'), - severity: 150 - } - } - cond.raiseNewCondition(condInfo) - }, 15000) - - const stringStateArray = ['Uncertain', 'Healthy', 'OutOfService', 'Maintenance'] - - const multiStateDiscreteNode = namespace.addMultiStateDiscrete({ - browseName: 'offNormalInputNode', - enumStrings: stringStateArray, - value: 1 - }) - - const normalStateNode = namespace.addMultiStateDiscrete({ - browseName: 'normalStateNode', - enumStrings: stringStateArray, - componentOf: showcaseAC, - value: 1, - accessLevel: 3, - userAccessLevel: 3 - }) - - const offnormalAlarm = namespace.instantiateOffNormalAlarm({ - browseName: 'SensorOffNormalAlarm', - conditionSource: showcaseAC, - componentOf: showcaseAC, - inputNode: multiStateDiscreteNode, - normalState: normalStateNode - }) - - offnormalAlarm.retain.setValueFromSource({ - value: true, - dataType: DataType.Boolean - }) - - setInterval(() => { - let randomIdx = Math.floor(Math.random()*stringStateArray.length) - if (randomIdx != 1) { - offnormalAlarm.severity.setValueFromSource({ - value: 600, - dataType: DataType.UInt16 - }) - } else { - offnormalAlarm.severity.setValueFromSource({ - value: 200, - dataType: DataType.UInt16 - }) - } - normalStateNode.setValueFromSource({ - value: randomIdx, - dataType: DataType.UInt32 - }) - }, 60000) - - const ownEventType = namespace.addEventType({ - browseName: 'ownNonExclusiveLimitAlarmType', - subtypeOf: 'NonExclusiveLimitAlarmType', - isAbstract: false - }) - - const alarm = namespace.instantiateNonExclusiveLimitAlarm(ownEventType, { - browseName: 'MyVarNonExclusiveLimitAlarm', - conditionName: 'MyVarNonExclusiveLimitAlarm', - componentOf: showcaseAC, - conditionSource: myVar, - highHighLimit: 50.0, - highLimit: 40.0, - inputNode: myVar, - lowLimit: 20.0, - lowLowLimit: -5.0, - }) - - alarm.retain.setValueFromSource({ - value: true, - dataType: DataType.Boolean - }) - - const alarmConfirmable = namespace.instantiateNonExclusiveLimitAlarm(ownEventType, { - browseName: 'MyVarConfirmableNonExclusiveLimitAlarm', - conditionName: 'MyVarConfirmableNonExclusiveLimitAlarm', - componentOf: showcaseAC, - conditionSource: myVar, - highHighLimit: 50.0, - highLimit: 40.0, - inputNode: myVar, - lowLimit: 20.0, - lowLowLimit: -5.0, - optionals: [ - 'ConfirmedState', 'Confirm' - ] - }) - - alarmConfirmable.retain.setValueFromSource({ - value: true, - dataType: DataType.Boolean - }) - - const ownEventType2 = namespace.addEventType({ - browseName: 'ownExclusiveLimitAlarmType', - subtypeOf: 'ExclusiveLimitAlarmType', - isAbstract: false - }) - - const alarm2 = namespace.instantiateExclusiveLimitAlarm(ownEventType2, { - browseName: 'MyVarExclusiveLimitAlarm', - conditionName: 'MyVarExclusiveLimitAlarm', - componentOf: showcaseAC, - conditionSource: myVar, - highHighLimit: 50.0, - highLimit: 40.0, - inputNode: myVar, - lowLimit: 20.0, - lowLowLimit: -5.0, - }) - - alarm2.retain.setValueFromSource({ - value: true, - dataType: DataType.Boolean - }) - - const alarm2Confirmable = namespace.instantiateExclusiveLimitAlarm(ownEventType2, { - browseName: 'MyVarConfirmableExclusiveLimitAlarm', - conditionName: 'MyVarConfirmableExclusiveLimitAlarm', - componentOf: showcaseAC, - conditionSource: myVar, - highHighLimit: 50.0, - highLimit: 40.0, - inputNode: myVar, - lowLimit: 20.0, - lowLowLimit: -5.0, - optionals: [ - 'ConfirmedState', 'Confirm' - ] - }) - - alarm2Confirmable.retain.setValueFromSource({ - value: true, - dataType: DataType.Boolean - }) - - /* + const showcaseAC = namespace.addObject({ + browseName: "Alarms&Conditions", + organizedBy: showcaseFolder, + eventSourceOf: addressSpace.rootFolder.objects.server, + eventNotifier: 1, + }); + + let myValue = 25; + setInterval(() => { + myValue += 1; + if (myValue >= 60) { + myValue = -25; + } + }, 1000); + + const myVar = namespace.addVariable({ + browseName: "MyVar", + componentOf: showcaseAC, + dataType: DataType.Double, + value: { + get: function (this: UAVariable): Variant { + return new Variant({ + value: myValue, + dataType: DataType.Double, + }); + }, + set: function (this: UAVariable, value: Variant): StatusCode { + myValue = value.value; + return StatusCodes.Good; + }, + }, + minimumSamplingInterval: 1000, + eventSourceOf: showcaseAC, + }); + + const ownConditionEventType = namespace.addEventType({ + browseName: "ownConditionEventType", + subtypeOf: "ConditionType", + isAbstract: false, + }); + + const cond = namespace.instantiateCondition(ownConditionEventType, { + browseName: "MyCondition", + conditionName: "MyCondition", + componentOf: showcaseAC, + conditionSource: showcaseAC, + }); + + cond.severity.setValueFromSource({ + value: 150, + dataType: DataType.UInt16, + }); + + cond.message.setValueFromSource({ + value: "MyCondition is Good!", + dataType: DataType.LocalizedText, + }); + + cond.retain.setValueFromSource({ + value: true, + dataType: DataType.Boolean, + }); + + cond.time.setValueFromSource({ + value: new Date(), + dataType: DataType.DateTime, + }); + + setInterval(() => { + let condInfo: ConditionInfoOptions; + if (cond.message.readValue().value.value.text == "MyCondition is Good!") { + cond.severity.setValueFromSource({ + value: 800, + dataType: DataType.UInt16, + }); + + cond.message.setValueFromSource({ + value: "MyCondition is Bad!", + dataType: DataType.LocalizedText, + }); + + cond.time.setValueFromSource({ + value: new Date(), + dataType: DataType.DateTime, + }); + condInfo = { + retain: true, + message: coerceLocalizedText("MyCondition is Bad!"), + severity: 800, + }; + } else { + cond.severity.setValueFromSource({ + value: 150, + dataType: DataType.UInt16, + }); + + cond.message.setValueFromSource({ + value: "MyCondition is Good!", + dataType: DataType.LocalizedText, + }); + + cond.time.setValueFromSource({ + value: new Date(), + dataType: DataType.DateTime, + }); + condInfo = { + retain: true, + message: coerceLocalizedText("MyCondition is Good!"), + severity: 150, + }; + } + cond.raiseNewCondition(condInfo); + }, 15000); + + const stringStateArray = [ + "Uncertain", + "Healthy", + "OutOfService", + "Maintenance", + ]; + + const multiStateDiscreteNode = namespace.addMultiStateDiscrete({ + browseName: "offNormalInputNode", + enumStrings: stringStateArray, + value: 1, + }); + + const normalStateNode = namespace.addMultiStateDiscrete({ + browseName: "normalStateNode", + enumStrings: stringStateArray, + componentOf: showcaseAC, + value: 1, + accessLevel: 3, + userAccessLevel: 3, + }); + + const offnormalAlarm = namespace.instantiateOffNormalAlarm({ + browseName: "SensorOffNormalAlarm", + conditionSource: showcaseAC, + componentOf: showcaseAC, + inputNode: multiStateDiscreteNode, + normalState: normalStateNode, + }); + + offnormalAlarm.retain.setValueFromSource({ + value: true, + dataType: DataType.Boolean, + }); + + setInterval(() => { + let randomIdx = Math.floor(Math.random() * stringStateArray.length); + if (randomIdx != 1) { + offnormalAlarm.severity.setValueFromSource({ + value: 600, + dataType: DataType.UInt16, + }); + } else { + offnormalAlarm.severity.setValueFromSource({ + value: 200, + dataType: DataType.UInt16, + }); + } + normalStateNode.setValueFromSource({ + value: randomIdx, + dataType: DataType.UInt32, + }); + }, 60000); + + const ownEventType = namespace.addEventType({ + browseName: "ownNonExclusiveLimitAlarmType", + subtypeOf: "NonExclusiveLimitAlarmType", + isAbstract: false, + }); + + const alarm = namespace.instantiateNonExclusiveLimitAlarm(ownEventType, { + browseName: "MyVarNonExclusiveLimitAlarm", + conditionName: "MyVarNonExclusiveLimitAlarm", + componentOf: showcaseAC, + conditionSource: myVar, + highHighLimit: 50.0, + highLimit: 40.0, + inputNode: myVar, + lowLimit: 20.0, + lowLowLimit: -5.0, + }); + + alarm.retain.setValueFromSource({ + value: true, + dataType: DataType.Boolean, + }); + + const alarmConfirmable = namespace.instantiateNonExclusiveLimitAlarm( + ownEventType, + { + browseName: "MyVarConfirmableNonExclusiveLimitAlarm", + conditionName: "MyVarConfirmableNonExclusiveLimitAlarm", + componentOf: showcaseAC, + conditionSource: myVar, + highHighLimit: 50.0, + highLimit: 40.0, + inputNode: myVar, + lowLimit: 20.0, + lowLowLimit: -5.0, + optionals: ["ConfirmedState", "Confirm"], + }, + ); + + alarmConfirmable.retain.setValueFromSource({ + value: true, + dataType: DataType.Boolean, + }); + + const ownEventType2 = namespace.addEventType({ + browseName: "ownExclusiveLimitAlarmType", + subtypeOf: "ExclusiveLimitAlarmType", + isAbstract: false, + }); + + const alarm2 = namespace.instantiateExclusiveLimitAlarm(ownEventType2, { + browseName: "MyVarExclusiveLimitAlarm", + conditionName: "MyVarExclusiveLimitAlarm", + componentOf: showcaseAC, + conditionSource: myVar, + highHighLimit: 50.0, + highLimit: 40.0, + inputNode: myVar, + lowLimit: 20.0, + lowLowLimit: -5.0, + }); + + alarm2.retain.setValueFromSource({ + value: true, + dataType: DataType.Boolean, + }); + + const alarm2Confirmable = namespace.instantiateExclusiveLimitAlarm( + ownEventType2, + { + browseName: "MyVarConfirmableExclusiveLimitAlarm", + conditionName: "MyVarConfirmableExclusiveLimitAlarm", + componentOf: showcaseAC, + conditionSource: myVar, + highHighLimit: 50.0, + highLimit: 40.0, + inputNode: myVar, + lowLimit: 20.0, + lowLowLimit: -5.0, + optionals: ["ConfirmedState", "Confirm"], + }, + ); + + alarm2Confirmable.retain.setValueFromSource({ + value: true, + dataType: DataType.Boolean, + }); + + /* Showcase: Historical Access */ - const showcaseHA = namespace.addObject({ - browseName: 'HistoricalAccess', - organizedBy: showcaseFolder, - }) - - const myHistoricalVar = namespace.addVariable({ - browseName: 'MyHistoricalVar', - componentOf: showcaseHA, - dataType: DataType.Double, - userAccessLevel: 'CurrentRead' - }) - - let setpoint = 50 - let myDeg = 0 - let actual = 0 - - const myHistoricalSetpointVar = namespace.addVariable({ - browseName: 'MyHistoricalSetpointVar', - componentOf: showcaseHA, - dataType: DataType.Double, - userAccessLevel: 'CurrentRead | CurrentWrite', - value: { - get: function(this: UAVariable): Variant { - return new Variant({ - value: setpoint, - dataType: DataType.Double - }) - }, - set: function(this: UAVariable, value: Variant): StatusCode { - setpoint = value.value - return StatusCodes.Good - } - }, - minimumSamplingInterval: 1000, - }) - - setInterval(() => { - myHistoricalSetpointVar.setValueFromSource(new Variant({ - value: setpoint, - dataType: DataType.Double - }) - ) - }, 5000) - - setInterval(()=>{ - myDeg+=1 - if (myDeg >= 360) { - myDeg = 0; - } - actual = Math.sin(myDeg) + setpoint - myHistoricalVar.setValueFromSource(new Variant({ - value: actual, - dataType: DataType.Double - }) - ) - }, 1000) - - addressSpace?.installHistoricalDataNode(myHistoricalVar, { - maxOnlineValues: 10000, - }) - - addressSpace?.installHistoricalDataNode(myHistoricalSetpointVar, { - maxOnlineValues: 2000, - }) - - /* + const showcaseHA = namespace.addObject({ + browseName: "HistoricalAccess", + organizedBy: showcaseFolder, + }); + + const myHistoricalVar = namespace.addVariable({ + browseName: "MyHistoricalVar", + componentOf: showcaseHA, + dataType: DataType.Double, + userAccessLevel: "CurrentRead", + }); + + let setpoint = 50; + let myDeg = 0; + let actual = 0; + + const myHistoricalSetpointVar = namespace.addVariable({ + browseName: "MyHistoricalSetpointVar", + componentOf: showcaseHA, + dataType: DataType.Double, + userAccessLevel: "CurrentRead | CurrentWrite", + value: { + get: function (this: UAVariable): Variant { + return new Variant({ + value: setpoint, + dataType: DataType.Double, + }); + }, + set: function (this: UAVariable, value: Variant): StatusCode { + setpoint = value.value; + return StatusCodes.Good; + }, + }, + minimumSamplingInterval: 1000, + }); + + setInterval(() => { + myHistoricalSetpointVar.setValueFromSource( + new Variant({ + value: setpoint, + dataType: DataType.Double, + }), + ); + }, 5000); + + setInterval(() => { + myDeg += 1; + if (myDeg >= 360) { + myDeg = 0; + } + actual = Math.sin(myDeg) + setpoint; + myHistoricalVar.setValueFromSource( + new Variant({ + value: actual, + dataType: DataType.Double, + }), + ); + }, 1000); + + addressSpace?.installHistoricalDataNode(myHistoricalVar, { + maxOnlineValues: 10000, + }); + + addressSpace?.installHistoricalDataNode(myHistoricalSetpointVar, { + maxOnlineValues: 2000, + }); + + /* Showcase: State Machines Part 16 State Machines https://reference.opcfoundation.org/Core/docs/Part16/ */ - const showcaseSta = namespace.addObject({ - browseName: 'StateMachines', - organizedBy: showcaseFolder, - rolePermissions: ServerRolePermissionGroup.DEFAULT, - }) - - await createMyFiniteStateMachineType(addressSpace) - - const myFiniteStateMachine = namespace.findObjectType('MyFiniteStateMachineType')! - - const demoFiniteStateMachineTypeInstance = myFiniteStateMachine.instantiate({ - displayName: 'MyFiniteStateMachineTypeInstance', - browseName: 'MyFiniteStateMachineTypeInstance', - componentOf: showcaseSta, - optionals: [ - 'AvailableStates', - 'AvailableTransitions' - ] - }) - - const demoFiniteStateMachine = promoteToStateMachine(demoFiniteStateMachineTypeInstance) - - const states = demoFiniteStateMachine.getStates() - const statesNodeIds = states.map((value: UAState, index: number, array: UAState[]) => { - return value.nodeId - }) - const availableStates = demoFiniteStateMachine.getChildByName('AvailableStates') as UAVariable - availableStates.setValueFromSource({ - value: statesNodeIds, - dataType: DataType.NodeId - }) - - const transitions = demoFiniteStateMachine.getTransitions() - const transitionsNodeIds = transitions.map((value: UATransitionEx, index: number, array: UATransitionEx[]) => { - return value.nodeId - }) - const availableTransitions = demoFiniteStateMachine.getChildByName('AvailableTransitions') as UAVariable - availableTransitions.setValueFromSource({ - value: transitionsNodeIds, - dataType: DataType.NodeId - }) - - const stateArray = ['Initializing', 'Idle', 'Prepare', 'Processing', 'Done'] - const transitionArray = [] - - demoFiniteStateMachine.setState('Initializing') - - let stateCount = 0 - - setInterval(() => { - stateCount++ - if (stateCount >= stateArray.length) { - stateCount = 1 - demoFiniteStateMachine.setState(stateArray[stateCount]) - } else { - demoFiniteStateMachine.setState(stateArray[stateCount]) - } - }, 10000) - - /* + const showcaseSta = namespace.addObject({ + browseName: "StateMachines", + organizedBy: showcaseFolder, + rolePermissions: ServerRolePermissionGroup.DEFAULT, + }); + + await createMyFiniteStateMachineType(addressSpace); + + const myFiniteStateMachine = namespace.findObjectType( + "MyFiniteStateMachineType", + )!; + + const demoFiniteStateMachineTypeInstance = myFiniteStateMachine.instantiate({ + displayName: "MyFiniteStateMachineTypeInstance", + browseName: "MyFiniteStateMachineTypeInstance", + componentOf: showcaseSta, + optionals: ["AvailableStates", "AvailableTransitions"], + }); + + const demoFiniteStateMachine = promoteToStateMachine( + demoFiniteStateMachineTypeInstance, + ); + + const states = demoFiniteStateMachine.getStates(); + const statesNodeIds = states.map( + (value: UAState, index: number, array: UAState[]) => { + return value.nodeId; + }, + ); + const availableStates = demoFiniteStateMachine.getChildByName( + "AvailableStates", + ) as UAVariable; + availableStates.setValueFromSource({ + value: statesNodeIds, + dataType: DataType.NodeId, + }); + + const transitions = demoFiniteStateMachine.getTransitions(); + const transitionsNodeIds = transitions.map( + (value: UATransitionEx, index: number, array: UATransitionEx[]) => { + return value.nodeId; + }, + ); + const availableTransitions = demoFiniteStateMachine.getChildByName( + "AvailableTransitions", + ) as UAVariable; + availableTransitions.setValueFromSource({ + value: transitionsNodeIds, + dataType: DataType.NodeId, + }); + + const stateArray = ["Initializing", "Idle", "Prepare", "Processing", "Done"]; + const transitionArray = []; + + demoFiniteStateMachine.setState("Initializing"); + + let stateCount = 0; + + setInterval(() => { + stateCount++; + if (stateCount >= stateArray.length) { + stateCount = 1; + demoFiniteStateMachine.setState(stateArray[stateCount]); + } else { + demoFiniteStateMachine.setState(stateArray[stateCount]); + } + }, 10000); + + /* Showcase: Programs Part 10 Programs https://reference.opcfoundation.org/Core/docs/Part10/ */ - - // const showcasePrg = namespace.addObject({ - // browseName: 'Programs', - // organizedBy: showcaseFolder, - // rolePermissions: ServerRolePermissionGroup.RESTRICTED, - // }) - // const prgObjectType = addressSpace?.findNode(`ns=0;i=2391`) as UAObjectType + // const showcasePrg = namespace.addObject({ + // browseName: 'Programs', + // organizedBy: showcaseFolder, + // rolePermissions: ServerRolePermissionGroup.RESTRICTED, + // }) - // const demoPrg = prgObjectType?.instantiate({ - // displayName: 'DemoProgram', - // browseName: 'DemoProgram', - // componentOf: showcasePrg, - // optionals: [] - // }) + // const prgObjectType = addressSpace?.findNode(`ns=0;i=2391`) as UAObjectType - // const demoPrgPromo = promoteToStateMachine(demoPrg) + // const demoPrg = prgObjectType?.instantiate({ + // displayName: 'DemoProgram', + // browseName: 'DemoProgram', + // componentOf: showcasePrg, + // optionals: [] + // }) - // demoPrgPromo.setState('Ready') - // setTimeout(()=>{ - // demoPrgPromo.setState('Running') - // },5000) + // const demoPrgPromo = promoteToStateMachine(demoPrg) + // demoPrgPromo.setState('Ready') + // setTimeout(()=>{ + // demoPrgPromo.setState('Running') + // },5000) - /* + /* DEV: Testspace!!! */ - const dev = namespace.addObject({ - browseName: 'DEV', - organizedBy: addressSpace.rootFolder.objects, - rolePermissions: ServerRolePermissionGroup.DEFAULT, - }) - - const testView1 = namespace.addView({ - browseName: 'developer-view', - organizedBy: addressSpace?.rootFolder.views - }) - - testView1.addReference({ - referenceType: 'Organizes', - nodeId: dev.nodeId - }) - - testView1.addReference({ - referenceType: 'Organizes', - nodeId: showcaseSta.nodeId - }) - - // testView1.addReference({ - // referenceType: 'Organizes', - // nodeId: showcasePrg.nodeId - // }) -} + const dev = namespace.addObject({ + browseName: "DEV", + organizedBy: addressSpace.rootFolder.objects, + rolePermissions: ServerRolePermissionGroup.DEFAULT, + }); + + const testView1 = namespace.addView({ + browseName: "developer-view", + organizedBy: addressSpace?.rootFolder.views, + }); + + testView1.addReference({ + referenceType: "Organizes", + nodeId: dev.nodeId, + }); + + testView1.addReference({ + referenceType: "Organizes", + nodeId: showcaseSta.nodeId, + }); + + // testView1.addReference({ + // referenceType: 'Organizes', + // nodeId: showcasePrg.nodeId + // }) +}; diff --git a/src/test/test.ts b/src/test/test.ts index 988b365f..42f644e5 100644 --- a/src/test/test.ts +++ b/src/test/test.ts @@ -12,36 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { describe, it } from 'mocha' +import { describe, it } from "mocha"; -import { - OPCUAServer, -} from 'node-opcua' +import { OPCUAServer } from "node-opcua"; -import { config } from './../config' +import { config } from "./../config"; -describe('following tests are for renovate dependency updates:', function () { - this.timeout(15000); - let server: OPCUAServer - after(function (done) { - if (server) { - server.shutdown(() => { - done() - }); - } else { - done() - } - }) +describe("following tests are for renovate dependency updates:", function () { + this.timeout(15000); + let server: OPCUAServer; + after(function (done) { + if (server) { + server.shutdown(() => { + done(); + }); + } else { + done(); + } + }); - it('should start the OPCUAServer', (done) => { - server = new OPCUAServer(config) - server.initialize() - server.start( - () => { - setTimeout(done, 10000) - } - ) - console.log(" --> server is running for 10s... ") - - }) -}) \ No newline at end of file + it("should start the OPCUAServer", (done) => { + server = new OPCUAServer(config); + server.initialize(); + server.start(() => { + setTimeout(done, 10000); + }); + console.log(" --> server is running for 10s... "); + }); +}); diff --git a/src/user.ts b/src/user.ts index fb020ccc..ea75890f 100644 --- a/src/user.ts +++ b/src/user.ts @@ -12,31 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { readFileSync } from 'fs'; -import { compare } from 'bcrypt'; -import yargs from 'yargs'; -import { - NodeId, - makeRoles -} from 'node-opcua'; -import { User } from './utils/userfile'; -import { green, red } from './utils/log'; +import { readFileSync } from "fs"; +import { compare } from "bcrypt"; +import yargs from "yargs"; +import { NodeId, makeRoles } from "node-opcua"; +import { User } from "./utils/userfile"; +import { green, red } from "./utils/log"; -const argv = yargs(process.argv.slice(2)).options({ - ip: { type: 'string' }, - port: { type: 'number' }, - configpath: { type: 'string' }, -}).parseSync(); +const argv = yargs(process.argv.slice(2)) + .options({ + ip: { type: "string" }, + port: { type: "number" }, + configpath: { type: "string" }, + }) + .parseSync(); const configPath: string = process.env.CONFIGPATH || argv.configpath || ""; const userFile: string = "user.json"; -const userList: User[] = Object.freeze(JSON.parse( - readFileSync(configPath + userFile, 'utf-8') -).users); +const userList: User[] = Object.freeze( + JSON.parse(readFileSync(configPath + userFile, "utf-8")).users, +); const getUser = (username: String, users: User[]): User | null => { - const user: User[] = users.filter(item => { + const user: User[] = users.filter((item) => { if (item.username === username) { return item; } @@ -49,7 +48,11 @@ const getUser = (username: String, users: User[]): User | null => { return user[0]; }; -export const isValidUserAsync = (username: string, password: string, callback:(err: Error | null, isAuthorized?: boolean) => void) => { +export const isValidUserAsync = ( + username: string, + password: string, + callback: (err: Error | null, isAuthorized?: boolean) => void, +) => { const user = getUser(username, userList); if (user) { compare(password, String(user.password), (err, result) => { @@ -62,11 +65,11 @@ export const isValidUserAsync = (username: string, password: string, callback:(e } }); } else { - red(' User:unknown rejected! '); + red(" User:unknown rejected! "); callback(null, false); } }; export const getUserRoles = (username: string): NodeId[] => { - return makeRoles(getUser(username, userList)?.roles || ''); + return makeRoles(getUser(username, userList)?.roles || ""); }; diff --git a/src/utils/log.ts b/src/utils/log.ts index 05e7936a..f7e6bc56 100644 --- a/src/utils/log.ts +++ b/src/utils/log.ts @@ -12,49 +12,46 @@ // See the License for the specific language governing permissions and // limitations under the License. -import fs from 'fs' -import { - green as g, - yellow as y, - red as r -} from 'chalk' +import fs from "fs"; +import { green as g, yellow as y, red as r } from "chalk"; const logToFile = (msg: string) => { - let date = new Date() - fs.appendFile('log.txt', `${date.toISOString().slice(0, 19)}: ${msg} \r\n`, (err) => { - if (err) return console.log(err) - }) -} + let date = new Date(); + fs.appendFile( + "log.txt", + `${date.toISOString().slice(0, 19)}: ${msg} \r\n`, + (err) => { + if (err) return console.log(err); + }, + ); +}; interface LoggerInterface { - green(msg:String): void - yellow(msg:String): void - red(msg:String): void + green(msg: String): void; + yellow(msg: String): void; + red(msg: String): void; } class Logger implements LoggerInterface { - - constructor () { - - } - - green(msg:string): void { - logToFile(msg) - console.log(' LOG: ', g(msg)) - } - - yellow (msg:string): void { - logToFile(msg) - console.log(' LOG: ', y(msg)) - } - - red (msg:string): void { - logToFile(msg) - console.log(' LOG: ', r(msg)) - } + constructor() {} + + green(msg: string): void { + logToFile(msg); + console.log(" LOG: ", g(msg)); + } + + yellow(msg: string): void { + logToFile(msg); + console.log(" LOG: ", y(msg)); + } + + red(msg: string): void { + logToFile(msg); + console.log(" LOG: ", r(msg)); + } } -export const logger = new Logger() -export const green = logger.green -export const yellow = logger.yellow -export const red = logger.red +export const logger = new Logger(); +export const green = logger.green; +export const yellow = logger.yellow; +export const red = logger.red; diff --git a/src/utils/userfile.ts b/src/utils/userfile.ts index 97bd2359..4371320b 100644 --- a/src/utils/userfile.ts +++ b/src/utils/userfile.ts @@ -12,33 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { writeFileSync } from 'fs' -import { hashSync, genSaltSync } from 'bcrypt' +import { writeFileSync } from "fs"; +import { hashSync, genSaltSync } from "bcrypt"; export interface User { - username: string, - password: string, - roles: string, + username: string; + password: string; + roles: string; } export class UserFile { - private userList: User[] = [] + private userList: User[] = []; - constructor(userList: User[] = []) { - this.userList = userList; - } + constructor(userList: User[] = []) { + this.userList = userList; + } - public addUser(user: User): void { - this.userList.push(Object.freeze({ - username: user.username, - roles: user.roles, - password: hashSync(user.password, genSaltSync()) - })) - } + public addUser(user: User): void { + this.userList.push( + Object.freeze({ + username: user.username, + roles: user.roles, + password: hashSync(user.password, genSaltSync()), + }), + ); + } - public createUserFile(path: string): void { - writeFileSync(path, JSON.stringify({ - users: this.userList - })) - } -} \ No newline at end of file + public createUserFile(path: string): void { + writeFileSync( + path, + JSON.stringify({ + users: this.userList, + }), + ); + } +} diff --git a/tsconfig.json b/tsconfig.json index e4f90b76..ca5fc839 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,8 +4,8 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "CommonJS", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "CommonJS" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, // "lib": ["es2015","es2015.promise"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ @@ -14,25 +14,25 @@ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./dst", /* Redirect output structure to the directory. */ + "outDir": "./dst" /* Redirect output structure to the directory. */, // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - "removeComments": true, /* Do not emit comments to output. */ + "removeComments": true /* Do not emit comments to output. */, // "noEmit": true, /* Do not emit outputs. */ // "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - "strictNullChecks": true, /* Enable strict null checks. */ - "strictFunctionTypes": true, /* Enable strict checking of function types. */ - "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, + "strictNullChecks": true /* Enable strict null checks. */, + "strictFunctionTypes": true /* Enable strict checking of function types. */, + "strictBindCallApply": true /* Enable strict 'bind', 'call', and 'apply' methods on functions. */, + "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */, + "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */, + "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ @@ -44,11 +44,16 @@ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - "rootDirs": ["./src", "./tests"], /* List of root folders whose combined content represents the structure of the project at runtime. */ + "rootDirs": [ + "./src", + "./tests" + ] /* List of root folders whose combined content represents the structure of the project at runtime. */, // "typeRoots": [], /* List of folders to include type definitions from. */ - "types": ["node"], /* Type declaration files to be included in compilation. */ + "types": [ + "node" + ] /* Type declaration files to be included in compilation. */, // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ @@ -63,7 +68,7 @@ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ - "skipLibCheck": true, /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ } } diff --git a/user.json b/user.json index a60d968e..e996d257 100644 --- a/user.json +++ b/user.json @@ -1,19 +1,19 @@ { - "users": [ - { - "username":"admin", - "password":"$2b$10$FJiv97xU3a7xIKQvW/VFNemJ6npESrv2iIrmltO62N5ItQTvFVu.W", - "roles":"Supervisor;ConfigureAdmin;SecurityAdmin" - }, - { - "username":"operator", - "password":"$2b$10$BUbEWHRR5HU2g0Wmqu690.q.LgqNYfa./yOv25dubZxQX0Tj6mG7O", - "roles":"Operator;ConfigureAdmin" - }, - { - "username":"guest", - "password":"$2b$10$rNxw5OKrvg1D8Wlm1Ar4TuE/POcimfrNqvBCxthqs/9JB6ELn3iHO", - "roles":"AuthenticatedUser" - } - ] -} \ No newline at end of file + "users": [ + { + "username": "admin", + "password": "$2b$10$FJiv97xU3a7xIKQvW/VFNemJ6npESrv2iIrmltO62N5ItQTvFVu.W", + "roles": "Supervisor;ConfigureAdmin;SecurityAdmin" + }, + { + "username": "operator", + "password": "$2b$10$BUbEWHRR5HU2g0Wmqu690.q.LgqNYfa./yOv25dubZxQX0Tj6mG7O", + "roles": "Operator;ConfigureAdmin" + }, + { + "username": "guest", + "password": "$2b$10$rNxw5OKrvg1D8Wlm1Ar4TuE/POcimfrNqvBCxthqs/9JB6ELn3iHO", + "roles": "AuthenticatedUser" + } + ] +}