OPC UA Historical Reads: Separate Page Completion from a Complete Time Range

A completed HistoryRead page proves only that one response was processed. Finishing a requested time range requires exhausting each node’s continuation sequence, preserving operation and value statuses, and interpreting bounds according to the original request. Even then, the result is the historian’s stored data, which may be compressed or subject to retention; it is not proof that every physical transition was recorded.

This guide pins OPC UA Part 4, version 1.05.07, section 5.11.3, and Part 11, Historical Access, version 1.05.04, sections 4.6, 6.3 and 6.5.3. The main scope is raw data history. Modified history is discussed only where it changes duplicate handling. An original forward-window model was executed without a real historian.

Freeze the requested time domain

ReadRawModifiedDetails requires at least two of startTime, endTime and numValuesPerNode. A zero count means no maximum, while an unspecified time uses the defined DateTime sentinel. Do not confuse these different defaults.

Save the node identity, history details, timestamp selection, range and local query generation before sending. With a continuation point, HistoryReadDetails and TimestampsToReturn must remain the same as in the original call. Changing them can cause server-specific behavior, including an error, ignored changes or a new operation.

For this Part 4 release, dataEncoding is no longer used and clients set it empty. The older Part 11 text discusses changing it; use the pinned service parameter contract rather than treating that historical allowance as a new feature.

Synthetic raw samples at2,5,8,12,16 seconds are queried from4 through14 seconds. Without bounds the core contains5,8,12. With bounds it also contains2 and16. A two-value page limit produces pages2/5,8/12,16, so a short final page and exhausted continuation describe completion separately from the requested time-domain coverage.
Bounding values consume page capacity and may lie outside the requested core interval. Preserve that distinction in a trend or export.

Decide direction and bounds before paging

For a forward raw interval with different start and end times, Part 11’s examples include the start and exclude the end when bounds are not requested. Reversing start and end returns reverse-ordered data. Equal times have a defined single-time behavior and must not be handled by an unconditional “empty interval” shortcut.

returnBounds requests surrounding values useful for interpolation. Those values can lie outside the requested interval and count against a nonzero numValuesPerNode. A page containing two boundary-related values is not necessarily two observations inside the requested time window.

When a requested bound cannot be found, the corresponding DataValue has Bad_BoundNotFound, a null value and the relevant boundary timestamp. The search distance is server-dependent. Do not turn that null into a measured zero or silently interpolate through an unestablished endpoint.

An original forward-window example

The hypothetical historian stores values at seconds two, five, eight, twelve and sixteen. A raw query from four to fourteen with bounds disabled selects five, eight and twelve. Enabling bounds adds the preceding sample at two and the following sample at sixteen.

Page limit two, bounds enabled Returned sample times Interpretation
First response 2, 5 Start-bound context plus first interior point
Second response 8, 12 More interior points
Third response 16 End-bound context; no continuation remains

The executed model asserted the full sequence and page sizes two, two and one. It also checked adjacent bound-free core windows, cancellation and immutable request settings. These are synthetic control-flow and selection tests, not measurements of a server’s archive or compression behavior.

Continue with HistoryRead, not BrowseNext

Each HistoryReadResult belongs to its ordered nodesToRead entry and carries its own status, continuation point and history data. Continue by putting the latest opaque point into that node’s next HistoryRead request.

A server can return zero values with a continuation point while approaching the client’s timeout hint. Keep working under a bounded local deadline instead of interpreting that page as Good_NoData. Conversely, an exhausted point does not erase a bad operation result.

If the task stops early, release the latest points through HistoryRead with releaseContinuationPoints true. Part 11 specifies no returned data for release and Bad_ContinuationPointInvalid for a missing or invalid supplied point. Do not reuse BrowseNext’s response-array assumptions for this service.

Record a completion state per node

  1. Inspect the service result, then the HistoryReadResult for every requested node.
  2. Validate the returned history-data representation and retain each value’s status and timestamps.
  3. Consume pages within item, byte and time budgets while any continuation remains.
  4. Mark cancellation, invalid continuation and unsupported history separately from normal exhaustion.
  5. After exhaustion, classify the requested domain as returned data, no stored data, missing bounds or failed/incomplete retrieval.
  6. Attach the requested interval and historian configuration evidence to the export.

For an interval with no data and no requested bounds, raw history returns Good_NoData. A requested interval outside the archive’s range is treated as no data, not automatically Bad_InvalidArgument. Good_NoData still does not establish why the historian lacks observations.

Avoid timestamp-only restart shortcuts

A continuation identifies a position in the server’s ordered result sequence. Replacing it with a new query starting at the last timestamp changes the operation and can repeat boundary values or omit records if the client guesses an increment.

Independent adjacent queries with bounds can legitimately share contextual values. Preserve their role or apply a documented export-merging policy; do not report every repeated timestamp as a server duplication defect.

Modified history is more demanding: multiple modification records can have the same source timestamp and can span pages. Deduplicating only by that timestamp loses legitimate records. The local counterexample retained two modifications at one timestamp and showed that a timestamp-keyed dictionary collapsed them.

Raw history returns the most recent value at a timestamp and can mark ExtraData when additional information or hidden modified values exist. Do not reinterpret that bit as a count or assume raw retrieval includes the full modification audit.

Qualify coverage claims

Test forward, reverse and equal-time requests on the chosen server, with bounds present and missing, small page limits, empty intermediate responses and expired continuations. Verify per-node results when one node succeeds and another does not support history.

The model did not implement reverse/equal-time services, missing-bound wire statuses or changing archives. Final acceptance must state the stored-data interval retrieved and any remaining gaps or retention limitations. “All pages received” is useful evidence, but it is only one part of an honest history-coverage claim.

Similar Posts