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開發的。

 

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設置

下圖是配置設置界面

  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 統一架構 (二),講講如何讀取和修改值。碼傑-博客園

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM