/// <summary> /// Releases any continuation points. /// </summary> private void ReleaseContinuationPoints() { if (m_details != null) { HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection(); nodesToRead.Add(m_nodeToRead); HistoryReadResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; m_session.HistoryRead( null, new ExtensionObject(m_details), TimestampsToReturn.Neither, true, nodesToRead, out results, out diagnosticInfos); Session.ValidateResponse(results, nodesToRead); Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); NextBTN.Visible = false; StopBTN.Enabled = false; GoBTN.Visible = true; m_details = null; m_nodeToRead = null; } }
/// <summary> /// Starts a new read operation. /// </summary> private void ReadFirst() { ResultsLV.ClearEventHistory(); // set up the request parameters. ReadEventDetails details = new ReadEventDetails(); details.StartTime = DateTime.MinValue; details.EndTime = DateTime.MinValue; details.NumValuesPerNode = 0; details.Filter = m_filter.GetFilter(); if (StartTimeCK.Checked) { details.StartTime = StartTimeDP.Value.ToUniversalTime(); } if (EndTimeCK.Checked) { details.EndTime = EndTimeDP.Value.ToUniversalTime(); } if (MaxReturnValuesCK.Checked) { details.NumValuesPerNode = (uint)MaxReturnValuesNP.Value; } // read the events from the server. HistoryReadValueId nodeToRead = new HistoryReadValueId(); nodeToRead.NodeId = m_areaId; ReadNext(details, nodeToRead); }
private ExtensionObject ReadEventDetails() { ReadEventDetails details = new ReadEventDetails { NumValuesPerNode = 10, StartTime = DateTime.UtcNow.AddSeconds(30), EndTime = DateTime.UtcNow.AddHours(-1), }; return(new ExtensionObject(details)); }
/// <summary> /// Continues a read operation. /// </summary> private void ReadNext(ReadEventDetails details, HistoryReadValueId nodeToRead) { HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection(); nodesToRead.Add(nodeToRead); HistoryReadResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; ResponseHeader responseHeader = m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, false, nodesToRead, out results, out diagnosticInfos); Session.ValidateResponse(results, nodesToRead); Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); if (StatusCode.IsBad(results[0].StatusCode)) { throw ServiceResultException.Create(results[0].StatusCode, 0, diagnosticInfos, responseHeader.StringTable); } // display results. HistoryEvent data = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryEvent; ResultsLV.AddEventHistory(data); // check if a continuation point exists. if (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0) { nodeToRead.ContinuationPoint = results[0].ContinuationPoint; NextBTN.Visible = true; StopBTN.Enabled = true; GoBTN.Visible = false; m_details = details; m_nodeToRead = nodeToRead; } // all done. else { NextBTN.Visible = false; StopBTN.Enabled = false; GoBTN.Visible = true; m_details = null; m_nodeToRead = null; } }
/// <summary> /// Fetches the recent history. /// </summary> private void ReadHistory(ReadEventDetails details, NodeId areaId) { HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection(); HistoryReadValueId nodeToRead = new HistoryReadValueId(); nodeToRead.NodeId = areaId; nodesToRead.Add(nodeToRead); HistoryReadResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, false, nodesToRead, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, nodesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); if (StatusCode.IsBad(results[0].StatusCode)) { throw new ServiceResultException(results[0].StatusCode); } HistoryEvent events = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryEvent; foreach (HistoryEventFieldList e in events.Events) { DisplayEvent(e.EventFields); } // release continuation points. if (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0) { nodeToRead.ContinuationPoint = results[0].ContinuationPoint; m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, true, nodesToRead, out results, out diagnosticInfos); } }
/// <summary> /// Fetches the recent history. /// </summary> private void ReadRecentHistory() { // check if session is active. if (m_session != null) { // check if area supports history. IObject area = m_session.NodeCache.Find(m_areaId) as IObject; if (area != null && ((area.EventNotifier & EventNotifiers.HistoryRead) != 0)) { // get the last hour or 10 events. ReadEventDetails details = new ReadEventDetails(); details.StartTime = DateTime.UtcNow.AddSeconds(30); details.EndTime = details.StartTime.AddHours(-1); details.NumValuesPerNode = 10; details.Filter = m_filter.GetFilter(); // read the history. ReadHistory(details, m_areaId); } } }
/// <summary> /// Returns the UTC timestamp of the first event in the archive. /// </summary> private DateTime ReadFirstDate() { // read the time of the first event in the archive. ReadEventDetails details = new ReadEventDetails(); details.StartTime = new DateTime(1970, 1, 1); details.EndTime = DateTime.MinValue; details.NumValuesPerNode = 1; details.Filter = new EventFilter(); details.Filter.AddSelectClause(Opc.Ua.ObjectTypeIds.BaseEventType, Opc.Ua.BrowseNames.Time); HistoryReadValueId nodeToRead = new HistoryReadValueId(); nodeToRead.NodeId = m_areaId; HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection(); nodesToRead.Add(nodeToRead); HistoryReadResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, false, nodesToRead, out results, out diagnosticInfos); Session.ValidateResponse(results, nodesToRead); Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); if (StatusCode.IsBad(results[0].StatusCode)) { throw new ServiceResultException(results[0].StatusCode); } // get the data. HistoryEvent data = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryEvent; // release the continuation point. if (results[0].ContinuationPoint != null) { nodeToRead.ContinuationPoint = results[0].ContinuationPoint; m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, true, nodesToRead, out results, out diagnosticInfos); Session.ValidateResponse(results, nodesToRead); Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); } // check if an event found. if (data == null || data.Events.Count == 0 || data.Events[0].EventFields.Count == 0) { throw new ServiceResultException(StatusCodes.BadNoDataAvailable); } // get the event time. DateTime? eventTime = data.Events[0].EventFields[0].Value as DateTime?; if (eventTime == null) { throw new ServiceResultException(StatusCodes.BadTypeMismatch); } // return time as UTC value. return eventTime.Value; }
/// <summary> /// Reads history events. /// </summary> protected virtual void HistoryReadEvents( ServerSystemContext context, ReadEventDetails details, TimestampsToReturn timestampsToReturn, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors, List<NodeHandle> nodesToProcess, IDictionary<NodeId, NodeState> cache) { for (int ii = 0; ii < nodesToProcess.Count; ii++) { NodeHandle handle = nodesToProcess[ii]; // validate node. NodeState source = ValidateNode(context, handle, cache); if (source == null) { continue; } errors[handle.Index] = StatusCodes.BadHistoryOperationUnsupported; } }
/// <summary> /// Creates a new history request. /// </summary> private HistoryReadRequest CreateHistoryReadRequest( ServerSystemContext context, ReadEventDetails details, NodeHandle handle, HistoryReadValueId nodeToRead) { FilterContext filterContext = new FilterContext(context.NamespaceUris, context.TypeTable, context.PreferredLocales); LinkedList <BaseEventState> events = new LinkedList <BaseEventState>(); for (ReportType ii = ReportType.FluidLevelTest; ii <= ReportType.InjectionTest; ii++) { DataView view = null; if (handle.Node is WellState) { view = m_generator.ReadHistoryForWellId( ii, (string)handle.Node.NodeId.Identifier, details.StartTime, details.EndTime); } else { view = m_generator.ReadHistoryForArea( ii, handle.Node.NodeId.Identifier as string, details.StartTime, details.EndTime); } LinkedListNode <BaseEventState> pos = events.First; bool sizeLimited = (details.StartTime == DateTime.MinValue || details.EndTime == DateTime.MinValue); foreach (DataRowView row in view) { // check if reached max results. if (sizeLimited) { if (events.Count >= details.NumValuesPerNode) { break; } } BaseEventState e = m_generator.GetReport(context, NamespaceIndex, ii, row.Row); if (details.Filter.WhereClause != null && details.Filter.WhereClause.Elements.Count > 0) { if (!details.Filter.WhereClause.Evaluate(filterContext, e)) { continue; } } bool inserted = false; for (LinkedListNode <BaseEventState> jj = pos; jj != null; jj = jj.Next) { if (jj.Value.Time.Value > e.Time.Value) { events.AddBefore(jj, e); pos = jj; inserted = true; break; } } if (!inserted) { events.AddLast(e); pos = null; } } } HistoryReadRequest request = new HistoryReadRequest(); request.Events = events; request.TimeFlowsBackward = details.StartTime == DateTime.MinValue || (details.EndTime != DateTime.MinValue && details.EndTime < details.StartTime); request.NumValuesPerNode = details.NumValuesPerNode; request.Filter = details.Filter; request.FilterContext = filterContext; return(request); }
/// <summary> /// Reads history events. /// </summary> protected override void HistoryReadEvents( ServerSystemContext context, ReadEventDetails details, TimestampsToReturn timestampsToReturn, IList <HistoryReadValueId> nodesToRead, IList <HistoryReadResult> results, IList <ServiceResult> errors, List <NodeHandle> nodesToProcess, IDictionary <NodeId, NodeState> cache) { for (int ii = 0; ii < nodesToProcess.Count; ii++) { NodeHandle handle = nodesToProcess[ii]; HistoryReadValueId nodeToRead = nodesToRead[handle.Index]; HistoryReadResult result = results[handle.Index]; HistoryReadRequest request = null; // load an exising request. if (nodeToRead.ContinuationPoint != null) { request = LoadContinuationPoint(context, nodeToRead.ContinuationPoint); if (request == null) { errors[handle.Index] = StatusCodes.BadContinuationPointInvalid; continue; } } // create a new request. else { request = CreateHistoryReadRequest( context, details, handle, nodeToRead); } // process events until the max is reached. HistoryEvent events = new HistoryEvent(); while (request.NumValuesPerNode == 0 || events.Events.Count < request.NumValuesPerNode) { if (request.Events.Count == 0) { break; } BaseEventState e = null; if (request.TimeFlowsBackward) { e = request.Events.Last.Value; request.Events.RemoveLast(); } else { e = request.Events.First.Value; request.Events.RemoveFirst(); } events.Events.Add(GetEventFields(request, e)); } errors[handle.Index] = ServiceResult.Good; // check if a continuation point is requred. if (request.Events.Count > 0) { // only set if both end time and start time are specified. if (details.StartTime != DateTime.MinValue && details.EndTime != DateTime.MinValue) { result.ContinuationPoint = SaveContinuationPoint(context, request); } } // check if no data returned. else { errors[handle.Index] = StatusCodes.GoodNoData; } // return the data. result.HistoryData = new ExtensionObject(events); } }
/// <summary> /// Creates a new history request. /// </summary> private HistoryReadRequest CreateHistoryReadRequest( ServerSystemContext context, ReadEventDetails details, NodeHandle handle, HistoryReadValueId nodeToRead) { FilterContext filterContext = new FilterContext(context.NamespaceUris, context.TypeTable, context.PreferredLocales); LinkedList<BaseEventState> events = new LinkedList<BaseEventState>(); for (ReportType ii = ReportType.FluidLevelTest; ii <= ReportType.InjectionTest; ii++) { DataView view = null; if (handle.Node is WellState) { view = m_generator.ReadHistoryForWellId( ii, (string)handle.Node.NodeId.Identifier, details.StartTime, details.EndTime); } else { view = m_generator.ReadHistoryForArea( ii, handle.Node.NodeId.Identifier as string, details.StartTime, details.EndTime); } LinkedListNode<BaseEventState> pos = events.First; bool sizeLimited = (details.StartTime == DateTime.MinValue || details.EndTime == DateTime.MinValue); foreach (DataRowView row in view) { // check if reached max results. if (sizeLimited) { if (events.Count >= details.NumValuesPerNode) { break; } } BaseEventState e = m_generator.GetReport(context, NamespaceIndex, ii, row.Row); if (details.Filter.WhereClause != null && details.Filter.WhereClause.Elements.Count > 0) { if (!details.Filter.WhereClause.Evaluate(filterContext, e)) { continue; } } bool inserted = false; for (LinkedListNode<BaseEventState> jj = pos; jj != null; jj = jj.Next) { if (jj.Value.Time.Value > e.Time.Value) { events.AddBefore(jj, e); pos = jj; inserted = true; break; } } if (!inserted) { events.AddLast(e); pos = null; } } } HistoryReadRequest request = new HistoryReadRequest(); request.Events = events; request.TimeFlowsBackward = details.StartTime == DateTime.MinValue || (details.EndTime != DateTime.MinValue && details.EndTime < details.StartTime); request.NumValuesPerNode = details.NumValuesPerNode; request.Filter = details.Filter; request.FilterContext = filterContext; return request; }
/// <summary> /// Fetches the recent history. /// </summary> private void ReadHistory(ReadEventDetails details, NodeId areaId) { HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection(); HistoryReadValueId nodeToRead = new HistoryReadValueId(); nodeToRead.NodeId = areaId; nodesToRead.Add(nodeToRead); HistoryReadResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, false, nodesToRead, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, nodesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); if (StatusCode.IsBad(results[0].StatusCode)) { throw new ServiceResultException(results[0].StatusCode); } HistoryEvent events = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryEvent; AddEventHistory(events); // release continuation points. if (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0) { nodeToRead.ContinuationPoint = results[0].ContinuationPoint; m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, true, nodesToRead, out results, out diagnosticInfos); } }
/// <summary> /// Returns the UTC timestamp of the first event in the archive. /// </summary> private DateTime ReadFirstDate() { // read the time of the first event in the archive. ReadEventDetails details = new ReadEventDetails(); details.StartTime = new DateTime(1970, 1, 1); details.EndTime = DateTime.MinValue; details.NumValuesPerNode = 1; details.Filter = new EventFilter(); details.Filter.AddSelectClause(Opc.Ua.ObjectTypeIds.BaseEventType, Opc.Ua.BrowseNames.Time); HistoryReadValueId nodeToRead = new HistoryReadValueId(); nodeToRead.NodeId = m_areaId; HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection(); nodesToRead.Add(nodeToRead); HistoryReadResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, false, nodesToRead, out results, out diagnosticInfos); Session.ValidateResponse(results, nodesToRead); Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); if (StatusCode.IsBad(results[0].StatusCode)) { throw new ServiceResultException(results[0].StatusCode); } // get the data. HistoryEvent data = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryEvent; // release the continuation point. if (results[0].ContinuationPoint != null) { nodeToRead.ContinuationPoint = results[0].ContinuationPoint; m_session.HistoryRead( null, new ExtensionObject(details), TimestampsToReturn.Neither, true, nodesToRead, out results, out diagnosticInfos); Session.ValidateResponse(results, nodesToRead); Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); } // check if an event found. if (data == null || data.Events.Count == 0 || data.Events[0].EventFields.Count == 0) { throw new ServiceResultException(StatusCodes.BadNoDataAvailable); } // get the event time. DateTime?eventTime = data.Events[0].EventFields[0].Value as DateTime?; if (eventTime == null) { throw new ServiceResultException(StatusCodes.BadTypeMismatch); } // return time as UTC value. return(eventTime.Value); }
/// <summary> /// Encode historic events /// </summary> /// <param name="ct"></param> /// <returns></returns> private async Task EncodeHistoricEventsAsync(CancellationToken ct) { EventFilter filter = null; try { filter = await ReadEventFilterAsync(ct); } catch (Exception ex) { _logger.Error(ex, "Failed to retrieve event filter for {nodeId}", _nodeId); } if (filter == null) { // Nothing to do without event filter // TODO: use generates events? What other way to get event field structure? return; } var details = new ReadEventDetails { NumValuesPerNode = (uint)_maxValues, // Read from today backward EndTime = _startTime, StartTime = _endTime, Filter = filter }; // // Read first and retry with lower number of nodes to fix issues with // misbehaving servers such as reference stack server. // byte[] continuationToken = null; while (true) { ct.ThrowIfCancellationRequested(); try { var result = await ReadHistoryAsync <HistoryEvent>(details, ct); if (result.history?.Events != null) { _logger.Verbose(" {count} events...", result.history.Events.Count); foreach (var data in result.history.Events) { _encoder.WriteEncodeable(null, data, data.GetType()); _count++; } } continuationToken = result.continuationToken; break; } catch (FormatException) { if (details.NumValuesPerNode == 0) { details.NumValuesPerNode = ushort.MaxValue; } else { details.NumValuesPerNode /= 2; } } } // Continue reading while (continuationToken != null && _count < _maxValues) { // Continue reading history ct.ThrowIfCancellationRequested(); var result = await ReadHistoryAsync <HistoryEvent>(details, ct, continuationToken); if (result.history?.Events != null) { _logger.Verbose("+ {count} events...", result.history.Events.Count); foreach (var data in result.history.Events) { _encoder.WriteEncodeable(null, data, data.GetType()); _count++; } } continuationToken = result.continuationToken; } }
/// <summary> /// Reads history events. /// </summary> protected override void HistoryReadEvents( ServerSystemContext context, ReadEventDetails details, TimestampsToReturn timestampsToReturn, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors, List<NodeHandle> nodesToProcess, IDictionary<NodeId, NodeState> cache) { for (int ii = 0; ii < nodesToProcess.Count; ii++) { NodeHandle handle = nodesToProcess[ii]; HistoryReadValueId nodeToRead = nodesToRead[handle.Index]; HistoryReadResult result = results[handle.Index]; HistoryReadRequest request = null; // load an exising request. if (nodeToRead.ContinuationPoint != null) { request = LoadContinuationPoint(context, nodeToRead.ContinuationPoint); if (request == null) { errors[handle.Index] = StatusCodes.BadContinuationPointInvalid; continue; } } // create a new request. else { request = CreateHistoryReadRequest( context, details, handle, nodeToRead); } // process events until the max is reached. HistoryEvent events = new HistoryEvent(); while (request.NumValuesPerNode == 0 || events.Events.Count < request.NumValuesPerNode) { if (request.Events.Count == 0) { break; } BaseEventState e = null; if (request.TimeFlowsBackward) { e = request.Events.Last.Value; request.Events.RemoveLast(); } else { e = request.Events.First.Value; request.Events.RemoveFirst(); } events.Events.Add(GetEventFields(request, e)); } errors[handle.Index] = ServiceResult.Good; // check if a continuation point is requred. if (request.Events.Count > 0) { // only set if both end time and start time are specified. if (details.StartTime != DateTime.MinValue && details.EndTime != DateTime.MinValue) { result.ContinuationPoint = SaveContinuationPoint(context, request); } } // check if no data returned. else { errors[handle.Index] = StatusCodes.GoodNoData; } // return the data. result.HistoryData = new ExtensionObject(events); } }