OPCFoundation / UA-.NETStandard

OPC Unified Architecture .NET Standard
Other
1.97k stars 950 forks source link

How to create an address space using 4 xml nodeset2 files #1495

Closed fsodano1 closed 1 year ago

fsodano1 commented 3 years ago

Type of Issue

Describe the Issue

How to create an address space using 4 xml nodeset2 files

To Reproduce

Hello everyone, I need to create an address spaceusing 4 xml nodeset2 files:

using Opc.Ua;
using Opc.Ua.Server;
using System;
using System.Collections.Generic;
using System.IO;

namespace App.Core.Services.OpcUa.Server.NodeManagers
{

    public class UmatiNodeManager : CustomNodeManager2
    {
        private readonly string _nodeset2Dir;

        public UmatiNodeManager(IServerInternal server, ApplicationConfiguration configuration, string nodeset2Dir)
            : base(server, configuration)
        {
            _nodeset2Dir = nodeset2Dir;
        }

        /// <summary>
        /// Does any initialization required before the address space can be used.
        /// </summary>
        /// <remarks>
        /// The externalReferences is an out parameter that allows the node manager to link to nodes
        /// in other node managers. For example, the 'Objects' node is managed by the CoreNodeManager and
        /// should have a reference to the root folder node(s) exposed by this node manager.  
        /// </remarks>
        public override void CreateAddressSpace(IDictionary<NodeId, IList<IReference>> externalReferences)
        {
            lock (Lock)
            {
                IList<IReference> references = null;

                if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out references))
                {
                    externalReferences[ObjectIds.ObjectsFolder] = references = new List<IReference>();
                }

                var orderedFiles = new List<string> { 
                    "Opc.Ua.Di.NodeSet2.xml", 
                    "Opc.Ua.Machinery.NodeSet2.xml", 
                    "Opc.Ua.Woodworking.NodeSet2.xml", 
                    "Opc.Ua.Eumabois.NodeSet2.xml" };

               foreach(var file in orderedFiles)
                    ImportXml(externalReferences, Path.Combine(_nodeset2Dir,file));

            }
        }

        private void ImportXml(IDictionary<NodeId, IList<IReference>> externalReferences, string resourcepath)
        {
            try
            {

                NodeStateCollection predefinedNodes = new NodeStateCollection();

                    using (Stream stream = new FileStream(resourcepath, FileMode.Open))
                    {
                        Opc.Ua.Export.UANodeSet nodeSet = Opc.Ua.Export.UANodeSet.Read(stream);

                        foreach (string namespaceUri in nodeSet.NamespaceUris)
                        {
                            SystemContext.NamespaceUris.GetIndexOrAppend(namespaceUri);
                        }
                        nodeSet.Import(SystemContext, predefinedNodes);

                        for (int ii = 0; ii < predefinedNodes.Count; ii++)
                        {
                            AddPredefinedNode(SystemContext, predefinedNodes[ii]);
                        }
                        // ensure the reverse refernces exist.
                        AddReverseReferences(externalReferences);
                    }

            }
            catch (Exception e)
            {

                throw e;
            }
        }

    }

I'm not able to see my machines when I try to connect to the server. What am I doing wrong? I am attaching the 4 files. Thanks for the help.

Screenshots Please note client cannot see my machines: image

Expected behaviour: image

mrsuciu commented 3 years ago

@fsodano1 Try if it works by slightly changing the following method to this:

private void ImportXml(IDictionary<NodeId, IList<IReference>> externalReferences, string resourcepath)
{
    try
    {

        NodeStateCollection predefinedNodes = new NodeStateCollection();

        using (Stream stream = new FileStream(resourcepath, FileMode.Open))
        {
            Opc.Ua.Export.UANodeSet nodeSet = Opc.Ua.Export.UANodeSet.Read(stream);
            nodeSet.Import(SystemContext, predefinedNodes);

            // Detect new namespace uris imported from file
            List<string> newNamespaceUris = new List<string>();
            if (nodeSet.NamespaceUris != null && SystemContext.NamespaceUris != null)
            {
                for (int ii = 0; ii < nodeSet.NamespaceUris.Length; ii++)
                {
                    SystemContext.NamespaceUris.GetIndexOrAppend(nodeSet.NamespaceUris[ii]);
                    newNamespaceUris.Add(nodeSet.NamespaceUris[ii]);
                }
            }

            // Add new namespace uris to current node manager
            if (newNamespaceUris.Count > 0)
            {
                List<string> allNamespaceUris = new List<string>();
                allNamespaceUris.AddRange(NamespaceUris);
                allNamespaceUris.AddRange(newNamespaceUris);
                SetNamespaces(allNamespaceUris.ToArray());

                foreach (var namespaceUri in newNamespaceUris)
                {
                    Server.NodeManager.RegisterNamespaceManager(namespaceUri, this);
                }
            }

            // Add new imported nodes to the predefined nodes collection
            for (int ii = 0; ii < predefinedNodes.Count; ii++)
            {
                AddPredefinedNode(SystemContext, predefinedNodes[ii]);
            }

            // Ensure the reverse refernces exist.
            AddReverseReferences(externalReferences);
        }
    }       
}
mregen commented 2 years ago

Maybe we can support loading of Nodeset2 files with the next wave of complex type improvements.

mregen commented 1 year ago

