1

Noobie OPCUA user here. I built a custom object type using UA Modeler, which as far as I understand creates a class of x custom object with y properties. My issue is with creating a node instance of that in my server. I'm looking for something that would allow me to do: Node test = new object node of type x custom object. I know that I could recreate my custom object in code, but that wouldn't be very smart... I think this is a very simple issue, but I can't find how to fix it in documentation or in the servers. Unless this is the way?

CreateObjectSettings settings = new CreateObjectSettings()
                {
                    // All the settings
                    TypeDefinitionId = ObjectTypeIds.MyCustomObject,
                };
                CreateObject(Server.DefaultRequestContext, settings);

Thanks for the help :)

oiergoiergh
  • 115
  • 7

1 Answers1

1

You are on the right track.

Here is a function I wrote to create custom objects based on the type passed-in. Notice that you have to lock the nodes and make sure that the node does not already exist.

private ObjectNode CreateOpcObject(NodeId parentNodeId, string nodeName, string identifier, uint type,
        bool inRootFolder, bool isParentAsOwner, string description = "")
    {
        ObjectNode newNode = null;

        lock (InMemoryNodeLock)
        {
            if (FindInMemoryNode(new NodeId(identifier, DefaultNamespaceIndex)) == null)
            {
                if (!inRootFolder && FindInMemoryNode(parentNodeId) == null)
                {
                    log.Warn("Cannot create OPC object because parent node is not found for nodeName {nodeName}, identifier {identifier}.", nodeName, identifier);
                    return null;
                }

                var settings = new CreateObjectSettings
                {
                    ParentNodeId = parentNodeId,
                    ParentAsOwner = isParentAsOwner, // cannot set this to true since it makes deleting much slower
                    ReferenceTypeId = ReferenceTypeIds.Organizes,
                    RequestedNodeId = new NodeId(identifier, DefaultNamespaceIndex),
                    BrowseName = new QualifiedName(nodeName, DefaultNamespaceIndex),
                    TypeDefinitionId = new NodeId(type, DefaultNamespaceIndex),
                    DisplayName = nodeName,
                    Description = description
                };

                newNode = CreateObject(Server.DefaultRequestContext, settings);
            }
            else
            {
                log.Warn("Cannot create OPC object because identifier is not found for nodeName {nodeName}, identifier {identifier}.", nodeName, identifier);
            }
        }
        return newNode;
    }

Notice that you can to do this instead of just assigning the type to the TypeDefinitionId:

TypeDefinitionId = new NodeId(type, DefaultNamespaceIndex),

You call this by doing something like this:

var newNode = CreateOpcObject(parentNodeId, newNodeName, newNodeId, Model.ObjectTypes.MyGeneratedType, false, true, "This is a description of the new node object.");
eglease
  • 2,445
  • 11
  • 18
  • 28
  • Ah thank you. This seems like something that should be in the sdk. Anyways, what does locking the node do? – oiergoiergh Oct 31 '22 at 17:50
  • 1
    It prevents multiple node operations at the same time thus preventing deadlocks. – eglease Oct 31 '22 at 18:05
  • 1
    Quick follow up question: Any newly created node should be a child of the root node either directly or through intermediate nodes. Am I meant to create this root node (in which case how?) or is it created when I initialize the server or a node manager (in which case how do I reference it?)? – oiergoiergh Nov 01 '22 at 13:24
  • It does not need to be a child. Making it a child makes deletes easier since you can just delete the parent but also can slow things down when doing deletes since it has to traverse each child node. In my code, I make certain structures orphans and delete them individually to improve performance. Making them children was much easier to implement but had performance problems when deleting. – eglease Nov 01 '22 at 17:33
  • Thanks, I'll give that a go. By making it an orphan you mean that it's parent node is itself? In any case, how do I reference the root node? I'm looking for something like CreateOpcObject(server.rootNode.NodeId,...) – oiergoiergh Nov 02 '22 at 09:37
  • If you want it connected to the parent, set `ParentAsOwner` to true. You can always reference any node by its NodeID. – eglease Nov 02 '22 at 13:25