.NET Based OPC UA Client/Server SDK
History Read – History Read Events


A session with the server must be established.


The following dialog shows an example implementation of the History Read service for reading historical events. Press the button “Show Code” to display the corresponding code, and the button “Help” to show this documentation page.


All fields are already filled with reasonable values.

Press the button “...” right of the field “Notifier” to open a window to browse the address space and select a historizing notifier.


After pressing the button “OK” the NodeId will be shown in the corresponding field.


You can specify a time range by checking the boxes right of the input fields “Start Time” and “End Time” and entering the desired values. Clicking on the arrow in the input field opens a calendar for picking the date. The time can be entered directly.

In addtion you can specify the maximum number of values to be returned in the field “Num Values”.

When pressing the button “Event Filter...” a dialog window for adding/removing fields to return and to edit filter critera is opened. A description can be found at Modify Event Monitored Items.

On pressing the button “Read History” the response is listed at “History Read Response”. Check the box in front of “Use Asynchronous Pattern” to call “BeginHistoryRead” instead of “HistoryRead”.


Sample Code

The implementation is very similar to reading historical data for a variable (see History Read Raw).

The following code reads historical events from the server. Differences to the History Read Raw Example are marked in comments.

Step 1: Fill in the ReadEventDetails Structure.

The StartTime and EndTime are always UTC if specified. If the NumValuesPerNode is 0, all events are returned. However, the Server may still return a continuation point. The EventFilter must, at a minimum, specify the fields that are returned for each event. An additional clause can filter events based on the values of the fields.

ReadEventDetails details = m_details as ReadEventDetails;
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
if (m_nodeToContinue == null)
details = new ReadEventDetails();
details.StartTime = (StartTimeCK.Checked) ? StartTimeDP.Value.ToUniversalTime() : DateTime.MinValue;
details.EndTime = (EndTimeCK.Checked) ? EndTimeDP.Value.ToUniversalTime() : DateTime.MinValue;
details.NumValuesPerNode = (MaxReturnValuesCK.Checked) ? (uint)MaxReturnValuesNP.Value : 0;
details.Filter = m_currentFilter.ToEventFilter();
nodesToRead.Add(new HistoryReadValueId() { NodeId = nodeId });
m_details = details;
m_nodeToContinue = nodesToRead[0];

Step 2: Call the HistoryReadEvent Method.

Synchronous and asynchronous versions of the function exist. The result provides the events for each Node passed in the request.

// this is a blocking call so show the wait cursor.
Cursor = Cursors.WaitCursor;
// fetch the history (with a 10s timeout).
List<HistoryEventReadResult> results = session.HistoryReadEvent(
new RequestSettings() { OperationTimeout = 10000 });
// check for operation error.
if (StatusCode.IsBad(results[0].StatusCode))
m_parent.ShowError(this, "Read history call failed: " + results[0].StatusCode.ToString());
m_details = null;
m_nodeToContinue = null;
// update controls.
if (results[0].Events != null)
foreach (var value in results[0].Events)

Step 3: Manage the ContinuationPoint

Each result returned can have a ContinuationPoint. The HistoryReadEvent must be called again with the ContinuationPoint to fetch the additional result. If it is not called, the ContinuationPoints must be released with a call to ReleaseHistoryContinuationPoints. The ReadEventDetails passed to the original call to HistoryReadEvent must be passed to ReleaseHistoryContinuationPoints.

// save continuation point.
if (!ByteString.IsNull(results[0].ContinuationPoint))
m_nodeToContinue.ContinuationPoint = results[0].ContinuationPoint;
ReleaseContinuationPointBTN.Visible = true;
m_nodeToContinue = null;
ReleaseContinuationPointBTN.Visible = false;