15:18, EET
January 20, 2021
Hi,
I am trying to get browse path by using nodeId.
I have done following things so far :
1. Added my own IoManagerListener.
2. Inside “onWriteValue” method of MyIoManagerListener, I get NodeId.
Is it possible to get complete browse path from that NodeId?
Also, Is there any method which can convert complete browse path(which I have stored in some string) to NodeId?
Please suggest some solution.
17:33, EET
April 3, 2012
Hi,
Could it be possible to explain why you would need it? Usually it should be at most needed to look at the immediate parent node(s) (there can be any number of parent nodes). Or you might have some application-specific mapping information that can directly determine what to do what per NodeId.
Also define what you mean by “browse path”? Rest of this post assumes a List of QualifiedNames sort of that when given to the TranslateBrowsePathsToNodeIds (https://reference.opcfoundation.org/v104/Core/docs/Part4/5.8.4/) starting from the Identifiers.RootFolder and following the BrowseNames would return that NodeId. So sort of “Inverse TranslateBrowsePathsToNodeIds” is what you would be looking for? Basically the parameter to that service call is also called BrowsePath, but the RelativePath element contains also other fields than a BrowseName/QualifiedName.
In a general sense the answer is that there is no single method in the current SDK that you could call. Additionally note that a node can have multiple parent nodes, thus in a theoretical address space you could have close to infinite BrowsePaths leading to the same node depending the way it is constructed. The other way to say this is that NodeId doesn’t define anything about the “path” it is in. If you are only using String-based NodeIds, then you can have a custom syntax to define a path.
If the nodes are created by the SDK with a createInstance/createNodeBuilder then by default all the subnodes of the created top-lvl node will get toString of the parent+”/”+browsename_of_sub_node (and if the browsename is in ns 0 then this time also that is used like 0:name when otherwise it would be omitted). We did that since that seemed to be a good best-effort way to generate unique NodeIds when instantiating a type (since each NodeId must be unique). However it is entirely upto to the server implementation details what the NodeIds are, i.e. this is not defined in the specification (and well, only works for String IdType’d NodeIds as well, there are 3 other IdTypes, such as numeric). Also here it is a “complete browsepath” only to the top-lvl node that reflects the TypeDefinition node, would this be what you mean instead with “complete browse path” or do you mean literally all the way from the RootFolder node?
If you are using UaNodes for all nodes, then you use UaNode.getReferences(Identifiers.HierarchicalReferences, true) and basically recursively construct all paths to the RootFolder instance and take the BrowseNames of all steps.
9:08, EET
January 20, 2021
Hi,
I have same browse names for multiple nodes in different browse paths. For example :
0:Root\0:Objects\2:RootEntities\3:System\3:Applications\3:App1\3:Nod1
0:Root\0:Objects\2:RootEntities\3:System\3:Applications\3:App2\3:Nod1
0:Root\0:Objects\2:RootEntities\3:System\3:Applications\3:App3\3:Nod1
Inside “onWriteValue” method of MyIoManagerListener, I get NodeId, so I was wondering if I could get complete browse path as mentioned above using some utility method.
I tried the approach that you suggested of recursively constructing path and it is working for me.
About my second question :
I have this string => “0:Root\0:Objects\2:RootEntities\3:System\3:Applications\3:App3\3:Nod1”
Then can I get NodeId from it?
12:07, EET
April 3, 2012
Note that there is no requirement in the Objects part of the address space to have a BrowsePath to be unique, that is to say, a single BrowsePath can point to multiple nodes (since a node is allowed to have e.g. multiple HasComponent targets that all would have the same BrowseName). In the Types part of the address space there however is this limitation.
If you know there is only a single node per a BrowsePath (or do not care which one of them you find) and you also know that they all start from “0:Root”, then you can:
1. Split that String with “\”
2. Transform each part with QualifiedName.parseQualifiedName(String)
3. Get the UaNode of the root node uaServer.getAddressSpace().getNode(Identifiers.RootFolder)
4. Ignore the first QualifiedName (since that is the root node)
5. Get all forward hierarchical references of the nodegetReferences(Identifiers.HierarchicalReferences, false), check all target’s BrowseNames until you find a match and repeat this process until you find the node or are not getting any forward hierarchical references. NOTE! The address space is allowed to make loops, unless you know that you have not made any, you would also need to track all visited nodes
Alternatively if you know that all parts are target of HasComponent or HasProperty, you can use the UaNode.getComponent and/or UaNode.getProperty instead of getting all references.
Alternatively you could try to call the TranslateBrowsePathsToNodeIds service internall via:
uaServer.getAddressSpace().translateBrowsePathToNodeIds(NodeId startingNode, RelativePath relativePath)
For more details see: https://reference.opcfoundation.org/v104/Core/docs/Part4/5.8.4/
Also sorry for pushing, but your answer doesn’t exactly say _why_ you are needing the BrowsePath. Since if it would happen to be a use-case we have missed we could probably add some utility methods in future SDK versions that would make this easier. It is normal to have same BrowseNames for nodes, basically everything should “key on” NodeIds, not to BrowseNames, unless the node is part of a larger type, then the BrowseName instead has meaning, since typically operations on the node mean something is to be done with the parent node. But I do also have to note that I have somewhat limited view of the entire worlds use-cases thus why I asked.
An alternative, depending on your use-cases and requirements would be to store a map or 2 that would map NodeId BrowsePath information. If you are creating all nodes yourself, you will also know (or can calculate per this and prev post) the BrowsePath of that node under which you are adding the new nodes and then basically append to that the nodes you are creating, that way you would have ready when your listener is called.
14:17, EET
January 20, 2021
Hi,
Requirement is as follows:
1. I am defining some nodes in the xml model which will be used to pass on some data to the server.
2. On the server side, I need to make sure that the node which is being used to send the data to server is one of those predefined nodes.
3. I am using browse path as xml model can be changed in the future and NodeId might change and browse path is not supposed to change.
4. lastly I need complete browse path because I have same nodes in multiple paths.
About this solution : uaServer.getAddressSpace().translateBrowsePathToNodeIds(NodeId startingNode, RelativePath relativePath)
How do I get uaServer instance in my listener? I have tried following things :
1. Making MyIoManagerListener as a component in my springboot application. But application does not start as it fails to register this bean.
2. Getting uaServer instance from IOPCServerManager implementation. This also fails.
Is there any better approach?
16:43, EET
April 3, 2012
OK, just note that most operations in OPC UA use the NodeId, such as Read, Write, Subscriptions/MonitoredItems. Thus typical client applications would thus need to be reconfigured each time the NodeIds would change. If you know/make all clients applications then it wont matter (either you can do that or you can develop them to have logic to search the NodeIds).
For getting the UaServer object, well it is up to you to decide how exactly you want to do. Since you mention Spring you can probably do some @AutoWired magic at least if you only have a single UaServer object in your application. But at least when you are adding your listener you have the IoManager for which you can call getNodeManager() and for NodeManager you can call getServer() which will return the UaServer.
Alternatively typically the UaNode instance on the server side is castable to ServerNode, which has getAddressSpace() which is the NodeManagerTable (the same what UaServer.getAddressSpace returns).
SDK doesn’t contain a type named IOPCServerManager, thus it is something you (or well, at least not by us) have created thus I cannot say anything about that.
8:12, EET
January 20, 2021
Hi,
I will be using UaExpert as client, so I don’t need fixed NodeId there. I can simply browse through address space and get whatever node I want. In case NodeId changes on server, I don’t need to do any changes on client side.
I used solution as suggested by you to cast UaNode to ServerNode, Its working for me.
Only problem now is when I am trying to use “Root” as a string for creating root node I am not able to get correct path, but when I use integer value in identifier for getting NodeId of root node it gives correct path.
Below are the steps that I have followed :
/*
NodeId root = new NodeId(0,84); // works
NodeId root = new NodeId(0,”Root”); // does not work
RelativePath relativePath = new RelativePath(Stream.of(browseNames).
map(b -> new RelativePathElement(Identifiers.HierarchicalReferences, false, true, b))
.toArray(RelativePathElement[]::new));
ExpandedNodeId id = server.getAddressSpace().translateBrowsePathToNodeIds(root,relativePath)[0].getTargetId();
UaNode node = server.getAddressSpace().getNode(id);
*/
Where in root node is => 0:Root
browseNames consists of => 0:Objects,2:RootEntities.3:System,3:Applications,3:App1,3:Node1
Is there any way I could directly get NodeId of root node as I need it in “translateBrowsePathToNodeIds” method.
16:25, EET
April 3, 2012
Use Identifiers.RootFolder.
As I have tried to explain, BrowseName != NodeId. BrowseNames of nodes has nothing to do what their NodeIds are. In some rare cases they like _could_ look the same, but that is basically a coincidence (I could try to say this differently, but hopefully this is clear enough). The standard/base information nodes are all Numeric NodeIds, so at least for them that never happens. Only for String-based NodeIds it could look the same, there are 3 other NodeId types as well.
Based on your questions I would assume you are not very familiar with OPC UA. I would recommend reading the specification regarding the different Attributes: https://reference.opcfoundation.org/v104/Core/docs/Part3/#5.
Anyway, use Identifiers.RootFolder, as explained in the previous posts. Though it is .equal to the “0, 84” one. But normally when refering to the base information model in the code the generated constants are used. The “new NodeId(0, “Root”)” does not exist, BrowseNames cannot be used like that, in general. For some models that like _might work_ though as said that is basically a “coincidence” or a choise, but cannot be generalized i.e. it is not defined in the OPC UA Specification nor that would ever work for non-String IdType’d NodeIds. In addition, when instantiating Types, the sub-structure of the type (i.e. nodes below the main TypeDefinition node) must retain their BrowseNames, this is including to their namespace. Therefore also do note that a BrowseName can be in a different namespace than the NodeId is.
Hopefully that was not too confusing..
Most Users Ever Online: 1919
Currently Online:
72 Guest(s)
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Heikki Tahvanainen: 402
hbrackel: 144
rocket science: 88
pramanj: 86
Francesco Zambon: 83
Ibrahim: 78
Sabari: 62
kapsl: 57
gjevremovic: 49
Xavier: 43
Member Stats:
Guest Posters: 0
Members: 734
Moderators: 7
Admins: 1
Forum Stats:
Groups: 3
Forums: 15
Topics: 1523
Posts: 6449
Newest Members:
christamcdowall, redaahern07571, nigelbdhmp, travistimmons, AnnelCib, dalenegettinger, howardkennerley, Thomassnism, biancacraft16, edgardo3518Moderators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1026, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0
Administrators: admin: 1