Professional OPC
Development Tools

logos

Recursive function for finding datanodes, not returning all datanodes

More
12 Oct 2018 04:26 #6743 by support
UPDATE: I have realized what's probably wrong.

Your code does not write out nodes that have no sub-nodes (the test "if (NodeCollection.Count > 0)"). It only writes out that is about to browse into. The part with StreamWriter should best be placed between the EasyUAClient.Browse AND the call to RecursiveBrowse (and become its own loop to go through the NodeCollection).

Best regards

Please Log in or Create an account to join the conversation.

More
11 Oct 2018 18:31 #6742 by support
This is a mystery - I do not see anything wrong with your code.

Can you please try to use our Connectivity Explorer app to view the same server? It uses the same underlying QuickOPC methods, so the purpose of this test is to determine whether "our own" code works well, or not - based on that, we will know whether to look further into your code, or elsewhere.

The Connectivity Explorer is accessible from the Start menu or the Launcher. Please locate or enter your server's URL in the Point Editor window, right-click on it, and select "Navigate: To Address Space Browser". The full address space tree should then open in its own window. Expand the nodes as needed - and let me know whether in this view, all nodes that you expect are there or not.

Best regards
The following user(s) said Thank You: CMAC447

Please Log in or Create an account to join the conversation.

More
11 Oct 2018 16:40 #6741 by CMAC447
Changes are pretty minor, mostly just using the Browse function instead of BrowseDataNodes. In the first Browse, I checked that UAObjectIds.ObjectsFolder did give me the starting set of nodes that I wanted to go deeper into.
//When a button is clicked, call this background worker
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
	UAEndpointDescriptor endpointDescriptor = "opc.tcp://" + PCNameTextBox.Text + ":4880/[SystemName]";
	UANodeElementCollection NodeCollection = new UANodeElementCollection();
	//grab the collection of nodes from our endpoint
	try
	{
		NodeCollection = CM100Client.Browse(
					endpointDescriptor,
					UAObjectIds.ObjectsFolder,
					new UABrowseParameters(UANodeClass.All, new[] { UAReferenceTypeIds.References })
					);
	}
	catch (Exception ex)
	{
		//Exception handling
	}
	RecursiveBrowse(NodeCollection, endpointDescriptor);
}
 
//Recursive function for browsing data nodes
private void RecursiveBrowse(UANodeElementCollection NodeCollection, UAEndpointDescriptor endpointDescriptor)
{
	//If it has children keep going
	if (NodeCollection.Count > 0)
	{
		//Next recursively get the data from each node on the OPC server.
		foreach (UANodeElement nodeElement in NodeCollection)
		{
			//Write to file, savepath comes from user input
			using (StreamWriter sw = new StreamWriter(Path.Combine(savepath, "[SystemName]ServerNodes.txt"), true))
			{
				sw.WriteLine("DisplayName: " + nodeElement.DisplayName);
				//Other things written to the file here
				sw.WriteLine("");
			}
			//Browse for the data nodes that are children of this one and browse deeper into the tree
			UANodeElementCollection NewNodeCollection = new UANodeElementCollection();
			try
			{
				NewNodeCollection = NewNodeCollection = CM100Client.Browse(
												endpointDescriptor,
												nodeElement.NodeId,
												new UABrowseParameters(UANodeClass.All, new[] { UAReferenceTypeIds.References })
											);
				RecursiveBrowse(NewNodeCollection, endpointDescriptor);
 
			}
			catch (Exception ex)
			{
				ResultsTextBox.AppendText(Environment.NewLine + ex.ToString());
			}
		}
	}
	else
	{
		return;
	}
}

Please Log in or Create an account to join the conversation.

More
11 Oct 2018 16:29 #6740 by support
How the namespaces are used depends largely on the server, and in principle there is nothing wrong with what you have described.

Please post here your current code, I will review it.

Best regards
The following user(s) said Thank You: CMAC447

Please Log in or Create an account to join the conversation.

More
11 Oct 2018 15:22 #6739 by CMAC447
I tried what you recommended, but unfortunately I am still not getting all of the data items I want, still the same ones as before.
Upon further inspection I see that the namespace numbers are assigned strangely. For instance, MRegs and CM100Events share ns=3. Would this have any bearing on the browsing?

Please Log in or Create an account to join the conversation.

More
10 Oct 2018 20:14 #6738 by support
In principle, the answer is Yes, you can do it that way.

In reality, the second argument to Browse is UANodeDescriptor, which comprises of UANodeId, UABrowsePath, or both. And there is an implicit conversion operator from UANodeElement to UANodeDescriptor. So in fact, you can also just use one of the UANodeElement-s returned from the Browse in place of the UANodeDescriptor argument to the lower-level Browse.

