FreeOpcUa / opcua-asyncio

OPC UA library for python >= 3.7
GNU Lesser General Public License v3.0
1.09k stars 357 forks source link

create_* functions doesn't respect namespace ID for browse name #1390

Open okapies opened 1 year ago

okapies commented 1 year ago

Describe the bug
create_* functions (e.g. create_folder()) in asyncua.common.managed_nodes receives nodeid and bname. If we specify a namespace ID for nodeid and not for bname, the namespace of the resulting browse name will be 0 instead of the one for node ID.

To Reproduce

from asyncua.sync import Client
from asyncua import ua

client = Client(...)
nodeid: ua.NodeId = ua.NodeId("0:Folder", 2)
qname: str = "Folder"
folder = client.nodes.objects.create_folder(nodeid, qname)

assert folder.read_browse_name().NamespaceIndex == 2  # fails

Expected behavior
The namespace of browse name is same one specified in the node ID.

Version

schroeder- commented 1 year ago

Don't think this change is a good idea, because it can break a lot of code. Because a lot of a lot of applications except the correct BrowseName NamespaceIndex.

Also a lot of times a BrosweName NamespaceIndex, doens't match the NodeId Namespace, this happens if you use companion specifications.

evanjs commented 7 months ago

Hitting the same issue now

I am trying to use the client to set up some example test cases for a separate OPCUA server instance The specification I am working on depends on EUROMAP83 (Opc.Ua.PlasticsRubber.GeneralTypes) Considering this, I will always have more than 1 namespace on the OPCUA server


Sample (Failing) Scenario

Namespace Index: 7 Target node: Objects/Devices/TEST/{namespaceIndex}:1:JobInformation Expected path: Objects/Devices/TEST/7:1:JobInformation Actual path: Objects/Devices/TEST/0:1:JobInformation

I am able to drill down (from client.nodes.root) into Objects/Devices/Test, but am unable to access nodes below that point without using the wrong namespace i.e. 0 rather than 7

AndreasHeine commented 7 months ago

Just general Information:

Index = 0 (OPC UA Standard-Nodeset) Index = 1 (Server own Namespace) Index = 2 (Maybe a CS-Nodeset) Index = 3 (Maybe a Machine-Instance)

Case 1: If you instantiate something from Namespace 0 (OPC UA Standard-Nodeset) the Browsename will always Inherit (to 0)

Case 2: If you instantiate something from Namespace 2 (CS-Nodeset) the Browsename will Inherit (to 2) BUT!!! if the node/property has been inherited from a ObjectType defined in Namespace 0 (OPC UA Standard-Nodeset) it will still get 0 for the Browsename!

This has nothing to do with the Node-Id at all! @okapies

References: https://reference.opcfoundation.org/Core/Part3/v104/docs/5.2.4

Servers may often choose to use the same namespace for the NodeId and the BrowseName. However, if they want to provide a standard Property, its BrowseName shall have the namespace of the standards body although the namespace of the NodeId reflects something else, for example the local Server.

if you want to see that live you could check out the sampleserver i wrote for UMATI a while ago to showcase CS-Models -> opc.tcp://opcua.umati.app:4843

under Objects/Machines/Extruder_SampleManufacturer_987 you can review the Browsenames and NodeIds ;)

e.g. image

OPC UA for Machinery - MachineIdentificationTypeas is Subtype of [FolderType (Index 0) / FunctionalGroupType (Index 2 - DI Spec.)]: image

cziebuhr commented 6 months ago

I see several issues here in the code from the original poster:

Personally I prefer using the explicit form with calling node.add_folder(ua.NodeId("Folder", 2), ua.QualifiedName("Folder", 2)) instead of using the string form node.add_folder("ns=2;s=Folder", "2:Folder").