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
}
}