使用 node-opcua 调用带有结构输入参数的 OPCUA 方法
Call OPCUA method with struct input argument using node-opcua
我正在尝试与根据 this specification.
实施 OPC-UA 服务器的 RFID reader 接口
我正在尝试调用将 ScanSettings struct 作为输入参数(AutoID 数据类型)的 ScanStart 方法,但尽管通读了示例和文档,我仍无法找到执行此操作的方法。
我可以使用 UAExpert 调用方法并使用 GUI 输入结构的值,这会在 wireshark 中生成以下转储:
ArraySize: 1
[0]: Variant
Variant Type: ExtensionObject (0x16)
Value: ExtensionObject
TypeId: ExpandedNodeId
EncodingMask: 0x01, EncodingMask: Four byte encoded Numeric
.... 0001 = EncodingMask: Four byte encoded Numeric (0x1)
.0.. .... = has server index: False
0... .... = has namespace uri: False
Namespace Index: 3
Identifier Numeric: 5015
EncodingMask: 0x01, has binary body
.... ...1 = has binary body: True
.... ..0. = has xml body: False
ByteString: 0000000000000000000000000000000000
有没有人成功地注册了一个 ExtensionObject 以传递给使用 node-opcua 的方法调用?在这一点上,我很高兴只发送上面的 ByteString,而不需要 encode/decode 结构,因为它始终是静态的。
显然有一个 constructExtensionObject 方法。我的客户端代码是:
(async () => {
const client = OPCUAClient.create({ endpoint_must_exist: false});
client.on("backoff", () => console.log("Backoff: trying to connect to ", endpointUri));
await client.withSessionAsync(endpointUri, async (session) => {
let scanSettings = {
Duration: 0,
Cyles: 0,
DataAvailble: false
};
const nodeID = new NodeId(NodeIdType.STRING, "rfr310.ScanStart.InputArguments", 4);
const extObj = session.constructExtensionObject(nodeID, scanSettings);
const methodsToCall = [
{
objectId: "ns=4;s=rfr310",
methodId: "ns=4;s=rfr310.ScanStart",
inputArguments: [extObj]
}
];
extObj.then(() => {
session.call(methodsToCall,(err,results) => {
if (err) {
console.log(err);
} else {
console.log(results);
}
});
}).catch(() => {
})
});
})();
产生错误 "dispose when pendingTransactions is not empty",它被 extObj.catch()
捕获
我做错了什么?我相当确定这是我的承诺处理问题...
感谢任何帮助!
好的,我终于到了。下面是使用 node-opcua 调用带有结构输入参数的 OPC-UA 方法的方法:
const { OPCUAClient, NodeId, NodeIdType, DataType} = require("node-opcua");
const endpointUri = "opc.tcp://<your-endpoint>:<your-port>";
(async () => {
const client = OPCUAClient.create({ endpoint_must_exist: false});
client.on("backoff", () => console.log("Backoff: trying to connect to ", endpointUri));
await client.withSessionAsync(endpointUri, async (session) => {
// Scan settings value input
const scanSettingsParams = {
duration: 0,
cycles : 0,
dataAvailable : false,
locationType: 0
};
try {
// NodeID for InputArguments struct type (inherits from ScanSettings)
const nodeID = new NodeId(NodeIdType.NUMERIC, 3010, 3);
// Create ExtensionObject for InputArguments
const scanSettingsObj = await session.constructExtensionObject(nodeID, scanSettingsParams);
// Populate Method call with ExtensionObject as InputArgument
const methodToCall = {
objectId: "ns=4;s=rfr310",
methodId: "ns=4;s=rfr310.ScanStart",
inputArguments: [
{
dataType: DataType.ExtensionObject,
value: scanSettingsObj
}
]
};
// Call method, passing ScanSettings as input argument
session.call(methodToCall,(err,results) => {
if (err) {
console.log(err);
} else {
console.log(results);
}
});
} catch (err) {
console.log(err);
}
});
})();
我正在尝试与根据 this specification.
实施 OPC-UA 服务器的 RFID reader 接口我正在尝试调用将 ScanSettings struct 作为输入参数(AutoID 数据类型)的 ScanStart 方法,但尽管通读了示例和文档,我仍无法找到执行此操作的方法。
我可以使用 UAExpert 调用方法并使用 GUI 输入结构的值,这会在 wireshark 中生成以下转储:
ArraySize: 1
[0]: Variant
Variant Type: ExtensionObject (0x16)
Value: ExtensionObject
TypeId: ExpandedNodeId
EncodingMask: 0x01, EncodingMask: Four byte encoded Numeric
.... 0001 = EncodingMask: Four byte encoded Numeric (0x1)
.0.. .... = has server index: False
0... .... = has namespace uri: False
Namespace Index: 3
Identifier Numeric: 5015
EncodingMask: 0x01, has binary body
.... ...1 = has binary body: True
.... ..0. = has xml body: False
ByteString: 0000000000000000000000000000000000
有没有人成功地注册了一个 ExtensionObject 以传递给使用 node-opcua 的方法调用?在这一点上,我很高兴只发送上面的 ByteString,而不需要 encode/decode 结构,因为它始终是静态的。
显然有一个 constructExtensionObject 方法。我的客户端代码是:
(async () => {
const client = OPCUAClient.create({ endpoint_must_exist: false});
client.on("backoff", () => console.log("Backoff: trying to connect to ", endpointUri));
await client.withSessionAsync(endpointUri, async (session) => {
let scanSettings = {
Duration: 0,
Cyles: 0,
DataAvailble: false
};
const nodeID = new NodeId(NodeIdType.STRING, "rfr310.ScanStart.InputArguments", 4);
const extObj = session.constructExtensionObject(nodeID, scanSettings);
const methodsToCall = [
{
objectId: "ns=4;s=rfr310",
methodId: "ns=4;s=rfr310.ScanStart",
inputArguments: [extObj]
}
];
extObj.then(() => {
session.call(methodsToCall,(err,results) => {
if (err) {
console.log(err);
} else {
console.log(results);
}
});
}).catch(() => {
})
});
})();
产生错误 "dispose when pendingTransactions is not empty",它被 extObj.catch()
捕获我做错了什么?我相当确定这是我的承诺处理问题...
感谢任何帮助!
好的,我终于到了。下面是使用 node-opcua 调用带有结构输入参数的 OPC-UA 方法的方法:
const { OPCUAClient, NodeId, NodeIdType, DataType} = require("node-opcua");
const endpointUri = "opc.tcp://<your-endpoint>:<your-port>";
(async () => {
const client = OPCUAClient.create({ endpoint_must_exist: false});
client.on("backoff", () => console.log("Backoff: trying to connect to ", endpointUri));
await client.withSessionAsync(endpointUri, async (session) => {
// Scan settings value input
const scanSettingsParams = {
duration: 0,
cycles : 0,
dataAvailable : false,
locationType: 0
};
try {
// NodeID for InputArguments struct type (inherits from ScanSettings)
const nodeID = new NodeId(NodeIdType.NUMERIC, 3010, 3);
// Create ExtensionObject for InputArguments
const scanSettingsObj = await session.constructExtensionObject(nodeID, scanSettingsParams);
// Populate Method call with ExtensionObject as InputArgument
const methodToCall = {
objectId: "ns=4;s=rfr310",
methodId: "ns=4;s=rfr310.ScanStart",
inputArguments: [
{
dataType: DataType.ExtensionObject,
value: scanSettingsObj
}
]
};
// Call method, passing ScanSettings as input argument
session.call(methodToCall,(err,results) => {
if (err) {
console.log(err);
} else {
console.log(results);
}
});
} catch (err) {
console.log(err);
}
});
})();