Best regards
The following user(s) said Thank You: CMAC447

Please Log in or Create an account to join the conversation.

More
10 Oct 2018 17:45 #6737 by CMAC447
Thank you for your help. So the second argument of the Browse function is a UANodeID, in your example it's "UAObjectIDs.Server", which helps me with the first set of nodes. When I do this recursively, would I simply use the UANodeElement.NodeID of the node that I am on instead?

Please Log in or Create an account to join the conversation.

More
10 Oct 2018 14:16 - 10 Oct 2018 14:17 #6736 by support
Hello.

OPC UA browsing uses filters to specify what you want, because getting "everything" is actually not that common. Methods like BrowseDataNodes already have specific filters built in - so that's why you are not getting everything.

In order to get everything, you need use the Browse method, and pass it a filter that does not exclude anything. Following example shows just that - it is non-recursive, but you'll get the point.
// Shows how to obtain references of all kinds to nodes of all classes, from the "Server" node in the address space.
 
using System;
using System.Diagnostics;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.AddressSpace;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.OperationModel;
 
namespace UADocExamples._EasyUAClient
{
    class Browse
    {
        public static void Main1()
        {
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"
 
            // Instantiate the client object
            var client = new EasyUAClient();
 
            // Obtain nodes under "Server" node
            UANodeElementCollection nodeElementCollection;
            try
            {
                nodeElementCollection = client.Browse(
                    endpointDescriptor,
                    UAObjectIds.Server,
                    new UABrowseParameters(UANodeClass.All, new[] { UAReferenceTypeIds.References }));
            }
            catch (UAException uaException)
            {
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                return;
            }
 
            // Display results
            foreach (UANodeElement nodeElement in nodeElementCollection)
            {
                Debug.Assert(nodeElement != null);
                Console.WriteLine();
                Console.WriteLine("nodeElement.NodeId: {0}", nodeElement.NodeId);
                Console.WriteLine("nodeElement.DisplayName: {0}", nodeElement.DisplayName);
            }
        }
    }
}
I hope this helps
Best regards
Last edit: 10 Oct 2018 14:17 by support.
The following user(s) said Thank You: CMAC447

Please Log in or Create an account to join the conversation.

More
10 Oct 2018 13:04 #6735 by CMAC447
Hello,
I am trying to create a function that will discover all of the available datanodes on an OPC server and document what is in them. The problem I am having is that most of the OPC nodes are not being read in. Attached is a picture showing what nodes I can and can't find.
Is there something wrong with how I call BrowseDataNodes?
Is there something wrong with my method for recursively
browsing the tree?
//When a button is clicked, call this background worker
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
	UAEndpointDescriptor endpointDescriptor = "opc.tcp://" + PCNameTextBox.Text + ":4880/[SystemName]";
	UANodeElementCollection NodeCollection = new UANodeElementCollection();
	//grab the collection of nodes from our endpoint
	try
	{
		NodeCollection = EasyOPCClient.BrowseDataNodes(endpointDescriptor);
	}
	catch (Exception ex)
	{
		//Exception handling
	}
	RecursiveBrowse(NodeCollection, endpointDescriptor);
}
 
//Recursive function for browsing data nodes
private void RecursiveBrowse(UANodeElementCollection NodeCollection, UAEndpointDescriptor endpointDescriptor)
{
	//If it has children keep going
	if (NodeCollection.Count > 0)
	{
		//Next recursively get the data from each node on the OPC server.
		foreach (UANodeElement nodeElement in NodeCollection)
		{
			//Write to file, savepath comes from user input
			using (StreamWriter sw = new StreamWriter(Path.Combine(savepath, "[SystemName]ServerNodes.txt"), true))
			{
				sw.WriteLine("DisplayName: " + nodeElement.DisplayName);
				//Other things written to the file here
				sw.WriteLine("");
			}
			//Browse for the data nodes that are children of this one and browse deeper into the tree
			UANodeElementCollection NewNodeCollection = new UANodeElementCollection();
			try
			{
				NewNodeCollection = EasyOPCClient.BrowseDataNodes(endpointDescriptor, nodeElement.NodeId);
				RecursiveBrowse(NewNodeCollection, endpointDescriptor);
 
			}
			catch (Exception ex)
			{
				ResultsTextBox.AppendText(Environment.NewLine + ex.ToString());
			}
		}
	}
	else
	{
		return;
	}
}
Attachments:

Please Log in or Create an account to join the conversation.

Moderators: support
Time to create page: 0.201 seconds

      

 Recommend this on Google