我想浏览OPC UA服务器上的特定节点并使用其方法。 我使用 open62541 堆栈,我想使用自制客户端。我的客户端连接到服务器,然后我使用给定的示例浏览一些对象。它向我展示了根文件夹之后的第一层节点- 如何找到特定节点?还是我必须浏览到这一点?open62541 项目中是否有一个我看不到会让我大开眼界的示例文件?
我也发现该方法"Service_TranslateBrowsePathsToNodeIds",但我不太确定如何以正确的方式使用它以及哪一部分对我来说很有趣。
举个例子: 我想浏览节点"文件系统",它位于比根文件夹更深的层中,并希望使用其方法 createFile。
若要调用方法,需要两个节点 ID:
- 包含方法的对象节点 ID
- 方法节点标识
如果已有这些节点 ID,则可以立即调用该方法。如果没有, OPC UA通常支持两个选项来获取这些节点ID:
-
从根节点 (
ns=0;i=84
( 开始,递归浏览所有子节点,直到找到具有特定浏览名称的节点。 https://github.com/open62541/open62541/blob/58bd161557111847d068650eff5ad670a9aa0395/examples/client.c#L61 -
如果您有浏览路径,请使用
TranslateBrowsePathsToNodeIds
服务。 即,将/Objects/MyDevice/FileSystem/UploadFile
(浏览名称的串联(与起始节点 Root (ns=0;i=84
( 一起提供,服务器将返回该特定节点的节点 ID(如果存在(。此服务采用相对路径,因此您也可以使用其他节点作为开始节点 https://github.com/open62541/open62541/blob/58bd161557111847d068650eff5ad670a9aa0395/examples/client_async.c#L183
经过一些试验和错误,我发现了"神奇"位,使其与服务器命名空间中的节点一起工作,例如真实设备而不是预定义的 UA 节点,如时间戳或服务器状态,如所有示例所示。下面的代码派生自 Open62541 的 corpus_generator.c 和 check_services_view.c 文件,但有 2 个主要区别:
- 您不必指定引用类型 ID。
- 创建字符串时,请将它们放在服务器命名空间中,而不是 UA 命名空间中(请参阅下面的UA_QUALIFIEDNAME_ALLOC(。
下面的函数将采用指向UA_Client的指针和构成节点路径的浏览名称向量,从 OPC-UA 中的"对象"文件夹开始。
Node::Node (UA_Client *client, const std::vector<std::string> &browse_path)
: m_client (client)
{
m_id = UA_NODEID_NULL;
// Search for ID in client
UA_BrowsePath browsePath;
UA_BrowsePath_init (&browsePath);
browsePath.startingNode = UA_NODEID_NUMERIC (0, UA_NS0ID_OBJECTSFOLDER);
browsePath.relativePath.elements = (UA_RelativePathElement *)UA_Array_new (browse_path.size (), &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT]);
browsePath.relativePath.elementsSize = browse_path.size ();
for (int i = 0; i < browse_path.size (); i++)
{
UA_RelativePathElement *elem = &browsePath.relativePath.elements[i];
elem->targetName = UA_QUALIFIEDNAME_ALLOC (1, browse_path.at (i).c_str ()); // Create in server namespace (1), not UA namespace (0)!
}
UA_TranslateBrowsePathsToNodeIdsRequest request;
UA_TranslateBrowsePathsToNodeIdsRequest_init (&request);
request.browsePaths = &browsePath;
request.browsePathsSize = 1;
UA_TranslateBrowsePathsToNodeIdsResponse response;
response = UA_Client_Service_translateBrowsePathsToNodeIds (m_client, request);
if (UA_STATUSCODE_GOOD == response.responseHeader.serviceResult && response.resultsSize > 0)
{
UA_BrowsePathResult *first = response.results;
if (first->targetsSize >= 1)
{
m_id = first->targets[0].targetId.nodeId;
std::cout << "Found ID";
}
else
{
std::cout << "OK response but no results";
}
}
else
{
std::cout << "Error in translate browsename";
}
UA_BrowsePath_deleteMembers (&browsePath); // Marked as deprecated, but UA_BrowsePath_delete() expects a heap-allocated pointer.
UA_TranslateBrowsePathsToNodeIdsResponse_deleteMembers (&response); // Idem
}