• 欢迎访问开心洋葱网站,在线教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入开心洋葱 QQ群
  • 为方便开心洋葱网用户,开心洋葱官网已经开启复制功能!
  • 欢迎访问开心洋葱网站,手机也能访问哦~欢迎加入开心洋葱多维思维学习平台 QQ群
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏开心洋葱吧~~~~~~~~~~~~~!
  • 由于近期流量激增,小站的ECS没能经的起亲们的访问,本站依然没有盈利,如果各位看如果觉着文字不错,还请看官给小站打个赏~~~~~~~~~~~~~!

OPC UA 统一架构 (一)

其他 开心洋葱 1251次浏览 0个评论

OPC UA 

一 、OPC UA简介

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

OPC UA 统一架构 (一)

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 统一架构 (一)

 

、OPC UA配置管理器

 1.OPC UA 

 其他家OPC配置界面

OPC UA 统一架构 (一)

OPC UA 统一架构 (一)

 

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

 

OPCFoundation/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设置

下图是配置设置界面

OPC UA 统一架构 (一)

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

 OPC UA 统一架构 (一)

OPC UA 统一架构 (一)

OPC UA 统一架构 (一)

 

  2.用户名验证

OPC UA 统一架构 (一)

  

  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)值对。

OPC UA 统一架构 (一)

 

类似二叉树数据结构

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

 

 OPC UA 统一架构 (一)

 

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 统一架构 (二),讲讲如何读取和修改值。码杰-博客园

 

 

 


开心洋葱 , 版权所有丨如未注明 , 均为原创丨未经授权请勿修改 , 转载请注明OPC UA 统一架构 (一)
喜欢 (0)

您必须 登录 才能发表评论!

加载中……