1

I want to browse a specific node on my OPC UA Server and use its method. I use the open62541 stack and i want to use a selfmade client. My Client connects to the Server and then i use the given example to browse some Objects. It shows me the first layer of nodes after the root-folder- How can i find a specific node? Or have i to browse to this point? Is there an example file in the open62541 project which i don't see that would open my eyes?

I also find the Method "Service_TranslateBrowsePathsToNodeIds" but i'm not quite sure how to use it the right way and which part is interesting for me.

As an example: I want to browse the Node "FileSystem", which is in a deeper layer than the root-folder, and want to use its Method createFile.

opc_rookie
  • 37
  • 2
  • 6

2 Answers2

2

To call a method, you need two node ids:

  • Object node id which contains the method
  • Method node id

If you already have these node ids, you can call the method right away. If not, OPC UA in general supports two options to get these node ids:

Stefan Profanter
  • 6,458
  • 6
  • 41
  • 73
0

After some trial and error I found the 'magic' bits to get it working with nodes that are in the server namespace, e.g. of real devices and not pre-defined UA nodes like timestamp or server status as shown in all examples. The code below is derived from the corpus_generator.c and check_services_view.c files of Open62541 with 2 key differences:

  • You do not have to specify the referenceTypeId.
  • When creating the strings, place them in the server namespace, not UA namespace (see UA_QUALIFIEDNAME_ALLOC below).

The function below will take a pointer to UA_Client and a vector of browsenames that form the path to the node, starting at the Objects folder in 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
}
JvO
  • 3,036
  • 2
  • 17
  • 32