@fsodano1 ModelCompiler has now support to generate code from Nodeset2. Here is a sample so you get the idea:

@echo off
setlocal

REM if docker is not available, ensure the Opc.Ua.ModelCompiler.exe is in the PATH
set MODELCOMPILER=Opc.Ua.ModelCompiler.exe
set MODELCOMPILERIMAGE=ghcr.io/opcfoundation/ua-modelcompiler:latest
set MODELROOT=.

echo pull latest modelcompiler from github container registry
docker pull %MODELCOMPILERIMAGE%
IF ERRORLEVEL 1 (
:nodocker
    Echo The docker command to download ModelCompiler failed. Using local PATH instead to execute ModelCompiler.
) ELSE (
    Echo Successfulled pulled the latest docker container for ModelCompiler.
    set MODELROOT=/model
    set MODELCOMPILER=docker run -v "%CD%:/model" -it --rm --name ua-modelcompiler %MODELCOMPILERIMAGE% 
)

echo Building DI from Nodeset2
%MODELCOMPILER% compile -version v104 -d2 "%MODELROOT%/Opc.Ua.Di.NodeSet2.xml,Opc.Ua.DI,OpcUaDI" -o2 "%MODELROOT%/DI"
IF %ERRORLEVEL% EQU 0 echo Success!

echo Building IA from Nodeset2
%MODELCOMPILER% compile -version v104 -d2 "%MODELROOT%/Opc.Ua.IA.NodeSet2.xml,Opc.Ua.IA,OpcUaIA" -d2 "%MODELROOT%/Opc.Ua.Di.NodeSet2.xml,Opc.Ua.DI,OpcUaDI" -o2 "%MODELROOT%/IA"
IF %ERRORLEVEL% EQU 0 echo Success!

echo Building Machinery from Nodeset2
%MODELCOMPILER% compile -version v104 -d2 "%MODELROOT%/Opc.Ua.Machinery.NodeSet2.xml,Opc.Ua.Machinery,OpcUaMachinery" -d2 "%MODELROOT%/Opc.Ua.Di.NodeSet2.xml,Opc.Ua.DI,OpcUaDI" -o2 "%MODELROOT%/Machinery"
IF %ERRORLEVEL% EQU 0 echo Success!

echo Building Machinery.Examples from Nodeset2
%MODELCOMPILER% compile -version v104 -d2 "%MODELROOT%/Opc.Ua.Machinery.Examples.NodeSet2.xml,Opc.Ua.Machinery.Examples,OpcUaMachineryExamples" -d2 "%MODELROOT%/Opc.Ua.Di.NodeSet2.xml,Opc.Ua.DI,OpcUaDI" -d2 "%MODELROOT%/Opc.Ua.Machinery.NodeSet2.xml,Opc.Ua.Machinery,OpcUaMachinery" -o2 "%MODELROOT%/Machinery.Examples"
IF %ERRORLEVEL% EQU 0 echo Success!

echo Building Robotics from Nodeset2
%MODELCOMPILER% compile -version v104 -d2 "%MODELROOT%/Opc.Ua.Robotics.NodeSet2.xml,Opc.Ua.Robotics,OpcUaRobotics" -d2 "%MODELROOT%/Opc.Ua.Di.NodeSet2.xml,Opc.Ua.DI,OpcUaDI" -o2 "%MODELROOT%/Robotics"
IF %ERRORLEVEL% EQU 0 echo Success!

echo Building MachineTool from Nodeset2
%MODELCOMPILER% compile -version v104 -d2 "%MODELROOT%/Opc.Ua.MachineTool.NodeSet2.xml,Opc.Ua.MachineTool,OpcUaMachineTool" -d2 "%MODELROOT%/Opc.Ua.Di.NodeSet2.xml,Opc.Ua.DI,OpcUaDI" -d2 "%MODELROOT%/Opc.Ua.IA.NodeSet2.xml,Opc.Ua.IA,OpcUaIA" -d2 "%MODELROOT%/Opc.Ua.Machinery.NodeSet2.xml,Opc.Ua.Machinery,OpcUaMachinery" -o2 "%MODELROOT%/MachineTool"
IF %ERRORLEVEL% EQU 0 echo Success!

echo Building Woodworking from Nodeset2
%MODELCOMPILER% compile -version v104 -d2 "%MODELROOT%/Opc.Ua.Woodworking.NodeSet2.xml,Opc.Ua.Woodworking,OpcUaWoodworking" -d2 "%MODELROOT%/Opc.Ua.Di.NodeSet2.xml,Opc.Ua.DI,OpcUaDI" -d2 "%MODELROOT%/Opc.Ua.Machinery.NodeSet2.xml,Opc.Ua.Machinery,OpcUaMachinery" -o2 "%MODELROOT%/Woodworking"
IF %ERRORLEVEL% EQU 0 echo Success!

echo Building MachineVision from Nodeset2
%MODELCOMPILER% compile -version v104 -d2 "%MODELROOT%/Opc.Ua.MachineVision.NodeSet2.xml,Opc.Ua.MachineVision,OpcUaMachineVision"  -o2 "%MODELROOT%/MachineVision"
IF %ERRORLEVEL% EQU 0 echo Success!
EthanChangAED commented 1 year ago

Closing this issue. Feel free to file a new one in Discussion-Q&A if there is more question.