/// <summary> /// Get the Filter as per part 11 5.3.2: A Historical Event Node that /// has Event history available will provide the HistoricalEventFilter /// Property which has the filter used by the Server to determine which /// HistoricalEventNode fields are available in history. It may also /// include a where clause that indicates the types of Events or /// restrictions on the Events that are available via the Historical /// Event Node. /// </summary> /// <param name="ct"></param> /// <returns></returns> private Task <EventFilter> ReadEventFilterAsync(CancellationToken ct) { return(_client.ExecuteServiceAsync(_endpoint, _elevation, _priority, ct, async session => { _encoder.Context.UpdateFromSession(session); var nodeId = _nodeId.ToNodeId(session.MessageContext); var filterNode = await session.TranslateBrowsePathsToNodeIdsAsync(null, new BrowsePathCollection { new BrowsePath { StartingNode = nodeId, RelativePath = new RelativePath( BrowseNames.HistoricalEventFilter) } }); if (!filterNode.Results.Any() || !filterNode.Results[0].Targets.Any()) { return null; } var read = await RawNodeModel.ReadValueAsync(session, null, (NodeId)filterNode.Results[0].Targets[0].TargetId, _diagnostics, false); if (ExtensionObject.ToEncodeable(read.Value.Value as ExtensionObject) is EventFilter eventFilter) { return eventFilter; } return null; })); }
/// <summary> /// Read node /// </summary> /// <param name="nodeId"></param> /// <param name="ct"></param> /// <returns></returns> private async Task <BaseNodeModel> ReadNodeAsync(NodeId nodeId, CancellationToken ct) { try { // Read node with value return(await _client.ExecuteServiceAsync(_endpoint, _elevation, _priority, ct, async session => { _encoder.Context.UpdateFromSession(session); var node = await RawNodeModel.ReadAsync(session, _diagnostics.ToStackModel(), nodeId, false, Diagnostics, false); // Determine whether to read events or historic data later if (node.IsHistorizedNode) { _history.Add(node.LocalId, node.NodeId.AsString( session.MessageContext)); } else { // Otherwise mark as visited so we do not browse again. _visited.Add(nodeId); } var isProperty = (node.NodeClass == Opc.Ua.NodeClass.Variable || node.NodeClass == Opc.Ua.NodeClass.VariableType) && session.TypeTree.IsTypeOf(node.NodeId, VariableTypeIds.PropertyType); return node.ToNodeModel(isProperty); })); } catch (Exception ex) { _logger.Error(ex, "Failed reading node object for node {nodeId}.", nodeId); _visited.Add(nodeId); return(null); } }
/// <inheritdoc/> public async Task EncodeAsync(CancellationToken ct) { if (_count > 0) { throw new InvalidOperationException("Encoding already performed."); } bool eventSource; try { var node = await _client.ExecuteServiceAsync(_endpoint, _elevation, _priority, ct, async session => { _encoder.Context.UpdateFromSession(session); var nodeId = _nodeId.ToNodeId(session.MessageContext); return(await RawNodeModel.ReadAsync(session, null, nodeId, true, _diagnostics, false)); }); if (node.EventNotifier.HasValue && (node.EventNotifier.Value & EventNotifiers.HistoryRead) != 0) { eventSource = true; } else if (node.AccessLevel.HasValue && ((AccessLevelType)node.AccessLevel.Value & AccessLevelType.HistoryRead) != 0) { eventSource = false; } else { _logger.Error("{nodeId} has no history.", _nodeId); return; } } catch (Exception ex) { _logger.Error(ex, "Failed to retrieve node info for {nodeId}", _nodeId); return; } _logger.Verbose("Writing history for {nodeId}...", _nodeId); var sw = System.Diagnostics.Stopwatch.StartNew(); if (eventSource) { await EncodeHistoricEventsAsync(ct); } else { await EncodeHistoricValuesAsync(ct); } _logger.Debug("Wrote {count} items for {nodeId} in {elapsed}.", _count, _nodeId, sw.Elapsed); }