zoukankan      html  css  js  c++  java
  • OPC UA 统一架构 (一)

    OPC UA 

    一 、OPC UA简介

    OPC UA(OPC Unified Architecture)是下一代OPC统一体系架构,是一种基于服务的、跨越平台的解决方案。

    OPC UA具有如下特点:

    1)    扩展了OPC的应用平台。兼容Windows、Linux和Unix平台,不受平台限制,不需要进行DCOM安全设置(DA需要)。这使得基于OPC UA的标准产品可以更好地实现工厂级的数据采集和管理;

    2)    OPC UA定义了统一数据和服务模型,使数据组织更为灵活,可以实现报警与事件、数据存取、历史数据存取、控制命令、复杂数据的交互通信;

    3)    OPC UA比OPC DA更安全。OPC UA传递的数据是可以加密的,并对通信连接和数据本身都可以实现安全控制。新的安全模型保证了数据从原始设备到系统,从本地到远程的各级自动化和信息化系统的可靠传递;

    4)    OPC UA的Internet 通讯,可以不用设置防火墙。

    想要了解更多,https://www.cnblogs.com/thammer/p/12882468.html

    前期准备

     准备好开发的IDE,首选Visual Studio2019版本,新建项目,或是在你原有的项目上进行扩展。注意:项目的..Net Core 2.1和NET Framework版本最新为4.6.2

    打开NuGet管理器,输入指令

    Install-Package UA-.NETStandard

    或者

    、OPC UA配置管理器

     1.OPC UA 

     其他家OPC配置界面

    下面已基金会发布的SDK为基础,开发适合自己的OPC UA。也有基于open62541开发的。

    /UA-.NETStandard

     此OPC UA参考实现以.NET Standard规范为目标。

    .NET Standard允许开发可在当今可用的所有常见平台上运行的应用程序,包括Linux,iOS,Android(通过Xamarin)和Windows 7/8 / 8.1 / 10(包括嵌入式/ IoT版本),而无需特定于平台的修改。

    此项目中的参考实施之一已通过OPC Foundation认证测试实验室的认证,以证明其高质量。自从使用合规性测试工具(CTT)V1.04对认证过程进行了测试并验证了合规性以来的修复和增强功能。

    此外,还支持云应用程序和服务(例如ASP.NET,DNX,Azure网站,Azure Webjobs,Azure Nano Server和Azure Service Fabric)。

    1)Authentication设置

    下图是配置设置界面

    1.  证书验证,OPC Foundation指定路径或者存储在“受信用的根证书颁发机构”

     

      2.用户名验证

      

      3.Server可支持匿名Anonymous

     三 、OPC UA  数据模型

     数据里最重要的能够存储信息,还要好查找易维护。看到唯一性,好多方法都是围绕唯一性展开,UA-.NETStandard里NodeId地址标识符,下面的注释,封装在***State类里面

        /// <summary>
        /// Stores an identifier for a node in a server's address space.
        /// </summary>
        /// <remarks>
        /// <para>
        /// <b>Please refer to OPC Specifications</b>:
        /// <list type="bullet">
        /// <item><b>Address Space Model</b> setion <b>7.2</b></item>
        /// <item><b>Address Space Model</b> setion <b>5.2.2</b></item>
        /// </list>
        /// </para>
        /// <para>
        /// Stores the id of a Node, which resides within the server's address space.
        /// <br/></para>
        /// <para>
        /// The NodeId can be either:
        /// <list type="bullet">
        /// <item><see cref="uint"/></item>
        /// <item><see cref="Guid"/></item>
        /// <item><see cref="string"/></item>
        /// <item><see cref="byte"/>[]</item>
        /// </list>
        /// <br/></para>
        /// <note>
        /// <b>Important:</b> Keep in mind that the actual ID's of nodes should be unique such that no two
        /// nodes within an address-space share the same ID's.
        /// </note>
        /// <para>
        /// The NodeId can be assigned to a particular namespace index. This index is merely just a number and does
        /// not represent some index within a collection that this node has any knowledge of. The assumption is
        /// that the host of this object will manage that directly.
        /// <br/></para>
        /// </remarks>
        [DataContract(Namespace = Namespaces.OpcUaXsd)]
        public class NodeId : IComparable, IFormattable
    A.    初始化自己的节点

     OPC UA 里比较重要的是FolderStateNodeState和BaseDataVariableState,里面具体属性,可以自己去了解,这里不说了

        /// <summary> 
        /// A typed base class for all data variable nodes.
        /// </summary>
        public class BaseDataVariableState : BaseVariableState
        /// <summary> 
        /// The base class for all folder nodes.
        /// </summary>
        public class FolderState : BaseObjectState
        /// <summary>
        /// The base class for custom nodes.
        /// </summary>
        public abstract class NodeState : IDisposable, IFormattable

    a)      比较重要的是CreateAddressSpace(IDictionary<NodeId, IList<IReference>> externalReferences)创建自己地址空间,下图也是提供了很样例,一个根目录字符串路径就可以了,其他数据源数据类型可以不提供。一般地,(Key, Value)值对。

    类似二叉树数据结构

    b)  二叉树结构体,左为支(Folder)(可再次向下遍历),右为叶(Variable),存储变量信息,如变量完整Full路径,“***.变量组0.变量”,下图是用第三方测试结果

    c)      完整代码

     1         public override void CreateAddressSpace(IDictionary<NodeId, IList<IReference>> externalReferences)
     2         {
     3             lock (Lock)
     4             {
     5                 IList<IReference> references = null;
     6 
     7                 if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out references))
     8                 {
     9                     externalReferences[ObjectIds.ObjectsFolder] = references = new List<IReference>();
    10                 }
    11                 // 第三方数据源,来自API
    12                 if ((OpcuaDataPrivade == null || OpcuaDataPrivade.VariableNode == null) || String.IsNullOrEmpty(OpcuaDataPrivade.VariableNode.name))
    13                 {
    14                     return;
    15                 }
    16 
    17                 FolderState root = CreateFolder(null, OpcuaDataPrivade.VariableNode.name, OpcuaDataPrivade.VariableNode.name);
    18                 root.AddReference(ReferenceTypes.Organizes, true, ObjectIds.ObjectsFolder);
    19                 references.Add(new NodeStateReference(ReferenceTypes.Organizes, false, root.NodeId));
    20                 root.EventNotifier = EventNotifiers.SubscribeToEvents;
    21                 AddRootNotifier(root);
    22 
    23                 List<BaseDataVariableState> variables = new List<BaseDataVariableState>();
    24 
    25                 try
    26                 {
    27                     #region Device_Simulation
    28 
    29                     BrowseGroup(root, OpcuaDataPrivade.VariableNode);
    30 
    31                     m_dynamicNodes_temp = MemCopyList(m_dynamicNodes);
    32                     #endregion
    33 
    34                 }
    35                 catch (Exception e)
    36                 {
    37                     Utils.Trace(e, "Error creating the address space.");
    38                 }
    39 
    40                 AddPredefinedNode(SystemContext, root);
    41                 
    42                 m_simulationTimer = new Timer(DoSimulation, cts, 1000, 1000);
    43 
    44                 System.Threading.Tasks.Task.Factory.StartNew(() =>
    45                 {
    46                     WriteProcHandle(cts);
    47                 });
    48             }
    49         }
            private void BrowseGroup(FolderState folder, InterfaceSample.Model.NodeDef node, string folderFullPath = "")
            {
                if (node == null)
                {
                    return;
                }
    
                foreach (InterfaceSample.Model.NodeDef childGroup in node.LeftFolder)
                {
                    string str;
                    if (!string.IsNullOrEmpty(folderFullPath))
                    {
                        str = string.Format("{0}_{1}", folderFullPath, childGroup.name);
                    }
                    else
                    {
                        str = string.Format("{0}_{1}", childGroup.ParentName, childGroup.name);
                    }
    
                    FolderState folderStae = CreateFolder(folder, str, childGroup.name);
                    BrowseGroup(folderStae, childGroup, str);
                }
    
                foreach (InterfaceSample.Model.NodeVariable nv in node.RightVariable)
                {
                    string Device_scalarSimulation = string.Format("{0}_{1}", folder.BrowseName.Name, nv.name);
                    if(!XXXXToBaseDataVariableDic.ContainsKey(nv.nameFullPath))  XXXXToBaseDataVariableDic.Add(nv.nameFullPath, Device_scalarSimulation);
                    if (!baseDataVariableToXXXXDic.ContainsKey(Device_scalarSimulation)) baseDataVariableToXXXXDic.Add(Device_scalarSimulation, nv.nameFullPath);
                    CreateDynamicVariable(folder, Device_scalarSimulation, nv.name, BuiltInType.Variant, ValueRanks.Scalar);
                }
            }
     1     public class NodeDef
     2     {
     3         public string name = String.Empty;
     4         public string ParentName = String.Empty;
     5         public List<NodeDef> LeftFolder = new List<NodeDef>();//String.Empty;
     6         public List<NodeVariable> RightVariable = new List<NodeVariable>();//String.Empty;
     7         public string nameAbsolutePath = string.Empty;
     8     }
     9 
    10     public class NodeVariable
    11     {
    12         public string name = string.Empty;
    13 
    14         public string nameFullPath = string.Empty;
    15     }

    OPC UA 统一架构 (二),讲讲如何读取和修改值。码杰-博客园

     

  • 相关阅读:
    ajaxFileUpload 实现多文件上传(源码)
    Springboot 热部署的两种方式
    基于树莓派3B+Python3.5的OpenCV3.4的配置教程
    Shiro 架构原理
    Cron表达式
    SpringBoot中Scheduled代码实现
    Linus安装mysql8
    查看虚拟机CENTOS7 的 IP 地址和命令
    linux vi保存退出命令 (如何退出vi)
    Linux常用命令大全
  • 原文地址:https://www.cnblogs.com/zizhijing/p/14299721.html
Copyright © 2011-2022 走看看