public OpcUaDataItem(string name, int updateRate, Type valueType, object oldValue, object newValue, OpcUaStatusCodes opcUaStatusCodes) { this.Name = name; this.UpdateRate = updateRate; this.ValueType = valueType; this.OldValue = oldValue; this.NewValue = newValue; this.OpcUaStatusCodes = opcUaStatusCodes; }
public OpcUaDataEventArgs(OpcUaStatusCodes opcUaStatusCodes, OpcUaDataItem opcUaDataItem) { this.OpcUaStatusCodes = opcUaStatusCodes; this.OpcUaDataItem = opcUaDataItem; }
public OpcUaErrorEventArgs(OpcUaStatusCodes opcUaStatusCodes, string message, Exception exception) { this.OpcUaStatusCodes = opcUaStatusCodes; this.Message = message; this.Exception = exception; }
/// <summary> /// 注册监控的数据点 /// </summary> /// <param name="nodes"></param> /// <returns></returns> public async Task <OpcUaStatusCodes> RegisterNodes(List <OpcUaDataItem> nodes) { this.OpcUaDataItems = nodes; daemonTimer.Enabled = false; daemonTimer.Stop(); //如果未连接那么返回 if (!this.IsConnected) { OnErrorHappened?.Invoke(this, new OpcUaErrorEventArgs(OpcUaStatusCodes.Bad, $"{ToString()},未连接OPCUA服务器,请先连接在订阅数据项,", null)); return(OpcUaStatusCodes.Bad); } return(await Task <OpcUaStatusCodes> .Run(() => { OpcUaStatusCodes opcUaStatusCodes = OpcUaStatusCodes.Bad; if (session == null) { opcUaStatusCodes = OpcUaStatusCodes.BadSessionNotActivated; } try { if (Equals(null, nodes) && nodes.Count() < 1) { //没有数据 opcUaStatusCodes = OpcUaStatusCodes.BadInvalidArgument; } // 根据更新频率分组 var OpcUaNodeGroups = from a in nodes group a by a.UpdateRate into g select new { UpdateRate = g.Key, OpcUaNodes = g }; foreach (var OpcUaNodeGroup in OpcUaNodeGroups) { var subscription = session.Subscriptions.FirstOrDefault(a => a.DisplayName == OpcUaNodeGroup.UpdateRate.ToString()); //未找到已经订阅的组,那么新建组并添加订阅项,并关联监视事件句柄 if (Equals(null, subscription)) { #region 增加订阅 //创建订阅组。订阅组状态的名称是更新频率 //subscription = new Subscription(); subscription = new Subscription(session.DefaultSubscription); bool isAddSession = session.AddSubscription(subscription); subscription.Create(); subscription.PublishingInterval = OpcUaNodeGroup.UpdateRate; subscription.PublishingEnabled = true; subscription.LifetimeCount = 0; subscription.KeepAliveCount = 0; subscription.DisplayName = OpcUaNodeGroup.UpdateRate.ToString(); subscription.Priority = byte.MaxValue; List <MonitoredItem> monitoredItems = new List <MonitoredItem>(); foreach (var v in OpcUaNodeGroup.OpcUaNodes) { monitoredItems.Add(new MonitoredItem() { StartNodeId = new NodeId(v.Name), }); } //关联监视 monitoredItems.ForEach(a => a.Notification += OnMonitoredNotification); //foreach (var monitoredItem in monitoredItems) //{ // monitoredItem.Notification += OnMonitoredNotification; //} subscription.AddItems(monitoredItems); subscription.ApplyChanges(); if (isAddSession) { opcUaStatusCodes = OpcUaStatusCodes.BadSubscriptionIdInvalid; } else { opcUaStatusCodes = OpcUaStatusCodes.BadSubscriptionIdInvalid; } #endregion 增加订阅 } else//已经有订阅组,那么更新订阅项,没有的订阅移除,原有的订阅保留,新增的订阅增加 { //查询要删除的点 #region 更新订阅 //移除 //查询要删除的点 List <MonitoredItem> deleteItems = new List <MonitoredItem>(); foreach (var v in subscription.MonitoredItems) { if (!OpcUaNodeGroup.OpcUaNodes.Any(a => a.Name == v.StartNodeId)) { deleteItems.Add(v); } } deleteItems.ForEach(a => a.Notification -= OnMonitoredNotification); OnLogHappened?.BeginInvoke(this, new OpcUaLogEventArgs($"{ToString()},要删除的点数:{deleteItems.Count } "), new AsyncCallback((ia) => { if (ia.IsCompleted) { OnLogHappened.EndInvoke(ia); } }), null); if (!Equals(null, deleteItems) && deleteItems.Count() > 0) { subscription.RemoveItems(deleteItems); OnLogHappened?.Invoke(this, new OpcUaLogEventArgs($"{ToString()},已经删除的点数:{deleteItems.Count } ")); subscription.ApplyChanges(); } //新增 //查询要新增加的点, IList <OpcUaDataItem> addItems = new List <OpcUaDataItem>(); foreach (var v in OpcUaNodeGroup.OpcUaNodes) { if (!subscription.MonitoredItems.Any(a => a.StartNodeId.ToString() == v.Name)) { addItems.Add(v); } } var addMonitoredItems = from a in addItems select new MonitoredItem { StartNodeId = a.Name, AttributeId = Attributes.Value, DisplayName = a.Name, SamplingInterval = OpcUaNodeGroup.UpdateRate, MonitoringMode = MonitoringMode.Reporting, }; //关联监视 //addMonitoredItems.ToList().ForEach(a => a.Notification += OnMonitoredNotification); foreach (var monitoredItem in addMonitoredItems) { monitoredItem.Notification += OnMonitoredNotification; } //OnLogHappened?.Invoke(this, new OpcUaLogEventArgs($"{ToString()},要增加的点数:{addMonitoredItems.Count() } ")); OnLogHappened?.BeginInvoke(this, new OpcUaLogEventArgs($"{ToString()},要增加的点数:{addMonitoredItems.Count() } "), new AsyncCallback((ia) => { if (ia.IsCompleted) { OnLogHappened.EndInvoke(ia); } }), null); subscription.AddItems(addMonitoredItems); //OnLogHappened?.Invoke(this, new OpcUaLogEventArgs($"{ToString()},已经增加的点数:{addMonitoredItems.Count() } ")); OnLogHappened?.BeginInvoke(this, new OpcUaLogEventArgs($"{ToString()},已经增加的点数:{addMonitoredItems.Count() } "), new AsyncCallback((ia) => { if (ia.IsCompleted) { OnLogHappened.EndInvoke(ia); } }), null); //subscription.Create(); subscription.ApplyChanges(); #endregion 增加订阅 } }//endforeach //删除订阅项后没有item了,那么删除订阅subscription for (int i = session.Subscriptions.Count() - 1; i >= 0; i--) { var subscription = session.Subscriptions.ElementAt(i); OnLogHappened?.Invoke(this, new OpcUaLogEventArgs($"{ToString()},Subscription:{subscription.DisplayName},MonitoredItemCount:{subscription.MonitoredItemCount}")); if (subscription.MonitoredItemCount < 1) { subscription.Delete(false); session.RemoveSubscription(subscription); OnLogHappened?.Invoke(this, new OpcUaLogEventArgs($"{ToString()},Subscription:{subscription.DisplayName},MonitoredItemCount:{subscription.MonitoredItemCount}")); } //订阅组组减少时,需要删除组内的监视项,释放Notification,删除,订阅项 if (!OpcUaNodeGroups.Any(a => a.UpdateRate.ToString() == subscription.DisplayName)) { if (subscription.MonitoredItemCount > 0) { foreach (var monitoredItem in subscription.MonitoredItems) { monitoredItem.Notification -= OnMonitoredNotification; } OnLogHappened?.Invoke(this, new OpcUaLogEventArgs($"{ToString()},删除的点数:{subscription.MonitoredItems.Count() }")); subscription.RemoveItems(subscription.MonitoredItems); } subscription.Delete(false); session.RemoveSubscription(subscription); } } foreach (var subs in session.Subscriptions) { StringBuilder stringBuilder = new StringBuilder(); var badCount = 0; foreach (var v in subs.MonitoredItems) { if (!Equals(v.Status.Error, null) && v.Status.Error.StatusCode.Code != StatusCodes.Good) { stringBuilder.Append("点名:"); stringBuilder.Append(v?.StartNodeId?.ToString()); stringBuilder.Append(",状态:"); stringBuilder.Append(v?.Status?.Error?.StatusCode.ToString()); stringBuilder.AppendLine(); badCount = badCount + 1; } } int tolal = subs.MonitoredItems.Count(); OnLogHappened?. Invoke(this, new OpcUaLogEventArgs($"{ToString()},订阅组名:{subs.DisplayName},节点质量统计(Good/NotGood/Total):{tolal - badCount}/{badCount}/{tolal}{System.Environment.NewLine}{stringBuilder.ToString()}")); } opcUaStatusCodes = OpcUaStatusCodes.Good; } catch (ServiceResultException e) { OnErrorHappened?.Invoke(this, new OpcUaErrorEventArgs((OpcUaStatusCodes)e.StatusCode, $"{ToString()},订阅数据时错误", e)); opcUaStatusCodes = OpcUaStatusCodes.BadServerHalted; } catch (Exception ex) { OnErrorHappened?.Invoke(this, new OpcUaErrorEventArgs(OpcUaStatusCodes.Uncertain, $"{ToString()},订阅数据时发生未知错误", ex)); opcUaStatusCodes = OpcUaStatusCodes.Uncertain; } finally { daemonTimer.Enabled = true; daemonTimer.Start(); } return opcUaStatusCodes; })); }