-
-
Notifications
You must be signed in to change notification settings - Fork 479
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f51277e
commit 6eefed7
Showing
4 changed files
with
376 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { OPCUAClient, OPCUAServer, AttributeIds, TimestampsToReturn} from "node-opcua"; | ||
|
||
async function startServer() { | ||
|
||
const server = new OPCUAServer(); | ||
await server.initialize(); | ||
await server.start(); | ||
console.log("Server started at ", server.getEndpointUrl()); | ||
return server; | ||
} | ||
|
||
async function pause(ms) { | ||
return new Promise((resolve) => setTimeout(resolve, ms)); | ||
} | ||
|
||
(async () => { | ||
const client = OPCUAClient.create({ | ||
endpointMustExist: false, | ||
connectionStrategy: { maxRetry: 0 } | ||
}); | ||
|
||
client.on("backoff", () => console.log("keep trying to connect")); | ||
|
||
let server = await startServer(); | ||
const endpointUrl = server.getEndpointUrl(); | ||
|
||
await client.connect(endpointUrl); | ||
client.on("abort", () => console.log("client has aborted")); | ||
client.on("close", () => console.log("client has closed")); | ||
client.on("connection_reestablished", () => console.log("client has reconnected")); | ||
client.on("connection_lost", () => console.log("client has lost connection")); | ||
client.on("start_reconnection", () => console.log("client is trying to reconnect")); | ||
client.on("after_reconnection", () => console.log("client start reconnection")); | ||
|
||
|
||
|
||
const session = await client.createSession(); | ||
session.on("session_closed", () => console.log("session has closed")); | ||
session.on("keepalive", () => console.log("session keepalive")); | ||
session.on("keepalive_failure", () => console.log("session keepalive failure")); | ||
|
||
await pause(1000); | ||
await server.shutdown(); | ||
client.on("close", ()=>{ | ||
|
||
client.connect(endpointUrl); | ||
|
||
}) | ||
await pause(1000); | ||
server = await startServer(); | ||
await pause(1000); | ||
|
||
const dataValue = await session.read({ nodeId: "i=2258", attributeId: AttributeIds.Value }); | ||
console.log(dataValue.toString()); | ||
|
||
await session.close(); | ||
await client.disconnect(); | ||
|
||
|
||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
// @ts-check | ||
import { OPCUAServer, coerceQualifiedName, nodesets } from "node-opcua"; | ||
/// <reference types="node-opcua" /> | ||
|
||
/** | ||
* @param {import("node-opcua").IAddressSpace} addressSpace | ||
*/ | ||
async function constructAddressSpace(addressSpace) { | ||
|
||
// https://reference.opcfoundation.org/Machinery/v102/docs/6 | ||
|
||
const namespace = addressSpace.getOwnNamespace(); | ||
|
||
const nsDI = addressSpace.getNamespaceIndex("http://opcfoundation.org/UA/DI/"); | ||
if (nsDI === -1) { | ||
throw new Error("Cannot find namespace for DI"); | ||
} | ||
const deviceSet = addressSpace.rootFolder.objects.getFolderElementByName("DeviceSet", nsDI); | ||
if (!deviceSet) { | ||
throw new Error("Cannot find DeviceSet"); | ||
} | ||
|
||
const nsMachinery = addressSpace.getNamespaceIndex("http://opcfoundation.org/UA/Machinery/"); | ||
if (nsMachinery === -1) { | ||
throw new Error("Cannot find namespace for Machinery"); | ||
} | ||
const nsMachineTool = addressSpace.getNamespaceIndex("http://opcfoundation.org/UA/MachineTool/"); | ||
if (nsMachineTool === -1) { | ||
throw new Error("Cannot find namespace for MachineTool"); | ||
} | ||
const machineToolType = addressSpace.findObjectType("MachineToolType", nsMachineTool); | ||
if (!machineToolType) { | ||
throw new Error("Cannot find MachineToolType"); | ||
} | ||
|
||
const machineTool = machineToolType.instantiate({ | ||
browseName: "MachineTool", | ||
organizedBy: deviceSet, | ||
optionals: ["Identification", "Components", "MachineryBuildingBlocks", "MachineryBuildingBlocks"] | ||
}); | ||
|
||
const machineryBuildingBlocks = machineTool.getComponentByName("MachineryBuildingBlocks", nsMachinery); | ||
if (!machineryBuildingBlocks) { | ||
throw new Error("Cannot find MachineryBuildingBlocks"); | ||
} | ||
|
||
const identification = machineTool.getChildByName("Identification", nsMachineTool); | ||
if (!identification) { | ||
throw new Error("Cannot find Identification"); | ||
} | ||
machineryBuildingBlocks.addReference({ | ||
referenceType: "HasAddIn", | ||
nodeId: identification | ||
}); | ||
const components = machineTool.getComponentByName("Components", nsMachinery); | ||
if (!components) { | ||
throw new Error("Cannot find MachineryBuildingBlocks.Components"); | ||
} | ||
|
||
machineryBuildingBlocks.addReference({ | ||
referenceType: "HasAddIn", | ||
nodeId: components | ||
}); | ||
|
||
// add some components | ||
const baseObjectType = addressSpace.findObjectType("BaseObjectType", 0); | ||
if (!baseObjectType) { | ||
throw new Error("Cannot find BaseObjectType"); | ||
} | ||
const component1 = baseObjectType.instantiate({ | ||
browseName: "Component1", | ||
componentOf: components | ||
}); | ||
|
||
// add some building blocks | ||
const buildingBlock1Type = namespace.addObjectType({ | ||
browseName: "BuildingBlock1Type", | ||
subtypeOf: "BaseObjectType" | ||
}); | ||
|
||
const buildingBlock1 = buildingBlock1Type.instantiate({ | ||
browseName: "BuildingBlock1", | ||
// addInOf: machineryBuildingBlocks // DOES NOT EXIST YET !! | ||
}); | ||
// ... so we create it this way | ||
machineryBuildingBlocks.addReference({ | ||
referenceType: "HasAddIn", | ||
nodeId: buildingBlock1 | ||
}); | ||
|
||
|
||
const buildingBlock2Type = namespace.addObjectType({ | ||
browseName: "BuildingBlock2Type", | ||
subtypeOf: "BaseObjectType" | ||
}); | ||
const buildingBlock2 = buildingBlock2Type.instantiate({ | ||
browseName: "BuildingBlock2", | ||
// addInOf: machineryBuildingBlocks // DOES NOT EXIST YET !! | ||
}); | ||
// ... so we create it this way | ||
machineryBuildingBlocks.addReference({ | ||
referenceType: "HasAddIn", | ||
nodeId: buildingBlock2 | ||
}); | ||
|
||
} | ||
|
||
|
||
|
||
/** | ||
* | ||
* an other flavor not use | ||
* @param {import("node-opcua").IAddressSpace} addressSpace | ||
*/ | ||
async function constructAddressSpace2(addressSpace) { | ||
|
||
// https://reference.opcfoundation.org/Machinery/v102/docs/6 | ||
|
||
const namespace = addressSpace.getOwnNamespace(); | ||
|
||
const nsDI = addressSpace.getNamespaceIndex("http://opcfoundation.org/UA/DI/"); | ||
if (nsDI === -1) { | ||
throw new Error("Cannot find namespace for DI"); | ||
} | ||
const deviceSet = addressSpace.rootFolder.objects.getFolderElementByName("DeviceSet", nsDI); | ||
if (!deviceSet) { | ||
throw new Error("Cannot find DeviceSet"); | ||
} | ||
|
||
const nsMachineTool = addressSpace.getNamespaceIndex("http://opcfoundation.org/UA/MachineTool/"); | ||
if (nsMachineTool === -1) { | ||
throw new Error("Cannot find namespace for MachineTool"); | ||
} | ||
const machineToolType = addressSpace.findObjectType("MachineToolType", nsMachineTool); | ||
if (!machineToolType) { | ||
throw new Error("Cannot find MachineToolType"); | ||
} | ||
|
||
const machineTool = machineToolType.instantiate({ | ||
browseName: "MachineTool2", | ||
organizedBy: deviceSet, | ||
}); | ||
|
||
const nsMachinery = addressSpace.getNamespaceIndex("http://opcfoundation.org/UA/Machinery/"); | ||
if (nsMachinery === -1) { | ||
throw new Error("Cannot find namespace for Machinery"); | ||
} | ||
const machineryBuildingBlocks = namespace.addObject({ | ||
browseName: {name : "MachineryBuildingBlocks", namespaceIndex: nsMachinery}, | ||
typeDefinition: "FolderType", | ||
componentOf: machineTool | ||
}); | ||
|
||
const identification = machineTool.getChildByName("Identification", nsMachineTool); | ||
if (!identification) { | ||
throw new Error("Cannot find Identification"); | ||
} | ||
machineryBuildingBlocks.addReference({ | ||
referenceType: "HasAddIn", | ||
nodeId: identification | ||
}); | ||
const components = machineTool.getComponentByName("Components", nsMachinery); | ||
} | ||
|
||
(async () => { | ||
const server = new OPCUAServer({ | ||
nodeset_filename: [ | ||
nodesets.standard, | ||
nodesets.di, | ||
nodesets.ia, | ||
nodesets.machinery, | ||
nodesets.machineTool | ||
] | ||
|
||
}); | ||
|
||
await server.initialize(); | ||
const addressSpace = server.engine.addressSpace; | ||
if (!addressSpace) { throw new Error("Internal Error"); } | ||
|
||
constructAddressSpace(addressSpace); | ||
constructAddressSpace2(addressSpace); | ||
|
||
await server.start(); | ||
console.log("Server is now listening ... ( press CTRL+C to stop)"); | ||
console.log(server.getEndpointUrl()); | ||
await new Promise((resolve) => process.once("SIGINT", resolve)); | ||
|
||
await server.shutdown(); | ||
console.log("Server has shut down"); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import * as fs from 'fs'; | ||
import { OPCUAServer, nodesets, Variant, DataType, StatusCodes } from 'node-opcua'; | ||
|
||
(async () => { | ||
|
||
const data = await fetch("https://raw.githubusercontent.com/OPCFoundation/UA-Nodeset/2f76ebcfa097cde42414bea08abf04423f30ea4e/PlasticsRubber/GeneralTypes/1.03/Opc.Ua.PlasticsRubber.GeneralTypes.NodeSet2.xml"); | ||
|
||
const filename = "./Opc.Ua.PlasticsRubber.GeneralTypes.NodeSet2.xml"; | ||
fs.writeFileSync(filename, await data.text()); | ||
|
||
const server = new OPCUAServer({ | ||
nodeset_filename: [ | ||
nodesets.standard, | ||
nodesets.di, | ||
filename | ||
] | ||
}); | ||
|
||
await server.initialize(); | ||
|
||
const addressSpace = server.engine.addressSpace; | ||
|
||
const ns = addressSpace.getNamespaceIndex("http://opcfoundation.org/UA/PlasticsRubber/GeneralTypes/"); | ||
if (ns === -1) { | ||
throw new Error("Cannot find namespace"); | ||
} | ||
|
||
const activeErrorDataType = addressSpace.findDataType("ActiveErrorDataType", ns); | ||
if (!activeErrorDataType) { | ||
throw new Error("Cannot find ActiveErrorDataType"); | ||
} | ||
|
||
const activeError = addressSpace.constructExtensionObject( | ||
activeErrorDataType, | ||
{ | ||
id: "Alarm", severity: 1, message: "abc" | ||
}); | ||
console.log(activeError.toString()); | ||
|
||
|
||
const node = addressSpace.getOwnNamespace().addVariable({ | ||
browseName: "MyVariable", | ||
dataType: activeErrorDataType, | ||
componentOf: addressSpace.rootFolder.objects.server.vendorServerInfo | ||
}); | ||
|
||
node.bindVariable({ | ||
get: () => { | ||
return new Variant({ | ||
dataType: DataType.ExtensionObject, | ||
value: activeError, | ||
statusCode: StatusCodes.Good | ||
}); | ||
} | ||
}); | ||
|
||
|
||
await server.start(); | ||
|
||
})(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import fs from "fs"; | ||
import path from "path"; | ||
import { OPCUACertificateManager } from "node-opcua"; | ||
|
||
const pkiRoot = "/tmp/pki1289"; | ||
const certificateFile = path.join(pkiRoot, "server_selfsigned_cert_2048.pem"); | ||
const selfSignedCertificatePath = certificateFile; | ||
const appName = "RpiPlc"; | ||
|
||
const data = { | ||
"applicationUri": "urn:rpi-plc-deployment-55cc7bbc64-r89h4:RpiPlc", | ||
"dns": [ | ||
"rpi-plc-deployment-55cc7bbc64-r89h4" | ||
], | ||
"outputFile": "/rpi-plc/data/.config/PKI/certificate.pem", | ||
"subject": "/CN=RpiPlc/O=TestSHome/L=Midway/C=US", | ||
"startDate": "2023-08-15T06:16:15.077Z", | ||
"validity": 3650 | ||
}; | ||
|
||
|
||
const ModuleName = ""; | ||
(async () => { | ||
|
||
|
||
console.log("starting from fresh: deleting existing pki folder") | ||
if (fs.existsSync(pkiRoot)) { | ||
fs.rmdirSync(pkiRoot, { recursive: true }); | ||
} | ||
|
||
const serverCertificateManager = new OPCUACertificateManager({ | ||
automaticallyAcceptUnknownCertificate: true, | ||
rootFolder: pkiRoot | ||
}); | ||
try { | ||
|
||
await serverCertificateManager.initialize(); | ||
|
||
if (!fs.existsSync(certificateFile)) { | ||
console.log([ModuleName, 'info'], `Creating new certificate file:`); | ||
|
||
const certFileRequest = { | ||
applicationUri: data.applicationUri, | ||
dns: data.dns, | ||
// ip: await getIpAddresses(), | ||
outputFile: selfSignedCertificatePath, | ||
subject: `/CN=${appName}/O=TestHome/L=Midway/C=US`, | ||
startDate: new Date(), | ||
validity: 365 * 10 | ||
}; | ||
|
||
console.log([ModuleName, 'info'], `Self-signed certificate file request params:\n${JSON.stringify(certFileRequest, null, 2)}\n`); | ||
|
||
await serverCertificateManager.createSelfSignedCertificate(certFileRequest); | ||
} | ||
else { | ||
console.log([ModuleName, 'info'], `Using existing certificate file at: ${certificateFile}`); | ||
} | ||
} | ||
catch (ex) { | ||
console.log(ex); | ||
console.log([ModuleName, 'error'], `Error creating server self signed certificate: ${ex.message}`); | ||
} | ||
})(); |