/// <summary> /// Releases the history continuation point. /// </summary> protected override void HistoryReleaseContinuationPoints( ServerSystemContext context, IList <HistoryReadValueId> nodesToRead, 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]; // find the continuation point. HistoryReadRequest request = LoadContinuationPoint(context, nodeToRead.ContinuationPoint); if (request == null) { errors[handle.Index] = StatusCodes.BadContinuationPointInvalid; continue; } // all done. errors[handle.Index] = StatusCodes.Good; } }
public static LogEntry For(HistoryReadRequest request) { LogEntry entry = new LogEntry("HistoryReadRequest"); entry.Add("RequestHeader", For(request.RequestHeader)); entry.Add("HistoryReadDetails", For(request.HistoryReadDetails)); entry.Add("TimestampsToReturn", For(request.TimestampsToReturn)); entry.Add("ReleaseContinuationPoints", For(request.ReleaseContinuationPoints)); entry.Add("NodesToRead", For(request.NodesToRead)); return(entry); }
public async Task HistoryReadAsync() { var response = new HistoryReadResponse(); var request = new HistoryReadRequest(); var channel = new TestRequestChannel(response); var ret = await channel.HistoryReadAsync(request); ret .Should().BeSameAs(response); channel.Request .Should().BeSameAs(request); }
/// <summary> /// Saves a history continuation point. /// </summary> private byte[] SaveContinuationPoint( ServerSystemContext context, HistoryReadRequest request) { Session session = context.OperationContext.Session; if (session == null) { return(null); } Guid id = Guid.NewGuid(); session.SaveHistoryContinuationPoint(id, request); request.ContinuationPoint = id.ToByteArray(); return(request.ContinuationPoint); }
/// <summary> /// Loads a history continuation point. /// </summary> private HistoryReadRequest LoadContinuationPoint( ServerSystemContext context, byte[] continuationPoint) { Session session = context.OperationContext.Session; if (session == null) { return(null); } HistoryReadRequest request = session.RestoreHistoryContinuationPoint(continuationPoint) as HistoryReadRequest; if (request == null) { return(null); } return(request); }
/// <summary> /// Fetches the requested event fields from the event. /// </summary> private HistoryEventFieldList GetEventFields(HistoryReadRequest request, IFilterTarget instance) { // fetch the event fields. HistoryEventFieldList fields = new HistoryEventFieldList(); foreach (SimpleAttributeOperand clause in request.Filter.SelectClauses) { // get the value of the attribute (apply localization). object value = instance.GetAttributeValue( request.FilterContext, clause.TypeDefinitionId, clause.BrowsePath, clause.AttributeId, clause.ParsedIndexRange); // add the value to the list of event fields. if (value != null) { // translate any localized text. LocalizedText text = value as LocalizedText; if (text != null) { value = Server.ResourceManager.Translate(request.FilterContext.PreferredLocales, text); } // add value. fields.EventFields.Add(new Variant(value)); } // add a dummy entry for missing values. else { fields.EventFields.Add(Variant.Null); } } return(fields); }
/// <summary> /// Reads historical values or Events of one or more Nodes. /// </summary> /// <param name="client">A instance of <see cref="IRequestChannel"/>.</param> /// <param name="request">A <see cref="HistoryReadRequest"/>.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation that returns a <see cref="HistoryReadResponse"/>.</returns> public static async Task <HistoryReadResponse> HistoryReadAsync(this IRequestChannel client, HistoryReadRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } return((HistoryReadResponse)await client.RequestAsync(request).ConfigureAwait(false)); }
public async Task ReadHistorical() { var channel = new UaTcpSessionChannel( this.localDescription, this.certificateStore, null, EndpointUrl); await channel.OpenAsync(); Console.WriteLine($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); Console.WriteLine($"Activated session '{channel.SessionId}'."); var historyReadRequest = new HistoryReadRequest { HistoryReadDetails = new ReadRawModifiedDetails { StartTime = DateTime.UtcNow - TimeSpan.FromMinutes(10), EndTime = DateTime.UtcNow, ReturnBounds = true, IsReadModified = false }, NodesToRead = new[] { new HistoryReadValueId { NodeId = NodeId.Parse("ns=2;s=MyLevel") } }, }; var historyReadResponse = await channel.HistoryReadAsync(historyReadRequest); var result = historyReadResponse.Results[0]; Assert.IsTrue(StatusCode.IsGood(result.StatusCode)); Console.WriteLine($"HistoryRead response status code: {result.StatusCode}, HistoryData count: {((HistoryData)result.HistoryData.Body).DataValues.Length}."); var historyReadRequest2 = new HistoryReadRequest { HistoryReadDetails = new ReadEventDetails { StartTime = DateTime.UtcNow - TimeSpan.FromMinutes(10), EndTime = DateTime.UtcNow, Filter = new EventFilter // Use EventHelper to select all the fields of AlarmCondition. { SelectClauses = EventHelper.GetSelectClauses <AlarmCondition>() } }, NodesToRead = new[] { new HistoryReadValueId { NodeId = NodeId.Parse("ns=2;s=MyDevice") } }, }; var historyReadResponse2 = await channel.HistoryReadAsync(historyReadRequest2); var result2 = historyReadResponse2.Results[0]; Assert.IsTrue(StatusCode.IsGood(result2.StatusCode)); Console.WriteLine($"HistoryRead response status code: {result2.StatusCode}, HistoryEvent count: {((HistoryEvent)result2.HistoryData.Body).Events.Length}."); // Use EventHelper to create AlarmConditions from the HistoryEventFieldList var alarms = ((HistoryEvent)result2.HistoryData.Body).Events.Select(e => EventHelper.Deserialize <AlarmCondition>(e.EventFields)); Console.WriteLine($"Closing session '{channel.SessionId}'."); await channel.CloseAsync(); }
/// <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> /// Initializes the message with the body. /// </summary> public HistoryReadMessage(HistoryReadRequest HistoryReadRequest) { this.HistoryReadRequest = HistoryReadRequest; }
/// <summary> /// Saves a history continuation point. /// </summary> private byte[] SaveContinuationPoint( ServerSystemContext context, HistoryReadRequest request) { Session session = context.OperationContext.Session; if (session == null) { return null; } Guid id = Guid.NewGuid(); session.SaveHistoryContinuationPoint(id, request); request.ContinuationPoint = id.ToByteArray(); return request.ContinuationPoint; }
/// <summary> /// Creates a new history request. /// </summary> private HistoryReadRequest CreateHistoryReadRequest( ServerSystemContext context, ReadRawModifiedDetails details, NodeHandle handle, HistoryReadValueId nodeToRead) { bool sizeLimited = (details.StartTime == DateTime.MinValue || details.EndTime == DateTime.MinValue); bool applyIndexRangeOrEncoding = (nodeToRead.ParsedIndexRange != NumericRange.Empty || !QualifiedName.IsNull(nodeToRead.DataEncoding)); bool returnBounds = !details.IsReadModified && details.ReturnBounds; bool timeFlowsBackward = (details.StartTime == DateTime.MinValue) || (details.EndTime != DateTime.MinValue && details.EndTime < details.StartTime); // find the archive item. ArchiveItemState item = Reload(context, handle); if (item == null) { throw new ServiceResultException(StatusCodes.BadNotSupported); } LinkedList<DataValue> values = new LinkedList<DataValue>(); LinkedList<ModificationInfo> modificationInfos = null; if (details.IsReadModified) { modificationInfos = new LinkedList<ModificationInfo>(); } // read history. DataView view = item.ReadHistory(details.StartTime, details.EndTime, details.IsReadModified, handle.Node.BrowseName); int startBound = -1; int endBound = -1; int ii = (timeFlowsBackward)?view.Count-1:0; while (ii >= 0 && ii < view.Count) { try { DateTime timestamp = (DateTime)view[ii].Row[0]; // check if looking for start of data. if (values.Count == 0) { if (timeFlowsBackward) { if ((details.StartTime != DateTime.MinValue && timestamp >= details.StartTime) || (details.StartTime == DateTime.MinValue && timestamp >= details.EndTime)) { startBound = ii; if (timestamp > details.StartTime) { continue; } } } else { if (timestamp <= details.StartTime) { startBound = ii; if (timestamp < details.StartTime) { continue; } } } } // check if absolute max values specified. if (sizeLimited) { if (details.NumValuesPerNode > 0 && details.NumValuesPerNode < values.Count) { break; } } // check for end bound. if (details.EndTime != DateTime.MinValue && timestamp >= details.EndTime) { if (timeFlowsBackward) { if (timestamp <= details.EndTime) { endBound = ii; break; } } else { if (timestamp >= details.EndTime) { endBound = ii; break; } } } // check if the start bound needs to be returned. if (returnBounds && values.Count == 0 && startBound != ii && details.StartTime != DateTime.MinValue) { // add start bound. if (startBound == -1) { values.AddLast(new DataValue(Variant.Null, StatusCodes.BadBoundNotFound, details.StartTime, details.StartTime)); } else { values.AddLast(RowToDataValue(context, nodeToRead, view[startBound], applyIndexRangeOrEncoding)); } // check if absolute max values specified. if (sizeLimited) { if (details.NumValuesPerNode > 0 && details.NumValuesPerNode < values.Count) { break; } } } // add value. values.AddLast(RowToDataValue(context, nodeToRead, view[ii], applyIndexRangeOrEncoding)); if (modificationInfos != null) { modificationInfos.AddLast((ModificationInfo)view[ii].Row[6]); } } finally { if (timeFlowsBackward) { ii--; } else { ii++; } } } // add late bound. while (returnBounds && details.EndTime != DateTime.MinValue) { // add start bound. if (values.Count == 0) { if (startBound == -1) { values.AddLast(new DataValue(Variant.Null, StatusCodes.BadBoundNotFound, details.StartTime, details.StartTime)); } else { values.AddLast(RowToDataValue(context, nodeToRead, view[startBound], applyIndexRangeOrEncoding)); } } // check if absolute max values specified. if (sizeLimited) { if (details.NumValuesPerNode > 0 && details.NumValuesPerNode < values.Count) { break; } } // add end bound. if (endBound == -1) { values.AddLast(new DataValue(Variant.Null, StatusCodes.BadBoundNotFound, details.EndTime, details.EndTime)); } else { values.AddLast(RowToDataValue(context, nodeToRead, view[endBound], applyIndexRangeOrEncoding)); } break; } HistoryReadRequest request = new HistoryReadRequest(); request.Values = values; request.ModificationInfos = modificationInfos; request.NumValuesPerNode = details.NumValuesPerNode; request.Filter = null; return request; }
/// <summary> /// Creates a new history request. /// </summary> private HistoryReadRequest CreateHistoryReadRequest( ServerSystemContext context, ReadProcessedDetails details, NodeHandle handle, HistoryReadValueId nodeToRead, NodeId aggregateId) { bool applyIndexRangeOrEncoding = (nodeToRead.ParsedIndexRange != NumericRange.Empty || !QualifiedName.IsNull(nodeToRead.DataEncoding)); bool timeFlowsBackward = (details.EndTime < details.StartTime); ArchiveItemState item = handle.Node as ArchiveItemState; if (item == null) { throw new ServiceResultException(StatusCodes.BadNotSupported); } item.ReloadFromSource(context); LinkedList<DataValue> values = new LinkedList<DataValue>(); // read history. DataView view = item.ReadHistory(details.StartTime, details.EndTime, false); int ii = (timeFlowsBackward) ? view.Count - 1 : 0; // choose the aggregate configuration. AggregateConfiguration configuration = (AggregateConfiguration)details.AggregateConfiguration.Clone(); ReviseAggregateConfiguration(context, item, configuration); // create the aggregate calculator. IAggregateCalculator calculator = Server.AggregateManager.CreateCalculator( aggregateId, details.StartTime, details.EndTime, details.ProcessingInterval, item.ArchiveItem.Stepped, configuration); while (ii >= 0 && ii < view.Count) { try { DataValue value = (DataValue)view[ii].Row[2]; calculator.QueueRawValue(value); // queue any processed values. QueueProcessedValues( context, calculator, nodeToRead.ParsedIndexRange, nodeToRead.DataEncoding, applyIndexRangeOrEncoding, false, values); } finally { if (timeFlowsBackward) { ii--; } else { ii++; } } } // queue any processed values beyond the end of the data. QueueProcessedValues( context, calculator, nodeToRead.ParsedIndexRange, nodeToRead.DataEncoding, applyIndexRangeOrEncoding, true, values); HistoryReadRequest request = new HistoryReadRequest(); request.Values = values; request.NumValuesPerNode = 0; request.Filter = null; return request; }
/// <summary> /// Begins an asynchronous invocation of the HistoryRead service. /// </summary> public IAsyncResult BeginHistoryRead( RequestHeader requestHeader, ExtensionObject historyReadDetails, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, HistoryReadValueIdCollection nodesToRead, AsyncCallback callback, object asyncState) { HistoryReadRequest request = new HistoryReadRequest(); request.RequestHeader = requestHeader; request.HistoryReadDetails = historyReadDetails; request.TimestampsToReturn = timestampsToReturn; request.ReleaseContinuationPoints = releaseContinuationPoints; request.NodesToRead = nodesToRead; UpdateRequestHeader(request, requestHeader == null, "HistoryRead"); if (UseTransportChannel) { return TransportChannel.BeginSendRequest(request, callback, asyncState); } return InnerChannel.BeginHistoryRead(new HistoryReadMessage(request), callback, asyncState); }
/// <summary> /// Invokes the HistoryRead service. /// </summary> public virtual ResponseHeader HistoryRead( RequestHeader requestHeader, ExtensionObject historyReadDetails, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, HistoryReadValueIdCollection nodesToRead, out HistoryReadResultCollection results, out DiagnosticInfoCollection diagnosticInfos) { HistoryReadRequest request = new HistoryReadRequest(); HistoryReadResponse response = null; request.RequestHeader = requestHeader; request.HistoryReadDetails = historyReadDetails; request.TimestampsToReturn = timestampsToReturn; request.ReleaseContinuationPoints = releaseContinuationPoints; request.NodesToRead = nodesToRead; UpdateRequestHeader(request, requestHeader == null, "HistoryRead"); try { if (UseTransportChannel) { IServiceResponse genericResponse = TransportChannel.SendRequest(request); if (genericResponse == null) { throw new ServiceResultException(StatusCodes.BadUnknownResponse); } ValidateResponse(genericResponse.ResponseHeader); response = (HistoryReadResponse)genericResponse; } else { HistoryReadResponseMessage responseMessage = InnerChannel.HistoryRead(new HistoryReadMessage(request)); if (responseMessage == null || responseMessage.HistoryReadResponse == null) { throw new ServiceResultException(StatusCodes.BadUnknownResponse); } response = responseMessage.HistoryReadResponse; ValidateResponse(response.ResponseHeader); } results = response.Results; diagnosticInfos = response.DiagnosticInfos; } finally { RequestCompleted(request, response, "HistoryRead"); } return response.ResponseHeader; }
/// <summary> /// Creates a new history request. /// </summary> private HistoryReadRequest CreateHistoryReadRequest( ServerSystemContext context, ReadAtTimeDetails details, NodeHandle handle, HistoryReadValueId nodeToRead) { bool applyIndexRangeOrEncoding = (nodeToRead.ParsedIndexRange != NumericRange.Empty || !QualifiedName.IsNull(nodeToRead.DataEncoding)); ArchiveItemState item = handle.Node as ArchiveItemState; if (item == null) { throw new ServiceResultException(StatusCodes.BadNotSupported); } item.ReloadFromSource(context); // find the start and end times. DateTime startTime = DateTime.MaxValue; DateTime endTime = DateTime.MinValue; for (int ii = 0; ii < details.ReqTimes.Count; ii++) { if (startTime > details.ReqTimes[ii]) { startTime = details.ReqTimes[ii]; } if (endTime < details.ReqTimes[ii]) { endTime = details.ReqTimes[ii]; } } DataView view = item.ReadHistory(startTime, endTime, false); LinkedList<DataValue> values = new LinkedList<DataValue>(); for (int ii = 0; ii < details.ReqTimes.Count; ii++) { bool dataBeforeIgnored = false; bool dataAfterIgnored = false; // find the value at the time. int index = item.FindValueAtOrBefore(view, details.ReqTimes[ii], !details.UseSimpleBounds, out dataBeforeIgnored); if (index < 0) { values.AddLast(new DataValue(StatusCodes.BadNoData, details.ReqTimes[ii])); continue; } // nothing more to do if a raw value exists. if ((DateTime)view[index].Row[0] == details.ReqTimes[ii]) { values.AddLast((DataValue)view[index].Row[2]); continue; } DataValue before = (DataValue)view[index].Row[2]; DataValue value; // find the value after the time. int afterIndex = item.FindValueAfter(view, index, !details.UseSimpleBounds, out dataAfterIgnored); if (afterIndex < 0) { // use stepped interpolation if no end bound exists. value = AggregateCalculator.SteppedInterpolate(details.ReqTimes[ii], before); if (StatusCode.IsNotBad(value.StatusCode) && dataBeforeIgnored) { value.StatusCode = value.StatusCode.SetCodeBits(StatusCodes.UncertainDataSubNormal); } values.AddLast(value); continue; } // use stepped or slopped interpolation depending on the value. if (item.ArchiveItem.Stepped) { value = AggregateCalculator.SteppedInterpolate(details.ReqTimes[ii], before); if (StatusCode.IsNotBad(value.StatusCode) && dataBeforeIgnored) { value.StatusCode = value.StatusCode.SetCodeBits(StatusCodes.UncertainDataSubNormal); } } else { value = AggregateCalculator.SlopedInterpolate(details.ReqTimes[ii], before, (DataValue)view[afterIndex].Row[2]); if (StatusCode.IsNotBad(value.StatusCode) && (dataBeforeIgnored || dataAfterIgnored)) { value.StatusCode = value.StatusCode.SetCodeBits(StatusCodes.UncertainDataSubNormal); } } values.AddLast(value); } HistoryReadRequest request = new HistoryReadRequest(); request.Values = values; request.NumValuesPerNode = 0; request.Filter = null; return request; }
public async Task ReadHistoryRawValues() { // describe this client application. var clientDescription = new ApplicationDescription { ApplicationName = "Workstation.UaClient.FeatureTests", ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:Workstation.UaClient.FeatureTests", ApplicationType = ApplicationType.Client }; // place to store certificates var certificateStore = new DirectoryStore("./pki"); // create a 'UaTcpSessionChannel', a client-side channel that opens a 'session' with the server. var channel = new UaTcpSessionChannel( clientDescription, certificateStore, new AnonymousIdentity(), // the anonymous identity "opc.tcp://localhost:48010"); // the endpoint of Unified Automation's UaCPPServer. try { // try opening a session and reading a few nodes. await channel.OpenAsync(); Console.WriteLine($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); Console.WriteLine($"UserIdentityToken: '{channel.UserIdentity}'."); Console.WriteLine("\nCheck if DataLogger active."); // check if DataLoggerActive is true. If not, then call method StartLogging. var req = new ReadRequest { NodesToRead = new[] { new ReadValueId { NodeId = NodeId.Parse("ns=2;s=Demo.History.DataLoggerActive"), AttributeId = AttributeIds.Value } }, }; var res = await channel.ReadAsync(req); if (StatusCode.IsBad(res.Results[0].StatusCode)) { throw new InvalidOperationException("Error reading 'Demo.History.DataLoggerActive'. "); } var isActive = res.Results[0].GetValueOrDefault <bool>(); if (!isActive) { Console.WriteLine("Activating DataLogger."); var req1 = new CallRequest { MethodsToCall = new[] { new CallMethodRequest { ObjectId = NodeId.Parse("ns=2;s=Demo.History"), // parent node MethodId = NodeId.Parse("ns=2;s=Demo.History.StartLogging") }, }, }; var res1 = await channel.CallAsync(req1); if (StatusCode.IsBad(res1.Results[0].StatusCode)) { throw new InvalidOperationException("Error calling method 'Demo.History.StartLogging'."); } Console.WriteLine("Note: Datalogger has just been activated, so there will be little or no history data to read."); Console.WriteLine(" Try again in 1 minute."); } Console.WriteLine("\nReading history for last 1 minute(s)."); // A continuation point is returned if there are more values to return than the // limit set by parameter NumValuesPerNode. A client should continue calling HistoryRead // until the continuation point returns null. byte[] cp = null; do { var req2 = new HistoryReadRequest { HistoryReadDetails = new ReadRawModifiedDetails { StartTime = DateTime.UtcNow.Add(TimeSpan.FromSeconds(-60)), // set start time to 1 minute ago EndTime = DateTime.UtcNow, NumValuesPerNode = 100, // sets limit. if there are more values to return then a continuation point is returned. ReturnBounds = false, // set true to return interpolated values for the start and end times }, TimestampsToReturn = TimestampsToReturn.Both, ReleaseContinuationPoints = false, // set true to abandon returning any remaining values from this interval NodesToRead = new[] { new HistoryReadValueId { NodeId = NodeId.Parse("ns=2;s=Demo.History.DoubleWithHistory"), ContinuationPoint = cp }, }, }; var res2 = await channel.HistoryReadAsync(req2); if (StatusCode.IsGood(res2.Results[0].StatusCode)) { var historyData = res2.Results[0].HistoryData as HistoryData; Console.WriteLine($"Found {historyData.DataValues.Length} value(s) for node '{req2.NodesToRead[0].NodeId}':"); foreach (var dv in historyData.DataValues) { Console.WriteLine($"Read {dv.Value}, q: {dv.StatusCode}, ts: {dv.SourceTimestamp}"); } cp = res2.Results[0].ContinuationPoint; // if ContinuationPoint is null, then there is no more data to return. if (cp == null) { break; } } else { Console.WriteLine($"HistoryRead return statuscode: {res2.Results[0].StatusCode}"); break; } } while (cp != null); // loop while ContinuationPoint is not null. Console.WriteLine($"\nClosing session '{channel.SessionId}'."); await channel.CloseAsync(); } catch (Exception ex) { await channel.AbortAsync(); Console.WriteLine(ex.Message); } }
/// <summary> /// Fetches the requested event fields from the event. /// </summary> private HistoryEventFieldList GetEventFields(HistoryReadRequest request, IFilterTarget instance) { // fetch the event fields. HistoryEventFieldList fields = new HistoryEventFieldList(); foreach (SimpleAttributeOperand clause in request.Filter.SelectClauses) { // get the value of the attribute (apply localization). object value = instance.GetAttributeValue( request.FilterContext, clause.TypeDefinitionId, clause.BrowsePath, clause.AttributeId, clause.ParsedIndexRange); // add the value to the list of event fields. if (value != null) { // translate any localized text. LocalizedText text = value as LocalizedText; if (text != null) { value = Server.ResourceManager.Translate(request.FilterContext.PreferredLocales, text); } // add value. fields.EventFields.Add(new Variant(value)); } // add a dummy entry for missing values. else { fields.EventFields.Add(Variant.Null); } } return fields; }
public async Task ReadHistorical() { var channel = new UaTcpSessionChannel( localDescription, certificateStore, new AnonymousIdentity(), "opc.tcp://localhost:48010", loggerFactory: loggerFactory); await channel.OpenAsync(); logger.LogInformation($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); logger.LogInformation($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); logger.LogInformation($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); logger.LogInformation($"Activated session '{channel.SessionId}'."); var historyReadRequest = new HistoryReadRequest { HistoryReadDetails = new ReadRawModifiedDetails { StartTime = DateTime.UtcNow - TimeSpan.FromMinutes(10), EndTime = DateTime.UtcNow, ReturnBounds = true, IsReadModified = false }, NodesToRead = new[] { new HistoryReadValueId { NodeId = NodeId.Parse("ns=2;s=Demo.History.DoubleWithHistory") } }, }; var historyReadResponse = await channel.HistoryReadAsync(historyReadRequest); var result = historyReadResponse.Results[0]; StatusCode.IsGood(result.StatusCode) .Should().BeTrue(); logger.LogInformation($"HistoryRead response status code: {result.StatusCode}, HistoryData count: {((HistoryData)result.HistoryData).DataValues.Length}."); if (false) // UaCPPserver does not appear to store event history. { var historyReadRequest2 = new HistoryReadRequest { HistoryReadDetails = new ReadEventDetails { StartTime = DateTime.UtcNow - TimeSpan.FromMinutes(10), EndTime = DateTime.UtcNow, Filter = new EventFilter // Use EventHelper to select all the fields of AlarmCondition. { SelectClauses = EventHelper.GetSelectClauses <AlarmCondition>() } }, NodesToRead = new[] { new HistoryReadValueId { NodeId = NodeId.Parse("ns=2;s=Demo.History.DoubleWithHistory") } }, }; var historyReadResponse2 = await channel.HistoryReadAsync(historyReadRequest2); var result2 = historyReadResponse2.Results[0]; StatusCode.IsGood(result2.StatusCode) .Should().BeTrue(); logger.LogInformation($"HistoryRead response status code: {result2.StatusCode}, HistoryEvent count: {((HistoryEvent)result2.HistoryData).Events.Length}."); // Use EventHelper to create AlarmConditions from the HistoryEventFieldList var alarms = ((HistoryEvent)result2.HistoryData).Events.Select(e => EventHelper.Deserialize <AlarmCondition>(e.EventFields)); } logger.LogInformation($"Closing session '{channel.SessionId}'."); await channel.CloseAsync(); }
/// <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; }