using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NX_CommonClassLibrary; using NX_LogClassLibrary; using NX_ModelClassLibrary.BaseModel; using NX_ModelClassLibrary.CustomEnum; using NX_ModelClassLibrary.CustomEvent; using NX_ModelClassLibrary.OpcModel; using NX_WcsDal.CommonBusiness; using Opc.Ua; using Opc.Ua.Client; using Opc.Ua.Configuration; using OpcUaHelper; namespace NX_OpcUaClientLibrary { /// /// OpcUa客户端帮助类 /// 基于OPC基金会开源的.net版本OPCUA客户端项目的二次封装 /// Copyright20210125 (C) sunyalong /// 允许修改、添加满足自己项目的需要。 /// 添加、修改后请详细注释。违者会强制删除不予采用。 /// public class LeadOpcUaClientHelper { #region 单例模式 /// /// 单例模式对象 /// private static LeadOpcUaClientHelper _instance = null; private static readonly object lockObj = new object(); /// /// 单例模式方法 /// public static LeadOpcUaClientHelper Instance { get { if (_instance == null) { lock (lockObj) { if (_instance == null) { _instance = new LeadOpcUaClientHelper(); } } } return _instance; } } #endregion #region 全局变量 /// /// 日志显示帮助类对象 /// public ShowLogToFrmHelper showLogToFrm = new ShowLogToFrmHelper(); /// /// 日志头部 /// private readonly string LogHeadText = "OpcUa客户端帮助类 ==>> "; /// /// OPCUA客户端列表 /// private ConcurrentDictionary opcUaClientLst = new ConcurrentDictionary(); /// /// 所有设备OPCItem变量信息列表 /// public List allOpcItemList; #region 2021 0602 孙亚龙注释掉旧版代码 ///// ///// 堆垛机OpcUa客户端 ///// //private OpcUaClient crn_OpcUaClient; ///// ///// 输送线OpcUa客户端 ///// //private OpcUaClient tran_OpcUaClient; ///// ///// 堆垛机OPC UA服务器地址 ///// //private readonly string CrnOpcUaServerIpAddress = AppConfigHelper.Get("CrnOpcUaServerIpAddress"); ///// ///// 输送线OPC UA服务器地址 ///// //private readonly string TranOpcUaServerIpAddress = AppConfigHelper.Get("TranOpcUaServerIpAddress"); ///// ///// 堆垛机OPC UA服务器连接状态 ///// //private bool CrnOpcUaServerConnStatus = false; ///// ///// 输送线OPC UA服务器连接状态 ///// //private bool TranOpcUaServerConnStatus = false; #endregion 2021 0602 孙亚龙注释掉旧版代码 #endregion /// /// 连接所有PLC的OPCUa服务器,并设置PLC的OPCItem变量为订阅模式。 /// /// WCS涉及的所有PLC信息列表 /// public bool ConnAllOpcUaServer(List basWcsPlcMdList) { try { foreach (BasWcsPlcMd item in basWcsPlcMdList) { if (opcUaClientLst.TryAdd(item, new OpcUaClient { UserIdentity = new UserIdentity("Administrator", "123456") })) { opcUaClientLst[item].ConnectServer(item.IpAddr); ShowLogToForm($"OpcUa客户端连接OpcUa服务器成功!IP地址:【{item.IpAddr}】", true, LogTypeEnum.Run); } } foreach (var item in opcUaClientLst) { string[] MonitorNodeTagArr = allOpcItemList.FindAll(x => x.PlcCode == item.Key.PlcCode).Select(x => x.OpcItemPos).ToArray(); item.Value.AddSubscription(item.Key.PlcCode, MonitorNodeTagArr, SubCallback); ShowLogToForm($"OpcUa客户端设置OpcItem订阅模式成功!IP地址:【{item.Key.IpAddr}】", true, LogTypeEnum.Run); } return true; } catch (Exception ex) { ShowLogToForm($"OpcUa客户端连接OpcUa服务器发生异常:【{ex.Message}】!", true, LogTypeEnum.Err); return false; } } #region 2021 0602 孙亚龙注释掉旧版代码 //public async Task ConnCrnOpcUaServer() //{ // try // { // crn_OpcUaClient = new OpcUaClient // { // UserIdentity = new UserIdentity("Administrator", "123456") // }; // await crn_OpcUaClient.ConnectServer(CrnOpcUaServerIpAddress); // ShowLogToForm($"堆垛机OpcUa客户端连接Opc服务器成功!IP地址:【{CrnOpcUaServerIpAddress}】", true, LogTypeEnum.Run); // CrnOpcUaServerConnStatus = true; // return true; // } // catch (Exception ex) // { // ShowLogToForm($"堆垛机OpcUa客户端连接Opc服务器发生异常:【{ex.Message}】!IP地址:【{CrnOpcUaServerIpAddress}】", true, LogTypeEnum.Err); // CrnOpcUaServerConnStatus = false; // return false; // } //} //public async Task ConnTranOpcUaServer() //{ // try // { // tran_OpcUaClient = new OpcUaClient // { // UserIdentity = new UserIdentity("Administrator", "123456") // }; // await tran_OpcUaClient.ConnectServer(TranOpcUaServerIpAddress); // ShowLogToForm($"输送线OpcUa客户端连接Opc服务器成功!IP地址:【{TranOpcUaServerIpAddress}】", true, LogTypeEnum.Run); // TranOpcUaServerConnStatus = true; // return true; // } // catch (Exception ex) // { // ShowLogToForm($"输送线OpcUa客户端连接Opc服务器发生异常:【{ex.Message}】!IP地址:【{TranOpcUaServerIpAddress}】", true, LogTypeEnum.Err); // TranOpcUaServerConnStatus = false; // return false; // } //} //public bool SetOpcItemSubscription() //{ // try // { // List MonitorNodeTags_Crn = new List(); // List MonitorNodeTags_Tran = new List(); // foreach (WcsOpcItemMd item in allOpcItemList) // { // if (item.PlcCode == "CrnPlc001") // { // MonitorNodeTags_Crn.Add(item.OpcItemPos); // } // if (item.PlcCode == "TranPlc001") // { // MonitorNodeTags_Tran.Add(item.OpcItemPos); // } // } // crn_OpcUaClient.AddSubscription("Crn", MonitorNodeTags_Crn.ToArray(), SubCallback); // ShowLogToForm($"堆垛机设置OpcItem订阅模式成功!", true, LogTypeEnum.Run); // tran_OpcUaClient.AddSubscription("Tran", MonitorNodeTags_Tran.ToArray(), SubCallback); // ShowLogToForm($"输送线设置OpcItem订阅模式成功!", true, LogTypeEnum.Run); // return true; // } // catch (Exception ex) // { // ShowLogToForm($"堆垛机设置OpcItem订阅模式发生异常:【{ex.Message}】!", true, LogTypeEnum.Err); // ShowLogToForm($"输送线设置OpcItem订阅模式发生异常:【{ex.Message}】!", true, LogTypeEnum.Err); // return false; // } //} #endregion 2021 0602 孙亚龙注释掉旧版代码 private void SubCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args) { MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification; WcsOpcItemMd tmpMonitoredOpcItem = allOpcItemList.FirstOrDefault(x => x.OpcItemPos == monitoredItem.StartNodeId.ToString() && x.PlcCode == key); if (tmpMonitoredOpcItem != null) { tmpMonitoredOpcItem.OpcItemValue = notification.Value.WrappedValue.Value.ToString(); Task.Run(() => { BasCommon_Dal.Instance.UpdateOpcItemMonitorToDataBase(tmpMonitoredOpcItem); }); } #region 2021 0602 孙亚龙注释掉旧版代码 //if (key == "Crn") //{ // MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification; // WcsOpcItemMd tmpMonitoredOpcItem = allOpcItemList.FirstOrDefault(x => x.OpcItemPos == monitoredItem.StartNodeId.ToString() && x.PlcCode == "CrnPlc001"); // if (tmpMonitoredOpcItem != null) // { // tmpMonitoredOpcItem.OpcItemValue = notification.Value.WrappedValue.Value.ToString(); // Task.Run(() => // { // BasCommon_Dal.Instance.UpdateOpcItemMonitorToDataBase(tmpMonitoredOpcItem); // }); // } //} //else if (key == "Tran") //{ // MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification; // WcsOpcItemMd tmpMonitoredOpcItem = allOpcItemList.FirstOrDefault(x => x.OpcItemPos == monitoredItem.StartNodeId.ToString() && x.PlcCode == "TranPlc001"); // if (tmpMonitoredOpcItem != null) // { // tmpMonitoredOpcItem.OpcItemValue = notification.Value.WrappedValue.Value.ToString(); // Task.Run(() => // { // BasCommon_Dal.Instance.UpdateOpcItemMonitorToDataBase(tmpMonitoredOpcItem); // }); // } //} #endregion 2021 0602 孙亚龙注释掉旧版代码 } /// /// 写入OPC变量值 /// /// opc变量对象 /// 写入值 /// public bool WriteOpcItemValue(WcsOpcItemMd wcsOpcItemMd, object value) { try { OpcUaClient tmpOpcUaClient = opcUaClientLst.Where(x => x.Key.PlcCode == wcsOpcItemMd.PlcCode).FirstOrDefault().Value; switch (wcsOpcItemMd.PlcItemDataType) { case 1: return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt32(value)); case 2: return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value.ToString()); case 3: return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToBoolean(value)); case 4: return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToDouble(value)); case 5: return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt16(value)); case 6: return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToByte(value)); default: return tmpOpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value); } #region 孙亚龙 20210602 注释旧版代码 //if (wcsOpcItemMd.PlcCode == "CrnPlc001") //{ // switch (wcsOpcItemMd.PlcItemDataType) // { // case 1: // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt32(value)); // case 2: // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value.ToString()); // case 3: // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToBoolean(value)); // case 4: // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToDouble(value)); // case 5: // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt16(value)); // case 6: // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToByte(value)); // default: // return crn_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value); // } //} //if (wcsOpcItemMd.PlcCode == "TranPlc001") //{ // switch (wcsOpcItemMd.PlcItemDataType) // { // case 1: // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt32(value)); // case 2: // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value.ToString()); // case 3: // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToBoolean(value)); // case 4: // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToDouble(value)); // case 5: // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToInt16(value)); // case 6: // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, Convert.ToByte(value)); // default: // return tran_OpcUaClient.WriteNode(wcsOpcItemMd.OpcItemPos, value); // } //} #endregion } catch(Exception ex) { ShowLogToForm($"OpcItem变量写入发生异常:【{ex.Message}】!设备名称:【{wcsOpcItemMd.DevName}】PLC:【{wcsOpcItemMd.PlcName}】OPC变量:【{wcsOpcItemMd.OpcItemCode}】变量OPC地址:【{wcsOpcItemMd.OpcItemPos}】写入值:【{value}】", true, LogTypeEnum.Err); return false; } } public void CloseConnect() { foreach (var item in opcUaClientLst) { item.Value.Disconnect(); } #region 孙亚龙 20210602 注释旧版代码 //if (CrnOpcUaServerConnStatus) //{ // crn_OpcUaClient.Disconnect(); //} //if (TranOpcUaServerConnStatus) //{ // tran_OpcUaClient.Disconnect(); //} #endregion } #region 桌面显示Log、记录log到文本 /// /// 桌面显示Log、记录log到文本 /// /// log内容 /// 是否输出到桌面日志端。true:输出桌面;false:只记录文本 /// 日志类型枚举 private void ShowLogToForm(string msg, bool isShowFormFlag, LogTypeEnum logTypeEnum) { if (isShowFormFlag) { showLogToFrm.ShowLog(new ShowLogToFrmEventArgs(LogHeadText + msg)); } LogHelper.WriteLog(LogHeadText + msg, logTypeEnum); } #endregion } }