open62541 浏览节点并使用其方法
open62541 browsing nodes an using its methods
我想浏览我的 OPC UA 服务器上的特定节点并使用它的方法。
我使用 open62541 堆栈,我想使用自制客户端。我的客户端连接到服务器,然后我使用给定的示例 to browse some Objects。它向我展示了根文件夹之后的第一层节点-
我怎样才能找到一个特定的节点?或者我必须浏览到这一点吗? open62541 项目中是否有一个我看不到的示例文件会让我大开眼界?
我也找到了方法 "Service_TranslateBrowsePathsToNodeIds",但我不太确定如何正确使用它以及我对哪一部分感兴趣。
举个例子:
我想浏览节点 "FileSystem",比根文件夹更深一层,并想使用它的方法 createFile。
要调用方法,需要两个节点id:
- 包含方法的对象节点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
) 并且服务器将 return 您该特定节点的节点 ID(如果它存在)。此服务采用相对路径,因此您也可以使用其他节点作为起始节点
https://github.com/open62541/open62541/blob/58bd161557111847d068650eff5ad670a9aa0395/examples/client_async.c#L183
经过反复试验,我发现 'magic' 位可以使其与服务器名称空间中的节点一起工作,例如真实设备的数量,而不是 pre-defined UA 节点,如所有示例中所示的时间戳或服务器状态。下面的代码源自 Open62541 的 corpus_generator.c 和 check_services_view.c 文件,有两个主要区别:
- 您不必指定 referenceTypeId。
- 创建字符串时,将它们放在 server 命名空间中,而不是 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
}
我想浏览我的 OPC UA 服务器上的特定节点并使用它的方法。 我使用 open62541 堆栈,我想使用自制客户端。我的客户端连接到服务器,然后我使用给定的示例 to browse some Objects。它向我展示了根文件夹之后的第一层节点- 我怎样才能找到一个特定的节点?或者我必须浏览到这一点吗? open62541 项目中是否有一个我看不到的示例文件会让我大开眼界?
我也找到了方法 "Service_TranslateBrowsePathsToNodeIds",但我不太确定如何正确使用它以及我对哪一部分感兴趣。
举个例子: 我想浏览节点 "FileSystem",比根文件夹更深一层,并想使用它的方法 createFile。
要调用方法,需要两个节点id:
- 包含方法的对象节点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
) 并且服务器将 return 您该特定节点的节点 ID(如果它存在)。此服务采用相对路径,因此您也可以使用其他节点作为起始节点 https://github.com/open62541/open62541/blob/58bd161557111847d068650eff5ad670a9aa0395/examples/client_async.c#L183
经过反复试验,我发现 'magic' 位可以使其与服务器名称空间中的节点一起工作,例如真实设备的数量,而不是 pre-defined UA 节点,如所有示例中所示的时间戳或服务器状态。下面的代码源自 Open62541 的 corpus_generator.c 和 check_services_view.c 文件,有两个主要区别:
- 您不必指定 referenceTypeId。
- 创建字符串时,将它们放在 server 命名空间中,而不是 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
}