private void SetOperatorMI_Click(object sender, EventArgs e) { try { ContentFilterElement element = SelectedTag as ContentFilterElement; if (element == null) { return; } FilterOperator op = element.FilterOperator; if (!new FilterOperatorEditDlg().ShowDialog(ref op)) { return; } element.FilterOperator = op; UpdateItem(ItemsLV.SelectedItems[0], element); AdjustColumns(); } catch (Exception exception) { GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception); } }
public void InList(object operandFirst1, object operandFirst2, object operandFirst3, object operandFirst4, object expectedResult) { LiteralOperand loperand1 = new LiteralOperand(); LiteralOperand loperand2 = new LiteralOperand(); LiteralOperand loperand3 = new LiteralOperand(); LiteralOperand loperand4 = new LiteralOperand(); loperand1.Value = new Variant(operandFirst1); loperand2.Value = new Variant(operandFirst2); loperand3.Value = new Variant(operandFirst3); loperand4.Value = new Variant(operandFirst4); ContentFilterElement filterElement = new ContentFilterElement(); filterElement.FilterOperator = FilterOperator.InList; filterElement.SetOperands(new List <LiteralOperand>() { loperand1, loperand2, loperand3, loperand4 }); Filter.WhereClause.Elements = new[] { filterElement }; // apply filter. object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget); Assert.AreEqual(expectedResult, result); }
public void BinaryFilterOperators(object operandFirst1, object operandFirst2, FilterOperator filterOp, object expectedResult) { LiteralOperand loperand1 = new LiteralOperand(); LiteralOperand loperand2 = new LiteralOperand(); loperand1.Value = new Variant(operandFirst1); if (filterOp == FilterOperator.Cast) { NodeId uintNoid = new NodeId(operandFirst2, 0); loperand2.Value = new Variant(uintNoid); } else { loperand2.Value = new Variant(operandFirst2); } ContentFilterElement filterElement = new ContentFilterElement(); filterElement.FilterOperator = filterOp; filterElement.SetOperands(new List <LiteralOperand>() { loperand1, loperand2 }); Filter.WhereClause.Elements = new[] { filterElement }; // apply filter. object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget); Assert.AreEqual(expectedResult, result); }
/// <summary> /// Returns the where clause defined by the filter declaration. /// </summary> public ContentFilter GetWhereClause() { ContentFilter whereClause = new ContentFilter(); ContentFilterElement element1 = whereClause.Push(FilterOperator.OfType, EventTypeId); EventFilter filter = new EventFilter(); foreach (FilterDeclarationField field in Fields) { if (field.FilterEnabled) { SimpleAttributeOperand operand1 = new SimpleAttributeOperand(); operand1.TypeDefinitionId = field.InstanceDeclaration.RootTypeId; operand1.AttributeId = (field.InstanceDeclaration.NodeClass == NodeClass.Object) ? Attributes.NodeId : Attributes.Value; operand1.BrowsePath = field.InstanceDeclaration.BrowsePath; LiteralOperand operand2 = new LiteralOperand(); operand2.Value = field.FilterValue; ContentFilterElement element2 = whereClause.Push(field.FilterOperator, operand1, operand2); element1 = whereClause.Push(FilterOperator.And, element1, element2); } } return(whereClause); }
public void NonBoolWithUnary(object operandFirst1, object operandFirst2, FilterOperator filterOp1, FilterOperator filterOp2, object expectedResult) { // Setup the First ContentfilterElement (the BitwiseOr or BitwiseAnd filter operation) LiteralOperand loperand1 = new LiteralOperand(); LiteralOperand loperand2 = new LiteralOperand(); loperand1.Value = new Variant(operandFirst1); if (filterOp1 == FilterOperator.Cast) { NodeId uintNoid = new NodeId(operandFirst2, 0); loperand2.Value = new Variant(uintNoid); } else { loperand2.Value = new Variant(operandFirst2); } ContentFilterElement filterElement1 = new ContentFilterElement(); filterElement1.FilterOperator = filterOp1; filterElement1.SetOperands(new List<FilterOperand>() { loperand1, loperand2 }); // Setup the Second ContentfilterElement ElementOperand elementOperand = new ElementOperand(); elementOperand.Index = 1; // link to filterElement1 ContentFilterElement filterElement2 = new ContentFilterElement(); filterElement2.FilterOperator = filterOp2; filterElement2.SetOperands(new List<FilterOperand>() { elementOperand }); Filter.WhereClause.Elements = new[] { filterElement2, filterElement1 }; // apply filter. object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget); Assert.AreEqual(expectedResult, result); }
private void EditValueMI_Click(object sender, EventArgs e) { try { ContentFilterElement element = SelectedTag as ContentFilterElement; if (element == null) { return; } List <FilterOperand> operands = element.GetOperands(); if (operands.Count != 2) { return; } LiteralOperand literal = operands[1] as LiteralOperand; if (literal == null) { return; } // get the current value. object currentValue = literal.Value.Value; if (currentValue == null) { currentValue = String.Empty; } // edit the value. object value = new SimpleValueEditDlg().ShowDialog(currentValue, currentValue.GetType()); if (value == null) { return; } // update value. literal.Value = new Variant(value); ContentFilter filter = GetFilter(); Update(filter); } catch (Exception exception) { GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception); } }
/// <see cref="BaseListCtrl.UpdateItem" /> protected override void UpdateItem(ListViewItem listItem, object item, int index) { ContentFilterElement element = item as ContentFilterElement; if (element == null) { base.UpdateItem(listItem, item); return; } listItem.SubItems[0].Text = String.Format("[{0}]", index); listItem.SubItems[1].Text = String.Format("{0}", element.ToString(m_session.NodeCache)); listItem.Tag = element; }
public void UnaryFilterOperators(object operandFirst1, FilterOperator filterOp, object expectedResult) { LiteralOperand loperand1 = new LiteralOperand(); loperand1.Value = new Variant(operandFirst1); ContentFilterElement filterElement = new ContentFilterElement(); filterElement.FilterOperator = filterOp; filterElement.SetOperands(new List<LiteralOperand>() { loperand1 }); Filter.WhereClause.Elements = new[] { filterElement }; // apply filter. object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget); Assert.AreEqual(expectedResult, result); }
/// <summary> /// Returns the list of elements in the control. /// </summary> public List <ContentFilterElement> GetElements() { List <ContentFilterElement> elements = new List <ContentFilterElement>(); for (int ii = 0; ii < ItemsLV.Items.Count; ii++) { ContentFilterElement element = ItemsLV.Items[ii].Tag as ContentFilterElement; if (element != null) { elements.Add(element); } } return(elements); }
/// <summary> /// Returns the filter in the control. /// </summary> public ContentFilter GetFilter() { ContentFilter filter = new ContentFilter(); for (int ii = 0; ii < ItemsLV.Items.Count; ii++) { ContentFilterElement element = ItemsLV.Items[ii].Tag as ContentFilterElement; if (element != null) { filter.Elements.Add(element); } } return(filter); }
/// <summary> /// Convert to service model /// </summary> /// <param name="model"></param> /// <param name="encoder"></param> /// <returns></returns> public static ContentFilterElementModel Encode(this IVariantEncoder encoder, ContentFilterElement model) { if (model == null) { return(null); } return(new ContentFilterElementModel { FilterOperands = model.FilterOperands .Select(e => e.Body) .Cast <FilterOperand>() .Select(o => encoder.Encode(o)) .ToList(), FilterOperator = model.FilterOperator.ToServiceType() }); }
private void CreateElementNotMI_Click(object sender, EventArgs e) { try { if (ItemsLV.SelectedItems.Count != 1) { return; } ContentFilterElement element1 = ItemsLV.SelectedItems[0].Tag as ContentFilterElement; ContentFilter filter = GetFilter(); filter.Push(FilterOperator.Not, element1); Update(filter); } catch (Exception exception) { GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception); } }
private static void QueryFirstCall(Session session) { ViewDescription vd = new ViewDescription(); vd.ViewId = 5000; vd.ViewVersion = 0; NodeTypeDescriptionCollection nt = new NodeTypeDescriptionCollection(); NodeTypeDescription ntd = new NodeTypeDescription(); ExpandedNodeId enid = new ExpandedNodeId("ns=3;s=AirConditioner_1"); ntd.TypeDefinitionNode = enid; nt.Add(ntd); ContentFilterElement cfe = new ContentFilterElement(); ContentFilterElementCollection cfec = new ContentFilterElementCollection(); cfec.Add(cfe); ContentFilter cf = new ContentFilter(); cf.Elements = cfec; QueryDataSetCollection qdsc = new QueryDataSetCollection(); byte[] cp = new byte[100]; ParsingResultCollection prc = new ParsingResultCollection(); DiagnosticInfoCollection dic = new DiagnosticInfoCollection(); ContentFilterResult cfr = new ContentFilterResult(); try { var rs = session.QueryFirst(null, vd, nt, cf, 1000, 1000, out qdsc, out cp, out prc, out dic, out cfr); } catch (Exception eX) { Console.WriteLine("EXCEPTION: QueryFirst : {0}", eX.Message); } }
/// <summary> /// Returns the subscription filter to use. /// </summary> public EventFilter GetFilter() { ContentFilter whereClause = new ContentFilter(); ContentFilterElement element1 = whereClause.Push(FilterOperator.OfType, EventTypeId); EventFilter filter = new EventFilter(); for (int ii = 0; ii < Fields.Count; ii++) { filter.SelectClauses.Add(Fields[ii].Operand); if (Fields[ii].FilterValue != Variant.Null) { LiteralOperand operand = new LiteralOperand(); operand.Value = Fields[ii].FilterValue; ContentFilterElement element2 = whereClause.Push(Fields[ii].FilterOperator, Fields[ii].Operand, operand); element1 = whereClause.Push(FilterOperator.And, element1, element2); } } filter.WhereClause = whereClause; return(filter); }
private void SelectNodeMI_Click(object sender, EventArgs e) { try { ReferenceDescription reference = new SelectNodeDlg().ShowDialog(m_browser, ObjectTypes.BaseEventType); if (reference != null) { Node node = m_session.NodeCache.Find(reference.NodeId) as Node; if (node == null) { return; } ContentFilterElement element = null; // build the relative path. QualifiedNameCollection browsePath = new QualifiedNameCollection(); NodeId typeId = m_session.NodeCache.BuildBrowsePath(node, browsePath); switch (node.NodeClass) { case NodeClass.Variable: { IVariable variable = node as IVariable; if (variable == null) { break; } // create attribute operand. SimpleAttributeOperand attribute = new SimpleAttributeOperand( m_session.FilterContext, typeId, browsePath); // create default value. object value = GuiUtils.GetDefaultValue(variable.DataType, variable.ValueRank); // create attribute filter. element = m_filter.Push(FilterOperator.Equals, attribute, value); break; } case NodeClass.Object: { // create attribute operand. SimpleAttributeOperand attribute = new SimpleAttributeOperand( m_session.FilterContext, typeId, browsePath); attribute.AttributeId = Attributes.NodeId; // create attribute filter. element = m_filter.Push(FilterOperator.IsNull, attribute); break; } case NodeClass.ObjectType: { element = m_filter.Push(FilterOperator.OfType, node.NodeId); break; } default: { throw new ArgumentException("Selected an invalid node."); } } // add element. if (element != null) { AddItem(element); AdjustColumns(); } } } catch (Exception exception) { GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception); } }
/// <summary> /// Returns the where clause defined by the filter declaration. /// </summary> private ContentFilter GetWhereClause() { ContentFilter whereClause = new ContentFilter(); ContentFilterElement element1 = null; // filter by source. if (SelectedSources != null && SelectedSources.Count > 0) { SimpleAttributeOperand operand1 = new SimpleAttributeOperand(); operand1.TypeDefinitionId = Opc.Ua.ObjectTypeIds.BaseEventType; operand1.AttributeId = Attributes.Value; operand1.BrowsePath.Add(new QualifiedName(Opc.Ua.BrowseNames.SourceNode)); for (int ii = 0; ii < SelectedSources.Count; ii++) { LiteralOperand operand2 = new LiteralOperand(); operand2.Value = SelectedSources[ii]; ContentFilterElement element2 = whereClause.Push(FilterOperator.Equals, operand1, operand2); element1 = (element1 != null)?whereClause.Push(FilterOperator.Or, element1, element2):element2; } } // add condition/tracking categories if no other categories selected. if (RevisedCategories == null || RevisedCategories.Count == 0) { if (EventTypes == (OpcRcw.Ae.Constants.SIMPLE_EVENT | OpcRcw.Ae.Constants.TRACKING_EVENT)) { ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.ConditionType); ContentFilterElement element3 = whereClause.Push(FilterOperator.Not, element2); element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element3) : element3; } else if (EventTypes == (OpcRcw.Ae.Constants.SIMPLE_EVENT | OpcRcw.Ae.Constants.CONDITION_EVENT)) { ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.AuditEventType); ContentFilterElement element3 = whereClause.Push(FilterOperator.Not, element2); ContentFilterElement element4 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.TransitionEventType); ContentFilterElement element5 = whereClause.Push(FilterOperator.Not, element4); ContentFilterElement element6 = whereClause.Push(FilterOperator.Or, element3, element5); element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element6) : element6; } else if (EventTypes == (OpcRcw.Ae.Constants.TRACKING_EVENT | OpcRcw.Ae.Constants.CONDITION_EVENT)) { ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.AuditEventType); ContentFilterElement element3 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.TransitionEventType); ContentFilterElement element4 = whereClause.Push(FilterOperator.Or, element2, element3); ContentFilterElement element5 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.ConditionType); ContentFilterElement element6 = whereClause.Push(FilterOperator.Or, element4, element5); element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element6) : element6; } else if (EventTypes == OpcRcw.Ae.Constants.TRACKING_EVENT) { ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.AuditEventType); ContentFilterElement element3 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.TransitionEventType); ContentFilterElement element4 = whereClause.Push(FilterOperator.Or, element2, element3); element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element4) : element4; } else if (EventTypes == OpcRcw.Ae.Constants.CONDITION_EVENT) { ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.ConditionType); element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element2) : element2; } else if (EventTypes == OpcRcw.Ae.Constants.SIMPLE_EVENT) { ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.AuditEventType); ContentFilterElement element3 = whereClause.Push(FilterOperator.Not, element2); ContentFilterElement element4 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.TransitionEventType); ContentFilterElement element5 = whereClause.Push(FilterOperator.Not, element4); ContentFilterElement element6 = whereClause.Push(FilterOperator.Or, element3, element5); ContentFilterElement element7 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.ConditionType); ContentFilterElement element8 = whereClause.Push(FilterOperator.Not, element7); element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element8) : element8; } } // filter by event type. if (RevisedCategories.Count > 0) { SimpleAttributeOperand operand1 = new SimpleAttributeOperand(); operand1.TypeDefinitionId = Opc.Ua.ObjectTypeIds.BaseEventType; operand1.AttributeId = Attributes.Value; operand1.BrowsePath.Add(new QualifiedName(Opc.Ua.BrowseNames.EventType)); ContentFilterElement element3 = null; for (int ii = 0; ii < RevisedCategories.Count; ii++) { ContentFilterElement element2 = whereClause.Push(FilterOperator.Equals, operand1, RevisedCategories[ii].TypeId); element3 = (element3 != null) ? whereClause.Push(FilterOperator.Or, element2, element3) : element2; } element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element3) : element3; } // filter by severity. if (LowSeverity > 1 || HighSeverity < 1000) { SimpleAttributeOperand operand1 = new SimpleAttributeOperand(); operand1.TypeDefinitionId = Opc.Ua.ObjectTypeIds.BaseEventType; operand1.AttributeId = Attributes.Value; operand1.BrowsePath.Add(new QualifiedName(Opc.Ua.BrowseNames.Severity)); if (LowSeverity > 1) { LiteralOperand operand2 = new LiteralOperand(); operand2.Value = LowSeverity; ContentFilterElement element2 = whereClause.Push(FilterOperator.GreaterThanOrEqual, operand1, operand2); element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element2) : element2; } if (HighSeverity < 1000) { LiteralOperand operand2 = new LiteralOperand(); operand2.Value = HighSeverity; ContentFilterElement element2 = whereClause.Push(FilterOperator.LessThanOrEqual, operand1, operand2); element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element2) : element2; } } return(whereClause); }
/// <summary> /// Constructs the event filter for the subscription. /// </summary> /// <returns>The event filter.</returns> public EventFilter ConstructFilter(Session session) { EventFilter filter = new EventFilter(); // the select clauses specify the values returned with each event notification. filter.SelectClauses = SelectClauses; // the where clause restricts the events returned by the server. // it works a lot like the WHERE clause in a SQL statement and supports // arbitrary expession trees where the operands are literals or event fields. ContentFilter whereClause = new ContentFilter(); // the code below constructs a filter that looks like this: // (Severity >= X OR LastSeverity >= X) AND (SuppressedOrShelved == False) AND (OfType(A) OR OfType(B)) // add the severity. ContentFilterElement element1 = null; ContentFilterElement element2 = null; if (Severity > EventSeverity.Min) { // select the Severity property of the event. SimpleAttributeOperand operand1 = new SimpleAttributeOperand(); operand1.TypeDefinitionId = ObjectTypeIds.BaseEventType; operand1.BrowsePath.Add(BrowseNames.Severity); operand1.AttributeId = Attributes.Value; // specify the value to compare the Severity property with. LiteralOperand operand2 = new LiteralOperand(); operand2.Value = new Variant((ushort)Severity); // specify that the Severity property must be GreaterThanOrEqual the value specified. element1 = whereClause.Push(FilterOperator.GreaterThanOrEqual, operand1, operand2); } // add the event types. if (EventTypes != null && EventTypes.Count > 0) { element2 = null; // save the last element. for (int ii = 0; ii < EventTypes.Count; ii++) { // for this example uses the 'OfType' operator to limit events to thoses with specified event type. LiteralOperand operand1 = new LiteralOperand(); operand1.Value = new Variant(EventTypes[ii]); ContentFilterElement element3 = whereClause.Push(FilterOperator.OfType, operand1); // need to chain multiple types together with an OR clause. if (element2 != null) { element2 = whereClause.Push(FilterOperator.Or, element2, element3); } else { element2 = element3; } } // need to link the set of event types with the previous filters. if (element1 != null) { whereClause.Push(FilterOperator.And, element1, element2); } } filter.WhereClause = whereClause; // return filter. return(filter); }
/// <summary> /// Monitoring for an event source starts if it is required. /// </summary> public async Task MonitorEventsAsync(CancellationToken ct) { bool sessionLocked = false; try { try { sessionLocked = await LockSessionAsync().ConfigureAwait(false); // if the session is not connected or shutdown in progress, return if (!sessionLocked || ct.IsCancellationRequested || State != SessionState.Connected) { return; } } catch (Exception) { throw; } // ensure all nodes in all subscriptions of this session are monitored. foreach (var opcEventSubscription in OpcEventSubscriptions) { // create the subscription, if it is not yet there. if (opcEventSubscription.OpcUaClientSubscription == null) { opcEventSubscription.OpcUaClientSubscription = CreateSubscription(opcEventSubscription.RequestedPublishingInterval, out int revisedPublishingInterval); opcEventSubscription.PublishingInterval = revisedPublishingInterval; Logger.Information($"Create Event subscription on endpoint '{EndpointUrl}' requested OPC publishing interval is {opcEventSubscription.RequestedPublishingInterval} ms. (revised: {revisedPublishingInterval} ms)"); } // process all unmonitored events. var unmonitoredEvents = opcEventSubscription.OpcMonitoredItems.Where(i => (i.State == OpcMonitoredItemState.Unmonitored || i.State == OpcMonitoredItemState.UnmonitoredNamespaceUpdateRequested)); int additionalMonitoredEventsCount = 0; int monitoredEventsCount = 0; bool haveUnmonitoredEvents = false; if (unmonitoredEvents.Count() != 0) { haveUnmonitoredEvents = true; monitoredEventsCount = opcEventSubscription.OpcMonitoredItems.Count(i => (i.State == OpcMonitoredItemState.Monitored)); Logger.Information($"Start monitoring events on endpoint '{EndpointUrl}'. Currently monitoring {monitoredEventsCount} events."); } // init perf data Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); foreach (var unmonitoredEvent in unmonitoredEvents) { // if the session is not connected or a shutdown is in progress, we stop trying and wait for the next cycle if (ct.IsCancellationRequested || State != SessionState.Connected) { break; } NodeId currentNodeId = null; try { // update the namespace of the node if requested. there are two cases where this is requested: // 1) publishing requests via the OPC server method are raised using a NodeId format. for those // the NodeId format is converted into an ExpandedNodeId format // 2) ExpandedNodeId configuration file entries do not have at parsing time a session to get // the namespace index. this is set now. if (unmonitoredEvent.State == OpcMonitoredItemState.UnmonitoredNamespaceUpdateRequested) { if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.ExpandedNodeId) { ExpandedNodeId expandedNodeId = ExpandedNodeId.Parse(unmonitoredEvent.Id); int namespaceIndex = _namespaceTable.GetIndex(expandedNodeId.NamespaceUri); if (namespaceIndex < 0) { Logger.Information($"The namespace URI of node '{expandedNodeId.ToString()}' can be not mapped to a namespace index."); } else { unmonitoredEvent.IdAsExpandedNodeId = expandedNodeId; } } if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.NodeId) { NodeId nodeId = NodeId.Parse(unmonitoredEvent.Id); string namespaceUri = _namespaceTable.ToArray().ElementAtOrDefault(nodeId.NamespaceIndex); if (string.IsNullOrEmpty(namespaceUri)) { Logger.Information($"The namespace index of node '{nodeId.ToString()}' is invalid and the node format can not be updated."); } else { unmonitoredEvent.IdAsExpandedNodeId = new ExpandedNodeId(nodeId.Identifier, nodeId.NamespaceIndex, namespaceUri, 0); unmonitoredEvent.ConfigType = OpcMonitoredItemConfigurationType.ExpandedNodeId; } } unmonitoredEvent.State = OpcMonitoredItemState.Unmonitored; } // lookup namespace index if ExpandedNodeId format has been used and build NodeId identifier. if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.ExpandedNodeId) { ExpandedNodeId expandedNodeId = ExpandedNodeId.Parse(unmonitoredEvent.Id); int namespaceIndex = _namespaceTable.GetIndex(expandedNodeId.NamespaceUri); if (namespaceIndex < 0) { Logger.Warning($"Syntax or namespace URI of ExpandedNodeId '{expandedNodeId.ToString()}' is invalid and will be ignored."); continue; } unmonitoredEvent.IdAsNodeId = new NodeId(expandedNodeId.Identifier, expandedNodeId.NamespaceIndex); currentNodeId = unmonitoredEvent.IdAsNodeId; } else { NodeId nodeId = NodeId.Parse(unmonitoredEvent.Id); string namespaceUri = _namespaceTable.ToArray().ElementAtOrDefault(nodeId.NamespaceIndex); if (string.IsNullOrEmpty(namespaceUri)) { Logger.Information($"The namespace index of node '{nodeId.ToString()}' is invalid and the node format can not be updated."); } else { unmonitoredEvent.IdAsExpandedNodeId = new ExpandedNodeId(nodeId.Identifier, nodeId.NamespaceIndex, namespaceUri, 0); currentNodeId = nodeId; } } // if configured, get the key for the node, otherwise use the nodeId Node node; if (string.IsNullOrEmpty(unmonitoredEvent.Key)) { if (FetchOpcNodeDisplayName == true) { node = OpcUaClientSession.ReadNode(currentNodeId); unmonitoredEvent.Key = node.DisplayName.Text ?? currentNodeId.ToString(); } else { unmonitoredEvent.Key = currentNodeId.ToString(); } } // resolve all node and namespace references in the select and where clauses EventFilter eventFilter = new EventFilter(); foreach (var selectClause in unmonitoredEvent.EventConfiguration.SelectClauses) { SimpleAttributeOperand simpleAttributeOperand = new SimpleAttributeOperand(); simpleAttributeOperand.AttributeId = selectClause.AttributeId.ResolveAttributeId(); simpleAttributeOperand.IndexRange = selectClause.IndexRange; NodeId typeId = selectClause.TypeId.ToNodeId(_namespaceTable); simpleAttributeOperand.TypeDefinitionId = new NodeId(typeId); QualifiedNameCollection browsePaths = new QualifiedNameCollection(); foreach (var browsePath in selectClause.BrowsePaths) { browsePaths.Add(QualifiedName.Parse(browsePath)); } simpleAttributeOperand.BrowsePath = browsePaths; eventFilter.SelectClauses.Add(simpleAttributeOperand); } foreach (var whereClauseElement in unmonitoredEvent.EventConfiguration.WhereClause) { ContentFilterElement contentFilterElement = new ContentFilterElement(); contentFilterElement.FilterOperator = whereClauseElement.Operator.ResolveFilterOperator(); switch (contentFilterElement.FilterOperator) { case FilterOperator.OfType: case FilterOperator.InView: if (whereClauseElement.Operands.Count != 1) { Logger.Error($"The where clause element '{whereClauseElement.ToString()}' must contain 1 operands."); continue; } FilterOperand[] filterOperands = new FilterOperand[1]; TypeInfo typeInfo = new TypeInfo(BuiltInType.NodeId, ValueRanks.Scalar); filterOperands[0] = whereClauseElement.Operands[0].GetOperand(typeInfo); eventFilter.WhereClause.Push(contentFilterElement.FilterOperator, filterOperands); break; case FilterOperator.Equals: case FilterOperator.IsNull: case FilterOperator.GreaterThan: case FilterOperator.LessThan: case FilterOperator.GreaterThanOrEqual: case FilterOperator.LessThanOrEqual: case FilterOperator.Like: case FilterOperator.Not: case FilterOperator.Between: case FilterOperator.InList: case FilterOperator.And: case FilterOperator.Or: case FilterOperator.Cast: case FilterOperator.BitwiseAnd: case FilterOperator.BitwiseOr: case FilterOperator.RelatedTo: default: Logger.Error($"The operator '{contentFilterElement.FilterOperator.ToString()}' is not supported."); break; } } // add the new monitored event. IOpcUaMonitoredItem monitoredItem = new OpcUaMonitoredItem() { StartNodeId = currentNodeId, AttributeId = Attributes.EventNotifier, DisplayName = unmonitoredEvent.Key, MonitoringMode = unmonitoredEvent.MonitoringMode, SamplingInterval = 0, QueueSize = unmonitoredEvent.QueueSize, DiscardOldest = unmonitoredEvent.DiscardOldest, Filter = eventFilter }; monitoredItem.Notification += unmonitoredEvent.NotificationEventHandler; opcEventSubscription.OpcUaClientSubscription.AddItem(monitoredItem); unmonitoredEvent.OpcUaClientMonitoredItem = monitoredItem; unmonitoredEvent.State = OpcMonitoredItemState.Monitored; unmonitoredEvent.EndpointUrl = EndpointUrl; Logger.Verbose($"Created monitored event for node '{currentNodeId.ToString()}' in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}' on endpoint '{EndpointUrl}' (version: {NodeConfigVersion:X8})"); if (unmonitoredEvent.RequestedSamplingInterval != monitoredItem.SamplingInterval) { Logger.Information($"Sampling interval: requested: {unmonitoredEvent.RequestedSamplingInterval}; revised: {monitoredItem.SamplingInterval}"); unmonitoredEvent.SamplingInterval = monitoredItem.SamplingInterval; } if (additionalMonitoredEventsCount % 10000 == 0) { Logger.Information($"Now monitoring {monitoredEventsCount + additionalMonitoredEventsCount} events in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}'"); } } catch (Exception e) when(e.GetType() == typeof(ServiceResultException)) { ServiceResultException sre = (ServiceResultException)e; switch ((uint)sre.Result.StatusCode) { case StatusCodes.BadSessionIdInvalid: { Logger.Information($"Session with Id {OpcUaClientSession.SessionId} is no longer available on endpoint '{EndpointUrl}'. Cleaning up."); // clean up the session InternalDisconnect(); break; } case StatusCodes.BadNodeIdInvalid: case StatusCodes.BadNodeIdUnknown: { Logger.Error($"Failed to monitor node '{currentNodeId}' on endpoint '{EndpointUrl}'."); Logger.Error($"OPC UA ServiceResultException is '{sre.Result}'. Please check your publisher configuration for this node."); break; } default: { Logger.Error($"Unhandled OPC UA ServiceResultException '{sre.Result}' when monitoring node '{currentNodeId}' on endpoint '{EndpointUrl}'. Continue."); break; } } } catch (Exception e) { Logger.Error(e, $"Failed to monitor node '{currentNodeId}' on endpoint '{EndpointUrl}'"); } } opcEventSubscription.OpcUaClientSubscription.SetPublishingMode(true); opcEventSubscription.OpcUaClientSubscription.ApplyChanges(); stopWatch.Stop(); if (haveUnmonitoredEvents == true) { monitoredEventsCount = opcEventSubscription.OpcMonitoredItems.Count(i => (i.State == OpcMonitoredItemState.Monitored)); Logger.Information($"Done processing unmonitored events on endpoint '{EndpointUrl}' took {stopWatch.ElapsedMilliseconds} msec. Now monitoring {monitoredEventsCount} events in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}'."); } } } catch (Exception e) { Logger.Error(e, "Exception"); } finally { if (sessionLocked) { ReleaseSession(); } } }