2353 lines
83 KiB
C#
2353 lines
83 KiB
C#
/* ========================================================================
|
|
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
|
|
*
|
|
* OPC Foundation MIT License 1.00
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* The complete license agreement can be found here:
|
|
* http://opcfoundation.org/License/MIT/1.00/
|
|
* ======================================================================*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Data;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using Opc.Ua;
|
|
using Opc.Ua.Client;
|
|
|
|
namespace Opc.Ua.Client.Controls
|
|
{
|
|
/// <summary>
|
|
/// Displays the results from a history read operation.
|
|
/// </summary>
|
|
public partial class HistoryDataListView : UserControl
|
|
{
|
|
#region Constructors
|
|
/// <summary>
|
|
/// Constructs a new instance.
|
|
/// </summary>
|
|
public HistoryDataListView()
|
|
{
|
|
InitializeComponent();
|
|
ResultsDV.AutoGenerateColumns = false;
|
|
LeftPN.Enabled = false;
|
|
|
|
ReadTypeCB.Items.Add(HistoryReadType.Raw);
|
|
ReadTypeCB.Items.Add(HistoryReadType.Processed);
|
|
ReadTypeCB.Items.Add(HistoryReadType.Modified);
|
|
ReadTypeCB.Items.Add(HistoryReadType.AtTime);
|
|
ReadTypeCB.Items.Add(HistoryReadType.Subscribe);
|
|
ReadTypeCB.Items.Add(HistoryReadType.Insert);
|
|
ReadTypeCB.Items.Add(HistoryReadType.InsertReplace);
|
|
ReadTypeCB.Items.Add(HistoryReadType.Replace);
|
|
ReadTypeCB.Items.Add(HistoryReadType.Remove);
|
|
ReadTypeCB.Items.Add(HistoryReadType.DeleteRaw);
|
|
ReadTypeCB.Items.Add(HistoryReadType.DeleteModified);
|
|
ReadTypeCB.Items.Add(HistoryReadType.DeleteAtTime);
|
|
ReadTypeCB.SelectedIndex = 0;
|
|
|
|
m_dataset = new DataSet();
|
|
m_dataset.Tables.Add("Results");
|
|
|
|
m_dataset.Tables[0].Columns.Add("Index", typeof(int));
|
|
m_dataset.Tables[0].Columns.Add("SourceTimestamp", typeof(string));
|
|
m_dataset.Tables[0].Columns.Add("ServerTimestamp", typeof(string));
|
|
m_dataset.Tables[0].Columns.Add("Value", typeof(Variant));
|
|
m_dataset.Tables[0].Columns.Add("StatusCode", typeof(StatusCode));
|
|
m_dataset.Tables[0].Columns.Add("HistoryInfo", typeof(string));
|
|
m_dataset.Tables[0].Columns.Add("UpdateType", typeof(HistoryUpdateType));
|
|
m_dataset.Tables[0].Columns.Add("UpdateTime", typeof(string));
|
|
m_dataset.Tables[0].Columns.Add("UserName", typeof(string));
|
|
m_dataset.Tables[0].Columns.Add("DataValue", typeof(DataValue));
|
|
m_dataset.Tables[0].Columns.Add("UpdateResult", typeof(StatusCode));
|
|
|
|
m_dataset.Tables[0].DefaultView.Sort = "Index";
|
|
|
|
ResultsDV.DataSource = m_dataset.Tables[0];
|
|
}
|
|
#endregion
|
|
|
|
#region HistoryReadType Class
|
|
/// <summary>
|
|
/// The type history read operation.
|
|
/// </summary>
|
|
public enum HistoryReadType
|
|
{
|
|
/// <summary>
|
|
/// Subscribe to data changes.
|
|
/// </summary>
|
|
Subscribe,
|
|
|
|
/// <summary>
|
|
/// Read raw data.
|
|
/// </summary>
|
|
Raw,
|
|
|
|
/// <summary>
|
|
/// Read modified data.
|
|
/// </summary>
|
|
Modified,
|
|
|
|
/// <summary>
|
|
/// Read data at the specified times.
|
|
/// </summary>
|
|
AtTime,
|
|
|
|
/// <summary>
|
|
/// Read processed data.
|
|
/// </summary>
|
|
Processed,
|
|
|
|
/// <summary>
|
|
/// Insert data.
|
|
/// </summary>
|
|
Insert,
|
|
|
|
/// <summary>
|
|
/// Insert or replace data.
|
|
/// </summary>
|
|
InsertReplace,
|
|
|
|
/// <summary>
|
|
/// Replace data.
|
|
/// </summary>
|
|
Replace,
|
|
|
|
/// <summary>
|
|
/// Remove data.
|
|
/// </summary>
|
|
Remove,
|
|
|
|
/// <summary>
|
|
/// Delete raw data.
|
|
/// </summary>
|
|
DeleteRaw,
|
|
|
|
/// <summary>
|
|
/// Delete modified data.
|
|
/// </summary>
|
|
DeleteModified,
|
|
|
|
/// <summary>
|
|
/// Delete data at the specified times.
|
|
/// </summary>
|
|
DeleteAtTime
|
|
}
|
|
#endregion
|
|
|
|
#region AvailableAggregate Class
|
|
/// <summary>
|
|
/// An aggregate supported by server.
|
|
/// </summary>
|
|
private class AvailableAggregate
|
|
{
|
|
public NodeId NodeId { get; set; }
|
|
public string DisplayName { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return DisplayName;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region AvailableSession Class
|
|
/// <summary>
|
|
/// A session available in the conntrol.
|
|
/// </summary>
|
|
private class AvailableSession
|
|
{
|
|
public Session Session { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return Session.SessionName;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region PropertyWithHistory Class
|
|
/// <summary>
|
|
/// Stores the metadata about a property with history to read or update.
|
|
/// </summary>
|
|
private class PropertyWithHistory
|
|
{
|
|
public PropertyWithHistory()
|
|
{
|
|
}
|
|
|
|
public PropertyWithHistory(ReferenceDescription reference, byte accessLevel)
|
|
{
|
|
DisplayText = reference.ToString();
|
|
NodeId = (NodeId)reference.NodeId;
|
|
BrowseName = reference.BrowseName;
|
|
AccessLevel = accessLevel;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return DisplayText;
|
|
}
|
|
|
|
public string DisplayText;
|
|
public NodeId NodeId;
|
|
public QualifiedName BrowseName;
|
|
public byte AccessLevel;
|
|
}
|
|
#endregion
|
|
|
|
#region Private Fields
|
|
private Session m_session;
|
|
private Subscription m_subscription;
|
|
private MonitoredItem m_monitoredItem;
|
|
private NodeId m_nodeId;
|
|
private DataSet m_dataset;
|
|
private int m_nextId;
|
|
private bool m_isSubscribed;
|
|
private HistoryReadDetails m_details;
|
|
private HistoryReadValueId m_nodeToContinue;
|
|
private bool m_timesChanged;
|
|
private HistoricalDataConfigurationState m_configuration;
|
|
private List<PropertyWithHistory> m_properties;
|
|
#endregion
|
|
|
|
#region Public Members
|
|
/// <summary>
|
|
/// The node id to use.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public NodeId NodeId
|
|
{
|
|
get
|
|
{
|
|
return m_nodeId;
|
|
}
|
|
|
|
set
|
|
{
|
|
m_nodeId = value;
|
|
|
|
if (m_session != null)
|
|
{
|
|
NodeIdTB.Text = m_session.NodeCache.GetDisplayText(m_nodeId);
|
|
}
|
|
else
|
|
{
|
|
if (NodeId.IsNull(m_nodeId))
|
|
{
|
|
NodeIdTB.Text = String.Empty;
|
|
}
|
|
else
|
|
{
|
|
NodeIdTB.Text = m_nodeId.ToString();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The type of read operation.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public HistoryReadType ReadType
|
|
{
|
|
get { return (HistoryReadType)ReadTypeCB.SelectedItem; }
|
|
set { ReadTypeCB.SelectedItem = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The start time for the query.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public DateTime StartTime
|
|
{
|
|
get
|
|
{
|
|
if (StartTimeCK.Checked)
|
|
{
|
|
return DateTime.MinValue;
|
|
}
|
|
|
|
return StartTimeDP.Value;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value < Utils.TimeBase)
|
|
{
|
|
StartTimeCK.Checked = false;
|
|
return;
|
|
}
|
|
|
|
if (value.Kind == DateTimeKind.Local)
|
|
{
|
|
value = value.ToUniversalTime();
|
|
}
|
|
|
|
StartTimeCK.Checked = true;
|
|
StartTimeDP.Value = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The end time for the query.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public DateTime EndTime
|
|
{
|
|
get
|
|
{
|
|
if (EndTimeCK.Checked)
|
|
{
|
|
return DateTime.MinValue;
|
|
}
|
|
|
|
return EndTimeDP.Value;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (value < Utils.TimeBase)
|
|
{
|
|
EndTimeCK.Checked = false;
|
|
return;
|
|
}
|
|
|
|
if (value.Kind == DateTimeKind.Local)
|
|
{
|
|
value = value.ToUniversalTime();
|
|
}
|
|
|
|
EndTimeCK.Checked = true;
|
|
EndTimeDP.Value = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// THe maximum number of values to return.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public uint MaxReturnValues
|
|
{
|
|
get
|
|
{
|
|
if (MaxReturnValuesCK.Checked)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return (uint)MaxReturnValuesNP.Value;
|
|
}
|
|
|
|
set
|
|
{
|
|
MaxReturnValuesCK.Checked = value != 0;
|
|
MaxReturnValuesNP.Value = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// If true the bounds are returned in the query.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ReturnBounds
|
|
{
|
|
get
|
|
{
|
|
return ReturnBoundsCK.Checked;
|
|
}
|
|
|
|
set
|
|
{
|
|
ReturnBoundsCK.Checked = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The aggregate to calculate.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public NodeId Aggregate
|
|
{
|
|
get
|
|
{
|
|
AvailableAggregate aggregate = AggregateCB.SelectedItem as AvailableAggregate;
|
|
|
|
if (aggregate == null)
|
|
{
|
|
return NodeId.Null;
|
|
}
|
|
|
|
return aggregate.NodeId;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (NodeId.IsNull(value))
|
|
{
|
|
AggregateCB.SelectedIndex = -1;
|
|
return;
|
|
}
|
|
|
|
foreach (AvailableAggregate aggregate in AggregateCB.Items)
|
|
{
|
|
if (aggregate.NodeId == value)
|
|
{
|
|
AggregateCB.SelectedItem = value;
|
|
return;
|
|
|
|
}
|
|
}
|
|
|
|
throw new ArgumentException("Aggregate does match one of the available aggregates.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The processing interval to use.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public double ProcessingInterval
|
|
{
|
|
get { return (double)ProcessingIntervalNP.Value; }
|
|
set { ProcessingIntervalNP.Value = (decimal)value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Changes the session.
|
|
/// </summary>
|
|
public void ChangeSession(Session session)
|
|
{
|
|
if (Object.ReferenceEquals(session, m_session))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_session != null)
|
|
{
|
|
DeleteSubscription();
|
|
m_session = null;
|
|
}
|
|
|
|
if (session == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_session = session;
|
|
m_dataset.Clear();
|
|
LeftPN.Enabled = m_session != null;
|
|
|
|
if (m_session != null)
|
|
{
|
|
AggregateCB.Items.Clear();
|
|
|
|
ILocalNode node = m_session.NodeCache.Find(ObjectIds.Server_ServerCapabilities_AggregateFunctions) as ILocalNode;
|
|
|
|
if (node != null)
|
|
{
|
|
foreach (IReference reference in node.References.Find(ReferenceTypeIds.HierarchicalReferences, false, true, m_session.TypeTree))
|
|
{
|
|
ILocalNode aggregate = m_session.NodeCache.Find(reference.TargetId) as ILocalNode;
|
|
|
|
if (aggregate != null && aggregate.TypeDefinitionId == ObjectTypeIds.AggregateFunctionType)
|
|
{
|
|
AvailableAggregate item = new AvailableAggregate();
|
|
item.NodeId = aggregate.NodeId;
|
|
item.DisplayName = m_session.NodeCache.GetDisplayText(aggregate);
|
|
AggregateCB.Items.Add(item);
|
|
}
|
|
}
|
|
|
|
if (AggregateCB.Items.Count == 0)
|
|
{
|
|
AggregateCB.Items.Add(new AvailableAggregate() { NodeId = ObjectIds.AggregateFunction_Interpolative, DisplayName = BrowseNames.AggregateFunction_Interpolative });
|
|
AggregateCB.Items.Add(new AvailableAggregate() { NodeId = ObjectIds.AggregateFunction_Average, DisplayName = BrowseNames.AggregateFunction_Average });
|
|
AggregateCB.Items.Add(new AvailableAggregate() { NodeId = ObjectIds.AggregateFunction_TimeAverage, DisplayName = BrowseNames.AggregateFunction_TimeAverage });
|
|
AggregateCB.Items.Add(new AvailableAggregate() { NodeId = ObjectIds.AggregateFunction_Total, DisplayName = BrowseNames.AggregateFunction_Total });
|
|
AggregateCB.Items.Add(new AvailableAggregate() { NodeId = ObjectIds.AggregateFunction_Count, DisplayName = BrowseNames.AggregateFunction_Count });
|
|
}
|
|
|
|
if (AggregateCB.Items.Count > 0)
|
|
{
|
|
AggregateCB.SelectedIndex = 0;
|
|
}
|
|
}
|
|
|
|
SubscriptionStateChanged();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the control after the session has reconnected.
|
|
/// </summary>
|
|
public void SessionReconnected(Session session)
|
|
{
|
|
m_session = session;
|
|
|
|
if (m_session != null)
|
|
{
|
|
foreach (Subscription subscription in m_session.Subscriptions)
|
|
{
|
|
if (Object.ReferenceEquals(subscription.Handle, this))
|
|
{
|
|
m_subscription = subscription;
|
|
|
|
foreach (MonitoredItem monitoredItem in subscription.MonitoredItems)
|
|
{
|
|
m_monitoredItem = monitoredItem;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Changes the node monitored by the control.
|
|
/// </summary>
|
|
public void ChangeNode(NodeId nodeId)
|
|
{
|
|
m_nodeId = nodeId;
|
|
m_configuration = null;
|
|
m_properties = null;
|
|
PropertyCB.Items.Clear();
|
|
m_dataset.Clear();
|
|
NodeIdTB.Text = m_session.NodeCache.GetDisplayText(m_nodeId);
|
|
|
|
if (!NodeId.IsNull(nodeId))
|
|
{
|
|
m_properties = FindPropertiesWithHistory();
|
|
|
|
if (m_properties == null || m_properties.Count <= 1)
|
|
{
|
|
PropertyLB.Visible = false;
|
|
PropertyCB.Visible = false;
|
|
}
|
|
else
|
|
{
|
|
PropertyCB.Items.AddRange((object[])m_properties.ToArray());
|
|
PropertyCB.SelectedIndex = 0;
|
|
PropertyLB.Visible = true;
|
|
PropertyCB.Visible = true;
|
|
}
|
|
|
|
m_configuration = ReadConfiguration();
|
|
|
|
if (StatusCode.IsBad(m_configuration.Stepped.StatusCode))
|
|
{
|
|
this.ReadTypeCB.Enabled = false;
|
|
this.ReadTypeCB.SelectedItem = HistoryReadType.Subscribe;
|
|
}
|
|
else
|
|
{
|
|
this.ReadTypeCB.Enabled = true;
|
|
|
|
if (!m_timesChanged)
|
|
{
|
|
DateTime startTime = ReadFirstDate();
|
|
|
|
if (startTime != DateTime.MinValue)
|
|
{
|
|
StartTimeDP.Value = startTime;
|
|
}
|
|
|
|
DateTime endTime = ReadLastDate();
|
|
|
|
if (endTime != DateTime.MinValue)
|
|
{
|
|
EndTimeDP.Value = endTime;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_subscription != null)
|
|
{
|
|
MonitoredItem monitoredItem = new MonitoredItem(m_monitoredItem);
|
|
monitoredItem.StartNodeId = nodeId;
|
|
|
|
m_subscription.AddItem(monitoredItem);
|
|
m_subscription.RemoveItem(m_monitoredItem);
|
|
m_monitoredItem = monitoredItem;
|
|
|
|
monitoredItem.Notification += new MonitoredItemNotificationEventHandler(MonitoredItem_Notification);
|
|
|
|
m_subscription.ApplyChanges();
|
|
SubscriptionStateChanged();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the sort order for the control.
|
|
/// </summary>
|
|
/// <param name="mostRecentFirst">If true the most recent entries are displayed first.</param>
|
|
public void SetSortOrder(bool mostRecentFirst)
|
|
{
|
|
if (m_dataset != null && m_dataset.Tables.Count > 0)
|
|
{
|
|
if (mostRecentFirst)
|
|
{
|
|
m_dataset.Tables[0].DefaultView.Sort = "Index DESC";
|
|
}
|
|
else
|
|
{
|
|
m_dataset.Tables[0].DefaultView.Sort = "Index";
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A kludge to get around the stupid designer that keeps setting property values to bogus defaults.
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
NodeId = null;
|
|
ReadType = HistoryReadType.Raw;
|
|
StartTime = DateTime.MinValue;
|
|
EndTime = DateTime.MinValue;
|
|
Aggregate = null;
|
|
|
|
StartTimeCK.Checked = true;
|
|
EndTimeCK.Checked = false;
|
|
MaxReturnValuesCK.Checked = true;
|
|
MaxReturnValuesNP.Value = 10;
|
|
m_timesChanged = false;
|
|
ProcessingIntervalNP.Value = 5000;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows the configuration.
|
|
/// </summary>
|
|
public void ShowConfiguration()
|
|
{
|
|
if (m_session != null)
|
|
{
|
|
if (m_configuration != null)
|
|
{
|
|
new ViewNodeStateDlg().ShowDialog(m_session, m_configuration, null);
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
/// <summary>
|
|
/// Recursively collects the variables in a NodeState and returns a collection of BrowsePaths.
|
|
/// </summary>
|
|
public void GetBrowsePathFromNodeState(
|
|
ISystemContext context,
|
|
NodeId rootId,
|
|
NodeState parent,
|
|
RelativePath parentPath,
|
|
BrowsePathCollection browsePaths)
|
|
{
|
|
List<BaseInstanceState> children = new List<BaseInstanceState>();
|
|
parent.GetChildren(context, children);
|
|
|
|
for (int ii = 0; ii < children.Count; ii++)
|
|
{
|
|
BaseInstanceState child = children[ii];
|
|
|
|
BrowsePath browsePath = new BrowsePath();
|
|
browsePath.StartingNode = rootId;
|
|
browsePath.Handle = child;
|
|
|
|
if (parentPath != null)
|
|
{
|
|
browsePath.RelativePath.Elements.AddRange(parentPath.Elements);
|
|
}
|
|
|
|
RelativePathElement element = new RelativePathElement();
|
|
element.ReferenceTypeId = child.ReferenceTypeId;
|
|
element.IsInverse = false;
|
|
element.IncludeSubtypes = false;
|
|
element.TargetName = child.BrowseName;
|
|
|
|
browsePath.RelativePath.Elements.Add(element);
|
|
|
|
if (child.NodeClass == NodeClass.Variable)
|
|
{
|
|
browsePaths.Add(browsePath);
|
|
}
|
|
|
|
GetBrowsePathFromNodeState(context, rootId, child, browsePath.RelativePath, browsePaths);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the historical configuration for the node.
|
|
/// </summary>
|
|
private List<PropertyWithHistory> FindPropertiesWithHistory()
|
|
{
|
|
BrowseDescription nodeToBrowse = new BrowseDescription();
|
|
nodeToBrowse.NodeId = m_nodeId;
|
|
nodeToBrowse.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasProperty;
|
|
nodeToBrowse.IncludeSubtypes = true;
|
|
nodeToBrowse.BrowseDirection = BrowseDirection.Forward;
|
|
nodeToBrowse.NodeClassMask = 0;
|
|
nodeToBrowse.ResultMask = (uint)(BrowseResultMask.DisplayName | BrowseResultMask.BrowseName);
|
|
|
|
ReferenceDescriptionCollection references = ClientUtils.Browse(m_session, nodeToBrowse, false);
|
|
|
|
ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
|
|
|
|
for (int ii = 0; ii < references.Count; ii++)
|
|
{
|
|
if (references[ii].NodeId.IsAbsolute)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ReadValueId nodeToRead = new ReadValueId();
|
|
nodeToRead.NodeId = (NodeId)references[ii].NodeId;
|
|
nodeToRead.AttributeId = Attributes.AccessLevel;
|
|
nodeToRead.Handle = references[ii];
|
|
nodesToRead.Add(nodeToRead);
|
|
}
|
|
|
|
List<PropertyWithHistory> properties = new List<PropertyWithHistory>();
|
|
properties.Add(new PropertyWithHistory() { DisplayText = "(none)", NodeId = m_nodeId, AccessLevel = AccessLevels.HistoryReadOrWrite });
|
|
|
|
if (nodesToRead.Count > 0)
|
|
{
|
|
DataValueCollection values = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.Read(
|
|
null,
|
|
0,
|
|
TimestampsToReturn.Neither,
|
|
nodesToRead,
|
|
out values,
|
|
out diagnosticInfos);
|
|
|
|
ClientBase.ValidateResponse(values, nodesToRead);
|
|
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
|
|
|
|
for (int ii = 0; ii < nodesToRead.Count; ii++)
|
|
{
|
|
byte accessLevel = values[ii].GetValue<byte>(0);
|
|
|
|
if ((accessLevel & AccessLevels.HistoryRead) != 0)
|
|
{
|
|
properties.Add(new PropertyWithHistory((ReferenceDescription)nodesToRead[ii].Handle, accessLevel));
|
|
}
|
|
}
|
|
}
|
|
|
|
return properties;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the historical configuration for the node.
|
|
/// </summary>
|
|
private HistoricalDataConfigurationState ReadConfiguration()
|
|
{
|
|
// load the defaults for the historical configuration object.
|
|
HistoricalDataConfigurationState configuration = new HistoricalDataConfigurationState(null);
|
|
|
|
configuration.Definition = new PropertyState<string>(configuration);
|
|
configuration.MaxTimeInterval = new PropertyState<double>(configuration);
|
|
configuration.MinTimeInterval = new PropertyState<double>(configuration);
|
|
configuration.ExceptionDeviation = new PropertyState<double>(configuration);
|
|
configuration.ExceptionDeviationFormat = new PropertyState<ExceptionDeviationFormat>(configuration);
|
|
configuration.StartOfArchive = new PropertyState<DateTime>(configuration);
|
|
configuration.StartOfOnlineArchive = new PropertyState<DateTime>(configuration);
|
|
|
|
configuration.Create(
|
|
m_session.SystemContext,
|
|
null,
|
|
Opc.Ua.BrowseNames.HAConfiguration,
|
|
null,
|
|
false);
|
|
|
|
// get the browse paths to query.
|
|
RelativePathElement element = new RelativePathElement();
|
|
element.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasHistoricalConfiguration;
|
|
element.IsInverse = false;
|
|
element.IncludeSubtypes = false;
|
|
element.TargetName = Opc.Ua.BrowseNames.HAConfiguration;
|
|
|
|
RelativePath relativePath = new RelativePath();
|
|
relativePath.Elements.Add(element);
|
|
|
|
BrowsePathCollection pathsToTranslate = new BrowsePathCollection();
|
|
|
|
GetBrowsePathFromNodeState(
|
|
m_session.SystemContext,
|
|
m_nodeId,
|
|
configuration,
|
|
relativePath,
|
|
pathsToTranslate);
|
|
|
|
// translate browse paths.
|
|
BrowsePathResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.TranslateBrowsePathsToNodeIds(
|
|
null,
|
|
pathsToTranslate,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
ClientBase.ValidateResponse(results, pathsToTranslate);
|
|
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, pathsToTranslate);
|
|
|
|
// build list of values to read.
|
|
ReadValueIdCollection valuesToRead = new ReadValueIdCollection();
|
|
|
|
for (int ii = 0; ii < pathsToTranslate.Count; ii++)
|
|
{
|
|
BaseVariableState variable = (BaseVariableState)pathsToTranslate[ii].Handle;
|
|
variable.Value = null;
|
|
variable.StatusCode = StatusCodes.BadNotSupported;
|
|
|
|
if (StatusCode.IsBad(results[ii].StatusCode) || results[ii].Targets.Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (results[ii].Targets[0].RemainingPathIndex == UInt32.MaxValue && !results[ii].Targets[0].TargetId.IsAbsolute)
|
|
{
|
|
variable.NodeId = (NodeId)results[ii].Targets[0].TargetId;
|
|
|
|
ReadValueId valueToRead = new ReadValueId();
|
|
valueToRead.NodeId = variable.NodeId;
|
|
valueToRead.AttributeId = Attributes.Value;
|
|
valueToRead.Handle = variable;
|
|
valuesToRead.Add(valueToRead);
|
|
}
|
|
}
|
|
|
|
// read the values.
|
|
if (valuesToRead.Count > 0)
|
|
{
|
|
DataValueCollection values = null;
|
|
|
|
m_session.Read(
|
|
null,
|
|
0,
|
|
TimestampsToReturn.Neither,
|
|
valuesToRead,
|
|
out values,
|
|
out diagnosticInfos);
|
|
|
|
ClientBase.ValidateResponse(values, valuesToRead);
|
|
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, valuesToRead);
|
|
|
|
for (int ii = 0; ii < valuesToRead.Count; ii++)
|
|
{
|
|
BaseVariableState variable = (BaseVariableState)valuesToRead[ii].Handle;
|
|
variable.WrappedValue = values[ii].WrappedValue;
|
|
variable.StatusCode = values[ii].StatusCode;
|
|
}
|
|
}
|
|
|
|
return configuration;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the first date in the archive (truncates milliseconds and converts to local).
|
|
/// </summary>
|
|
private DateTime ReadFirstDate()
|
|
{
|
|
// use the historical data configuration if available.
|
|
if (m_configuration != null)
|
|
{
|
|
if (StatusCode.IsGood(m_configuration.StartOfOnlineArchive.StatusCode))
|
|
{
|
|
return m_configuration.StartOfOnlineArchive.Value.ToLocalTime();
|
|
}
|
|
|
|
if (StatusCode.IsGood(m_configuration.StartOfArchive.StatusCode))
|
|
{
|
|
return m_configuration.StartOfArchive.Value.ToLocalTime();
|
|
}
|
|
}
|
|
|
|
// do it the hard way (may take a long time with some servers).
|
|
ReadRawModifiedDetails details = new ReadRawModifiedDetails();
|
|
details.StartTime = new DateTime(1970, 1, 1);
|
|
details.EndTime = DateTime.MinValue;
|
|
details.NumValuesPerNode = 1;
|
|
details.IsReadModified = false;
|
|
details.ReturnBounds = false;
|
|
|
|
HistoryReadValueId nodeToRead = new HistoryReadValueId();
|
|
nodeToRead.NodeId = m_nodeId;
|
|
|
|
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
|
|
nodesToRead.Add(nodeToRead);
|
|
|
|
HistoryReadResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(details),
|
|
TimestampsToReturn.Source,
|
|
false,
|
|
nodesToRead,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
Session.ValidateResponse(results, nodesToRead);
|
|
Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
|
|
|
|
if (StatusCode.IsBad(results[0].StatusCode))
|
|
{
|
|
return DateTime.MinValue;
|
|
}
|
|
|
|
HistoryData data = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;
|
|
|
|
if (results == null)
|
|
{
|
|
return DateTime.MinValue;
|
|
}
|
|
|
|
DateTime startTime = data.DataValues[0].SourceTimestamp;
|
|
|
|
if (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0)
|
|
{
|
|
nodeToRead.ContinuationPoint = results[0].ContinuationPoint;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(details),
|
|
TimestampsToReturn.Source,
|
|
true,
|
|
nodesToRead,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
Session.ValidateResponse(results, nodesToRead);
|
|
Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
|
|
}
|
|
|
|
startTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, startTime.Hour, startTime.Minute, startTime.Second, 0, DateTimeKind.Utc);
|
|
startTime = startTime.ToLocalTime();
|
|
|
|
return startTime;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the last date in the archive (truncates milliseconds and converts to local).
|
|
/// </summary>
|
|
private DateTime ReadLastDate()
|
|
{
|
|
ReadRawModifiedDetails details = new ReadRawModifiedDetails();
|
|
details.StartTime = DateTime.MinValue;
|
|
details.EndTime = DateTime.UtcNow.AddDays(1);
|
|
details.NumValuesPerNode = 1;
|
|
details.IsReadModified = false;
|
|
details.ReturnBounds = false;
|
|
|
|
HistoryReadValueId nodeToRead = new HistoryReadValueId();
|
|
nodeToRead.NodeId = m_nodeId;
|
|
|
|
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
|
|
nodesToRead.Add(nodeToRead);
|
|
|
|
HistoryReadResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(details),
|
|
TimestampsToReturn.Source,
|
|
false,
|
|
nodesToRead,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
Session.ValidateResponse(results, nodesToRead);
|
|
Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
|
|
|
|
if (StatusCode.IsBad(results[0].StatusCode))
|
|
{
|
|
return DateTime.MinValue;
|
|
}
|
|
|
|
HistoryData data = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;
|
|
|
|
if (data == null || data.DataValues.Count == 0)
|
|
{
|
|
return DateTime.MinValue;
|
|
}
|
|
|
|
DateTime endTime = data.DataValues[0].SourceTimestamp;
|
|
|
|
if (results[0].ContinuationPoint != null && results[0].ContinuationPoint.Length > 0)
|
|
{
|
|
nodeToRead.ContinuationPoint = results[0].ContinuationPoint;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(details),
|
|
TimestampsToReturn.Source,
|
|
true,
|
|
nodesToRead,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
Session.ValidateResponse(results, nodesToRead);
|
|
Session.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
|
|
}
|
|
|
|
endTime = new DateTime(endTime.Year, endTime.Month, endTime.Day, endTime.Hour, endTime.Minute, endTime.Second, 0, DateTimeKind.Utc);
|
|
endTime = endTime.AddSeconds(1);
|
|
endTime = endTime.ToLocalTime();
|
|
|
|
return endTime;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the subscription.
|
|
/// </summary>
|
|
private void CreateSubscription()
|
|
{
|
|
if (m_session == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_subscription = new Subscription();
|
|
m_subscription.Handle = this;
|
|
m_subscription.DisplayName = null;
|
|
m_subscription.PublishingInterval = 1000;
|
|
m_subscription.KeepAliveCount = 10;
|
|
m_subscription.LifetimeCount = 100;
|
|
m_subscription.MaxNotificationsPerPublish = 1000;
|
|
m_subscription.PublishingEnabled = true;
|
|
m_subscription.TimestampsToReturn = TimestampsToReturn.Both;
|
|
|
|
m_session.AddSubscription(m_subscription);
|
|
m_subscription.Create();
|
|
|
|
m_monitoredItem = new MonitoredItem();
|
|
m_monitoredItem.StartNodeId = m_nodeId;
|
|
m_monitoredItem.AttributeId = Attributes.Value;
|
|
m_monitoredItem.SamplingInterval = (int)SamplingIntervalNP.Value;
|
|
m_monitoredItem.QueueSize = 1000;
|
|
m_monitoredItem.DiscardOldest = true;
|
|
|
|
// specify aggregate filter.
|
|
if (AggregateCB.SelectedItem != null)
|
|
{
|
|
AggregateFilter filter = new AggregateFilter();
|
|
|
|
if (StartTimeCK.Checked)
|
|
{
|
|
filter.StartTime = StartTimeDP.Value.ToUniversalTime();
|
|
}
|
|
else
|
|
{
|
|
filter.StartTime = DateTime.UtcNow;
|
|
}
|
|
|
|
filter.ProcessingInterval = (double)ProcessingIntervalNP.Value;
|
|
filter.AggregateType = ((AvailableAggregate)AggregateCB.SelectedItem).NodeId;
|
|
|
|
if (filter.AggregateType != null)
|
|
{
|
|
m_monitoredItem.Filter = filter;
|
|
}
|
|
}
|
|
|
|
m_monitoredItem.Notification += new MonitoredItemNotificationEventHandler(MonitoredItem_Notification);
|
|
|
|
m_subscription.AddItem(m_monitoredItem);
|
|
m_subscription.ApplyChanges();
|
|
SubscriptionStateChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes the subscription.
|
|
/// </summary>
|
|
private void DeleteSubscription()
|
|
{
|
|
if (m_subscription != null)
|
|
{
|
|
m_subscription.Delete(true);
|
|
m_session.RemoveSubscription(m_subscription);
|
|
m_subscription = null;
|
|
m_monitoredItem = null;
|
|
}
|
|
|
|
SubscriptionStateChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the controls after the subscription state changes.
|
|
/// </summary>
|
|
private void SubscriptionStateChanged()
|
|
{
|
|
if (m_monitoredItem != null)
|
|
{
|
|
if (ServiceResult.IsBad(m_monitoredItem.Status.Error))
|
|
{
|
|
StatusTB.Text = m_monitoredItem.Status.Error.ToString();
|
|
return;
|
|
}
|
|
|
|
StatusTB.Text = "Monitoring started.";
|
|
m_isSubscribed = true;
|
|
GoBTN.Enabled = false;
|
|
GoBTN.Visible = true;
|
|
StopBTN.Enabled = true;
|
|
NextBTN.Visible = false;
|
|
}
|
|
else
|
|
{
|
|
StatusTB.Text = "Monitoring stopped.";
|
|
m_isSubscribed = false;
|
|
GoBTN.Enabled = true;
|
|
GoBTN.Visible = true;
|
|
StopBTN.Enabled = false;
|
|
NextBTN.Visible = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a value to the grid.
|
|
/// </summary>
|
|
private void AddValue(DataValue value, ModificationInfo modificationInfo)
|
|
{
|
|
DataRow row = m_dataset.Tables[0].NewRow();
|
|
|
|
m_nextId += 10000;
|
|
|
|
row[0] = m_nextId;
|
|
UpdateRow(row, value, modificationInfo);
|
|
|
|
m_dataset.Tables[0].Rows.Add(row);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates a value in the grid.
|
|
/// </summary>
|
|
private void UpdateRow(DataRow row, DataValue value, ModificationInfo modificationInfo)
|
|
{
|
|
row[1] = value.SourceTimestamp.ToLocalTime().ToString("HH:mm:ss.fff");
|
|
row[2] = value.ServerTimestamp.ToLocalTime().ToString("HH:mm:ss.fff");
|
|
row[3] = value.WrappedValue;
|
|
row[4] = new StatusCode(value.StatusCode.Code);
|
|
row[5] = value.StatusCode.AggregateBits.ToString();
|
|
|
|
if (modificationInfo != null)
|
|
{
|
|
row[6] = modificationInfo.UpdateType;
|
|
row[7] = modificationInfo.ModificationTime.ToLocalTime().ToString("HH:mm:ss");
|
|
row[8] = modificationInfo.UserName;
|
|
}
|
|
|
|
row[9] = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the display with a new value for a monitored variable.
|
|
/// </summary>
|
|
private void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.BeginInvoke(new MonitoredItemNotificationEventHandler(MonitoredItem_Notification), monitoredItem, e);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (!Object.ReferenceEquals(monitoredItem.Subscription, m_subscription))
|
|
{
|
|
return;
|
|
}
|
|
|
|
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
|
|
|
|
if (notification == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AddValue(notification.Value, null);
|
|
m_dataset.AcceptChanges();
|
|
|
|
if (ResultsDV.Rows.Count > 0)
|
|
{
|
|
ResultsDV.FirstDisplayedCell = ResultsDV.Rows[ResultsDV.Rows.Count - 1].Cells[0];
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the next batch of history.
|
|
/// </summary>
|
|
private void ReadNext()
|
|
{
|
|
if (m_nodeToContinue == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
|
|
nodesToRead.Add(m_nodeToContinue);
|
|
|
|
HistoryReadResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(m_details),
|
|
TimestampsToReturn.Both,
|
|
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);
|
|
}
|
|
|
|
HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;
|
|
DisplayResults(values);
|
|
|
|
// save any continuation point.
|
|
SaveContinuationPoint(m_details, m_nodeToContinue, results[0].ContinuationPoint);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the currently selected historical variable or property node id.
|
|
/// </summary>
|
|
private NodeId GetSelectedNode()
|
|
{
|
|
if (PropertyCB.SelectedIndex >= 0)
|
|
{
|
|
return ((PropertyWithHistory)PropertyCB.SelectedItem).NodeId;
|
|
}
|
|
|
|
return m_nodeId;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the recent history.
|
|
/// </summary>
|
|
private void ReadRaw(bool isReadModified)
|
|
{
|
|
m_dataset.Clear();
|
|
|
|
ReadRawModifiedDetails details = new ReadRawModifiedDetails();
|
|
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.IsReadModified = isReadModified;
|
|
details.ReturnBounds = (isReadModified)?false:ReturnBoundsCK.Checked;
|
|
|
|
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
|
|
HistoryReadValueId nodeToRead = new HistoryReadValueId();
|
|
nodeToRead.NodeId = GetSelectedNode();
|
|
nodesToRead.Add(nodeToRead);
|
|
|
|
HistoryReadResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(details),
|
|
TimestampsToReturn.Both,
|
|
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);
|
|
}
|
|
|
|
HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;
|
|
DisplayResults(values);
|
|
|
|
// save any continuation point.
|
|
SaveContinuationPoint(details, nodeToRead, results[0].ContinuationPoint);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the recent history.
|
|
/// </summary>
|
|
private void ReadAtTime()
|
|
{
|
|
m_dataset.Clear();
|
|
|
|
ReadAtTimeDetails details = new ReadAtTimeDetails();
|
|
details.UseSimpleBounds = UseSimpleBoundsCK.Checked;
|
|
|
|
// generate times
|
|
DateTime startTime = StartTimeDP.Value.ToUniversalTime();
|
|
|
|
for (int ii = 0; ii < MaxReturnValuesNP.Value; ii++)
|
|
{
|
|
details.ReqTimes.Add(startTime.AddMilliseconds((double)(ii*TimeStepNP.Value)));
|
|
}
|
|
|
|
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
|
|
HistoryReadValueId nodeToRead = new HistoryReadValueId();
|
|
nodeToRead.NodeId = GetSelectedNode();
|
|
nodesToRead.Add(nodeToRead);
|
|
|
|
HistoryReadResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(details),
|
|
TimestampsToReturn.Both,
|
|
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);
|
|
}
|
|
|
|
HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;
|
|
DisplayResults(values);
|
|
|
|
// save any continuation point.
|
|
SaveContinuationPoint(details, nodeToRead, results[0].ContinuationPoint);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the recent history.
|
|
/// </summary>
|
|
private void ReadProcessed()
|
|
{
|
|
m_dataset.Clear();
|
|
|
|
AvailableAggregate aggregate = (AvailableAggregate)AggregateCB.SelectedItem;
|
|
|
|
if (aggregate == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ReadProcessedDetails details = new ReadProcessedDetails();
|
|
details.StartTime = StartTimeDP.Value.ToUniversalTime();
|
|
details.EndTime = EndTimeDP.Value.ToUniversalTime();
|
|
details.ProcessingInterval = (double)ProcessingIntervalNP.Value;
|
|
details.AggregateType.Add(aggregate.NodeId);
|
|
details.AggregateConfiguration.UseServerCapabilitiesDefaults = true;
|
|
|
|
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
|
|
HistoryReadValueId nodeToRead = new HistoryReadValueId();
|
|
nodeToRead.NodeId = m_nodeId;
|
|
nodesToRead.Add(nodeToRead);
|
|
|
|
HistoryReadResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(details),
|
|
TimestampsToReturn.Both,
|
|
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);
|
|
}
|
|
|
|
HistoryData values = ExtensionObject.ToEncodeable(results[0].HistoryData) as HistoryData;
|
|
DisplayResults(values);
|
|
|
|
// save any continuation point.
|
|
SaveContinuationPoint(details, nodeToRead, results[0].ContinuationPoint);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves a continuation point for later use.
|
|
/// </summary>
|
|
private void SaveContinuationPoint(HistoryReadDetails details, HistoryReadValueId nodeToRead, byte[] continuationPoint)
|
|
{
|
|
// clear existing continuation point.
|
|
if (m_nodeToContinue != null)
|
|
{
|
|
HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
|
|
nodesToRead.Add(m_nodeToContinue);
|
|
|
|
HistoryReadResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryRead(
|
|
null,
|
|
new ExtensionObject(m_details),
|
|
TimestampsToReturn.Neither,
|
|
true,
|
|
nodesToRead,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
ClientBase.ValidateResponse(results, nodesToRead);
|
|
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead);
|
|
}
|
|
|
|
m_details = null;
|
|
m_nodeToContinue = null;
|
|
|
|
// save new continutation point.
|
|
if (continuationPoint != null && continuationPoint.Length > 0)
|
|
{
|
|
m_details = details;
|
|
m_nodeToContinue = nodeToRead;
|
|
m_nodeToContinue.ContinuationPoint = continuationPoint;
|
|
}
|
|
|
|
// update controls.
|
|
if (m_nodeToContinue != null)
|
|
{
|
|
GoBTN.Visible = false;
|
|
NextBTN.Visible = true;
|
|
NextBTN.Enabled = true;
|
|
StopBTN.Enabled = true;
|
|
}
|
|
else
|
|
{
|
|
GoBTN.Visible = true;
|
|
GoBTN.Enabled = true;
|
|
NextBTN.Visible = false;
|
|
StopBTN.Enabled = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the history.
|
|
/// </summary>
|
|
private void InsertReplace(PerformUpdateType updateType)
|
|
{
|
|
DataValueCollection values = new DataValueCollection();
|
|
|
|
foreach (DataRowView row in m_dataset.Tables[0].DefaultView)
|
|
{
|
|
DataValue value = (DataValue)row.Row[9];
|
|
values.Add(value);
|
|
}
|
|
|
|
bool isStructured = false;
|
|
|
|
PropertyWithHistory property = PropertyCB.SelectedItem as PropertyWithHistory;
|
|
|
|
if (property != null && property.BrowseName == Opc.Ua.BrowseNames.Annotations)
|
|
{
|
|
isStructured = true;
|
|
}
|
|
|
|
HistoryUpdateResultCollection results = InsertReplace(GetSelectedNode(), updateType, isStructured, values);
|
|
|
|
ResultsDV.Columns[ResultsDV.Columns.Count - 1].Visible = true;
|
|
|
|
for (int ii = 0; ii < m_dataset.Tables[0].DefaultView.Count; ii++)
|
|
{
|
|
m_dataset.Tables[0].DefaultView[ii].Row[10] = results[0].OperationResults[ii];
|
|
}
|
|
|
|
m_dataset.AcceptChanges();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the history.
|
|
/// </summary>
|
|
private HistoryUpdateResultCollection InsertReplace(NodeId nodeId, PerformUpdateType updateType, bool isStructure, IList<DataValue> values)
|
|
{
|
|
HistoryUpdateDetails details = null;
|
|
|
|
if (isStructure)
|
|
{
|
|
UpdateStructureDataDetails details2 = new UpdateStructureDataDetails();
|
|
details2.NodeId = nodeId;
|
|
details2.PerformInsertReplace = updateType;
|
|
details2.UpdateValues.AddRange(values);
|
|
details = details2;
|
|
}
|
|
else
|
|
{
|
|
UpdateDataDetails details2 = new UpdateDataDetails();
|
|
details2.NodeId = nodeId;
|
|
details2.PerformInsertReplace = updateType;
|
|
details2.UpdateValues.AddRange(values);
|
|
details = details2;
|
|
}
|
|
|
|
ExtensionObjectCollection nodesToUpdate = new ExtensionObjectCollection();
|
|
nodesToUpdate.Add(new ExtensionObject(details));
|
|
|
|
HistoryUpdateResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryUpdate(
|
|
null,
|
|
nodesToUpdate,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
ClientBase.ValidateResponse(results, nodesToUpdate);
|
|
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToUpdate);
|
|
|
|
if (StatusCode.IsBad(results[0].StatusCode))
|
|
{
|
|
throw new ServiceResultException(results[0].StatusCode);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes the block of data.
|
|
/// </summary>
|
|
private void DeleteRaw(bool isModified)
|
|
{
|
|
DeleteRawModifiedDetails details = new DeleteRawModifiedDetails();
|
|
details.NodeId = m_nodeId;
|
|
details.IsDeleteModified = isModified;
|
|
details.StartTime = StartTimeDP.Value;
|
|
details.EndTime = EndTimeDP.Value;
|
|
|
|
ExtensionObjectCollection nodesToUpdate = new ExtensionObjectCollection();
|
|
nodesToUpdate.Add(new ExtensionObject(details));
|
|
|
|
HistoryUpdateResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryUpdate(
|
|
null,
|
|
nodesToUpdate,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
ClientBase.ValidateResponse(results, nodesToUpdate);
|
|
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToUpdate);
|
|
|
|
if (StatusCode.IsBad(results[0].StatusCode))
|
|
{
|
|
throw new ServiceResultException(results[0].StatusCode);
|
|
}
|
|
|
|
ResultsDV.Columns[ResultsDV.Columns.Count - 1].Visible = false;
|
|
m_dataset.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes the history.
|
|
/// </summary>
|
|
private void DeleteAtTime()
|
|
{
|
|
DeleteAtTimeDetails details = new DeleteAtTimeDetails();
|
|
details.NodeId = m_nodeId;
|
|
|
|
foreach (DataRowView row in m_dataset.Tables[0].DefaultView)
|
|
{
|
|
DateTime value = (DateTime)row.Row[1];
|
|
details.ReqTimes.Add(value);
|
|
}
|
|
|
|
ExtensionObjectCollection nodesToUpdate = new ExtensionObjectCollection();
|
|
nodesToUpdate.Add(new ExtensionObject(details));
|
|
|
|
HistoryUpdateResultCollection results = null;
|
|
DiagnosticInfoCollection diagnosticInfos = null;
|
|
|
|
m_session.HistoryUpdate(
|
|
null,
|
|
nodesToUpdate,
|
|
out results,
|
|
out diagnosticInfos);
|
|
|
|
ClientBase.ValidateResponse(results, nodesToUpdate);
|
|
ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToUpdate);
|
|
|
|
if (StatusCode.IsBad(results[0].StatusCode))
|
|
{
|
|
throw new ServiceResultException(results[0].StatusCode);
|
|
}
|
|
|
|
ResultsDV.Columns[ResultsDV.Columns.Count-1].Visible = true;
|
|
|
|
for (int ii = 0; ii < m_dataset.Tables[0].DefaultView.Count; ii++)
|
|
{
|
|
m_dataset.Tables[0].DefaultView[ii].Row[10] = results[0].OperationResults[ii];
|
|
}
|
|
|
|
m_dataset.AcceptChanges();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Displays the results of a history operation.
|
|
/// </summary>
|
|
private void DisplayResults(HistoryData values)
|
|
{
|
|
HistoryModifiedData modifiedData = values as HistoryModifiedData;
|
|
|
|
if (modifiedData != null)
|
|
{
|
|
ResultsDV.Columns[5].Visible = true;
|
|
ResultsDV.Columns[6].Visible = true;
|
|
ResultsDV.Columns[7].Visible = true;
|
|
ResultsDV.Columns[8].Visible = false;
|
|
|
|
for (int ii = 0; ii < modifiedData.DataValues.Count; ii++)
|
|
{
|
|
AddValue(modifiedData.DataValues[ii], modifiedData.ModificationInfos[ii]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResultsDV.Columns[5].Visible = false;
|
|
ResultsDV.Columns[6].Visible = false;
|
|
ResultsDV.Columns[7].Visible = false;
|
|
ResultsDV.Columns[8].Visible = false;
|
|
|
|
if (values != null)
|
|
{
|
|
foreach (DataValue value in values.DataValues)
|
|
{
|
|
AddValue(value, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_dataset.AcceptChanges();
|
|
}
|
|
|
|
private void NodeIdBTN_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (m_session == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ReferenceDescription reference = new SelectNodeDlg().ShowDialog(
|
|
m_session,
|
|
Opc.Ua.ObjectIds.ObjectsFolder,
|
|
null,
|
|
"Select Variable",
|
|
Opc.Ua.ReferenceTypeIds.Organizes,
|
|
Opc.Ua.ReferenceTypeIds.Aggregates);
|
|
|
|
if (reference == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (reference.NodeId != m_nodeId)
|
|
{
|
|
ChangeNode((NodeId)reference.NodeId);
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void SubscribeCK_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (m_session != null)
|
|
{
|
|
if (m_isSubscribed)
|
|
{
|
|
CreateSubscription();
|
|
}
|
|
else
|
|
{
|
|
DeleteSubscription();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void GoBTN_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
m_dataset.Tables[0].Rows.Clear();
|
|
|
|
switch ((HistoryReadType)ReadTypeCB.SelectedItem)
|
|
{
|
|
case HistoryReadType.Subscribe:
|
|
{
|
|
CreateSubscription();
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Raw:
|
|
{
|
|
ReadRaw(false);
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Modified:
|
|
{
|
|
ReadRaw(true);
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Processed:
|
|
{
|
|
ReadProcessed();
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.AtTime:
|
|
{
|
|
ReadAtTime();
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Insert:
|
|
{
|
|
InsertReplace(PerformUpdateType.Insert);
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Replace:
|
|
{
|
|
InsertReplace(PerformUpdateType.Replace);
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.InsertReplace:
|
|
{
|
|
InsertReplace(PerformUpdateType.Update);
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Remove:
|
|
{
|
|
InsertReplace(PerformUpdateType.Remove);
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.DeleteRaw:
|
|
{
|
|
DeleteRaw(false);
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.DeleteModified:
|
|
{
|
|
DeleteRaw(true);
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.DeleteAtTime:
|
|
{
|
|
DeleteAtTime();
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void NextBTN_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
ReadNext();
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void StopBTN_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
DeleteSubscription();
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void ReadTypeCB_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
HistoryReadType readType = (HistoryReadType)ReadTypeCB.SelectedItem;
|
|
|
|
switch (readType)
|
|
{
|
|
case HistoryReadType.Subscribe:
|
|
{
|
|
PropertyLB.Visible = false;
|
|
PropertyCB.Visible = false;
|
|
SamplingIntervalLB.Visible = true;
|
|
SamplingIntervalNP.Visible = true;
|
|
SamplingIntervalUnitsLB.Visible = true;
|
|
StartTimeLB.Visible = true;
|
|
StartTimeDP.Visible = true;
|
|
StartTimeCK.Visible = true;
|
|
StartTimeCK.Enabled = true;
|
|
StartTimeCK.Checked = false;
|
|
EndTimeLB.Visible = false;
|
|
EndTimeDP.Visible = false;
|
|
EndTimeCK.Visible = false;
|
|
MaxReturnValuesLB.Visible = false;
|
|
MaxReturnValuesNP.Visible = false;
|
|
MaxReturnValuesCK.Visible = false;
|
|
ReturnBoundsLB.Visible = false;
|
|
ReturnBoundsCK.Visible = false;
|
|
AggregateLB.Visible = true;
|
|
AggregateCB.Visible = true;
|
|
ResampleIntervalLB.Visible = true;
|
|
ProcessingIntervalNP.Visible = true;
|
|
ResampleIntervalUnitsLB.Visible = true;
|
|
TimeStepLB.Visible = false;
|
|
TimeStepNP.Visible = false;
|
|
TimeStepUnitsLB.Visible = false;
|
|
UseSimpleBoundsLB.Visible = false;
|
|
UseSimpleBoundsCK.Visible = false;
|
|
TimeShiftBTN.Visible = false;
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Raw:
|
|
{
|
|
PropertyLB.Visible = (m_properties != null && m_properties.Count > 1);
|
|
PropertyCB.Visible = (m_properties != null && m_properties.Count > 1);
|
|
SamplingIntervalLB.Visible = false;
|
|
SamplingIntervalNP.Visible = false;
|
|
SamplingIntervalUnitsLB.Visible = false;
|
|
StartTimeLB.Visible = true;
|
|
StartTimeDP.Visible = true;
|
|
StartTimeCK.Visible = true;
|
|
StartTimeCK.Enabled = true;
|
|
StartTimeCK.Checked = true;
|
|
EndTimeLB.Visible = true;
|
|
EndTimeDP.Visible = true;
|
|
EndTimeCK.Visible = true;
|
|
EndTimeCK.Enabled = true;
|
|
MaxReturnValuesLB.Visible = true;
|
|
MaxReturnValuesNP.Visible = true;
|
|
MaxReturnValuesCK.Visible = true;
|
|
MaxReturnValuesCK.Enabled = true;
|
|
MaxReturnValuesCK.Checked = true;
|
|
ReturnBoundsLB.Visible = true;
|
|
ReturnBoundsCK.Visible = true;
|
|
AggregateLB.Visible = false;
|
|
AggregateCB.Visible = false;
|
|
ResampleIntervalLB.Visible = false;
|
|
ProcessingIntervalNP.Visible = false;
|
|
ResampleIntervalUnitsLB.Visible = false;
|
|
TimeStepLB.Visible = false;
|
|
TimeStepNP.Visible = false;
|
|
TimeStepUnitsLB.Visible = false;
|
|
UseSimpleBoundsLB.Visible = false;
|
|
UseSimpleBoundsCK.Visible = false;
|
|
TimeShiftBTN.Visible = false;
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Modified:
|
|
{
|
|
PropertyLB.Visible = false;
|
|
PropertyCB.Visible = false;
|
|
SamplingIntervalLB.Visible = false;
|
|
SamplingIntervalNP.Visible = false;
|
|
SamplingIntervalUnitsLB.Visible = false;
|
|
StartTimeLB.Visible = true;
|
|
StartTimeDP.Visible = true;
|
|
StartTimeCK.Visible = true;
|
|
StartTimeCK.Enabled = true;
|
|
StartTimeCK.Checked = true;
|
|
EndTimeLB.Visible = true;
|
|
EndTimeDP.Visible = true;
|
|
EndTimeCK.Visible = true;
|
|
EndTimeCK.Enabled = true;
|
|
MaxReturnValuesLB.Visible = true;
|
|
MaxReturnValuesNP.Visible = true;
|
|
MaxReturnValuesCK.Visible = true;
|
|
MaxReturnValuesCK.Enabled = true;
|
|
MaxReturnValuesCK.Checked = true;
|
|
ReturnBoundsLB.Visible = false;
|
|
ReturnBoundsCK.Visible = false;
|
|
AggregateLB.Visible = false;
|
|
AggregateCB.Visible = false;
|
|
ResampleIntervalLB.Visible = false;
|
|
ProcessingIntervalNP.Visible = false;
|
|
ResampleIntervalUnitsLB.Visible = false;
|
|
TimeStepLB.Visible = false;
|
|
TimeStepNP.Visible = false;
|
|
TimeStepUnitsLB.Visible = false;
|
|
UseSimpleBoundsLB.Visible = false;
|
|
UseSimpleBoundsCK.Visible = false;
|
|
TimeShiftBTN.Visible = false;
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Processed:
|
|
{
|
|
PropertyLB.Visible = false;
|
|
PropertyCB.Visible = false;
|
|
SamplingIntervalLB.Visible = false;
|
|
SamplingIntervalNP.Visible = false;
|
|
SamplingIntervalUnitsLB.Visible = false;
|
|
StartTimeLB.Visible = true;
|
|
StartTimeDP.Visible = true;
|
|
StartTimeCK.Visible = true;
|
|
StartTimeCK.Enabled = false;
|
|
StartTimeCK.Checked = true;
|
|
EndTimeLB.Visible = true;
|
|
EndTimeDP.Visible = true;
|
|
EndTimeCK.Visible = true;
|
|
EndTimeCK.Enabled = false;
|
|
EndTimeCK.Checked = true;
|
|
MaxReturnValuesLB.Visible = false;
|
|
MaxReturnValuesNP.Visible = false;
|
|
MaxReturnValuesCK.Visible = false;
|
|
ReturnBoundsLB.Visible = false;
|
|
ReturnBoundsCK.Visible = false;
|
|
AggregateLB.Visible = true;
|
|
AggregateCB.Visible = true;
|
|
ResampleIntervalLB.Visible = true;
|
|
ProcessingIntervalNP.Visible = true;
|
|
ResampleIntervalUnitsLB.Visible = true;
|
|
TimeStepLB.Visible = false;
|
|
TimeStepNP.Visible = false;
|
|
TimeStepUnitsLB.Visible = false;
|
|
UseSimpleBoundsLB.Visible = false;
|
|
UseSimpleBoundsCK.Visible = false;
|
|
TimeShiftBTN.Visible = false;
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.AtTime:
|
|
{
|
|
PropertyLB.Visible = (m_properties != null && m_properties.Count > 1);
|
|
PropertyCB.Visible = (m_properties != null && m_properties.Count > 1);
|
|
SamplingIntervalLB.Visible = false;
|
|
SamplingIntervalNP.Visible = false;
|
|
SamplingIntervalUnitsLB.Visible = false;
|
|
StartTimeLB.Visible = true;
|
|
StartTimeDP.Visible = true;
|
|
StartTimeCK.Visible = true;
|
|
StartTimeCK.Enabled = false;
|
|
StartTimeCK.Checked = true;
|
|
EndTimeLB.Visible = false;
|
|
EndTimeDP.Visible = false;
|
|
EndTimeCK.Visible = false;
|
|
EndTimeCK.Enabled = false;
|
|
EndTimeCK.Checked = false;
|
|
MaxReturnValuesLB.Visible = true;
|
|
MaxReturnValuesNP.Visible = true;
|
|
MaxReturnValuesCK.Visible = true;
|
|
MaxReturnValuesCK.Enabled = false;
|
|
MaxReturnValuesCK.Checked = true;
|
|
ReturnBoundsLB.Visible = false;
|
|
ReturnBoundsCK.Visible = false;
|
|
AggregateLB.Visible = false;
|
|
AggregateCB.Visible = false;
|
|
ResampleIntervalLB.Visible = false;
|
|
ProcessingIntervalNP.Visible = false;
|
|
ResampleIntervalUnitsLB.Visible = false;
|
|
TimeStepLB.Visible = true;
|
|
TimeStepNP.Visible = true;
|
|
TimeStepUnitsLB.Visible = true;
|
|
UseSimpleBoundsLB.Visible = true;
|
|
UseSimpleBoundsCK.Visible = true;
|
|
TimeShiftBTN.Visible = false;
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.Insert:
|
|
case HistoryReadType.InsertReplace:
|
|
case HistoryReadType.Replace:
|
|
case HistoryReadType.Remove:
|
|
{
|
|
PropertyLB.Visible = (m_properties != null && m_properties.Count > 1);
|
|
PropertyCB.Visible = (m_properties != null && m_properties.Count > 1);
|
|
SamplingIntervalLB.Visible = false;
|
|
SamplingIntervalNP.Visible = false;
|
|
SamplingIntervalUnitsLB.Visible = false;
|
|
StartTimeLB.Visible = false;
|
|
StartTimeDP.Visible = false;
|
|
StartTimeCK.Visible = false;
|
|
StartTimeCK.Enabled = false;
|
|
StartTimeCK.Checked = false;
|
|
EndTimeLB.Visible = false;
|
|
EndTimeDP.Visible = false;
|
|
EndTimeCK.Visible = false;
|
|
EndTimeCK.Enabled = false;
|
|
EndTimeCK.Checked = false;
|
|
MaxReturnValuesLB.Visible = false;
|
|
MaxReturnValuesNP.Visible = false;
|
|
MaxReturnValuesCK.Visible = false;
|
|
MaxReturnValuesCK.Enabled = false;
|
|
MaxReturnValuesCK.Checked = false;
|
|
ReturnBoundsLB.Visible = false;
|
|
ReturnBoundsCK.Visible = false;
|
|
AggregateLB.Visible = false;
|
|
AggregateCB.Visible = false;
|
|
ResampleIntervalLB.Visible = false;
|
|
ProcessingIntervalNP.Visible = false;
|
|
ResampleIntervalUnitsLB.Visible = false;
|
|
TimeStepLB.Visible = true;
|
|
TimeStepNP.Visible = true;
|
|
TimeStepUnitsLB.Visible = true;
|
|
UseSimpleBoundsLB.Visible = false;
|
|
UseSimpleBoundsCK.Visible = false;
|
|
TimeShiftBTN.Visible = true;
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.DeleteAtTime:
|
|
{
|
|
PropertyLB.Visible = false;
|
|
PropertyCB.Visible = false;
|
|
SamplingIntervalLB.Visible = false;
|
|
SamplingIntervalNP.Visible = false;
|
|
SamplingIntervalUnitsLB.Visible = false;
|
|
StartTimeLB.Visible = false;
|
|
StartTimeDP.Visible = false;
|
|
StartTimeCK.Visible = false;
|
|
StartTimeCK.Enabled = false;
|
|
StartTimeCK.Checked = false;
|
|
EndTimeLB.Visible = false;
|
|
EndTimeDP.Visible = false;
|
|
EndTimeCK.Visible = false;
|
|
EndTimeCK.Enabled = false;
|
|
EndTimeCK.Checked = false;
|
|
MaxReturnValuesLB.Visible = false;
|
|
MaxReturnValuesNP.Visible = false;
|
|
MaxReturnValuesCK.Visible = false;
|
|
MaxReturnValuesCK.Enabled = false;
|
|
MaxReturnValuesCK.Checked = false;
|
|
ReturnBoundsLB.Visible = false;
|
|
ReturnBoundsCK.Visible = false;
|
|
AggregateLB.Visible = false;
|
|
AggregateCB.Visible = false;
|
|
ResampleIntervalLB.Visible = false;
|
|
ProcessingIntervalNP.Visible = false;
|
|
ResampleIntervalUnitsLB.Visible = false;
|
|
TimeStepLB.Visible = false;
|
|
TimeStepNP.Visible = false;
|
|
TimeStepUnitsLB.Visible = false;
|
|
UseSimpleBoundsLB.Visible = false;
|
|
UseSimpleBoundsCK.Visible = false;
|
|
TimeShiftBTN.Visible = false;
|
|
break;
|
|
}
|
|
|
|
case HistoryReadType.DeleteRaw:
|
|
case HistoryReadType.DeleteModified:
|
|
{
|
|
PropertyLB.Visible = false;
|
|
PropertyCB.Visible = false;
|
|
SamplingIntervalLB.Visible = false;
|
|
SamplingIntervalNP.Visible = false;
|
|
SamplingIntervalUnitsLB.Visible = false;
|
|
StartTimeLB.Visible = true;
|
|
StartTimeDP.Visible = true;
|
|
StartTimeCK.Visible = true;
|
|
StartTimeCK.Enabled = false;
|
|
StartTimeCK.Checked = true;
|
|
EndTimeLB.Visible = true;
|
|
EndTimeDP.Visible = true;
|
|
EndTimeCK.Visible = true;
|
|
EndTimeCK.Enabled = false;
|
|
EndTimeCK.Checked = true;
|
|
EndTimeCK.Visible = false;
|
|
MaxReturnValuesNP.Visible = false;
|
|
MaxReturnValuesCK.Visible = false;
|
|
MaxReturnValuesCK.Enabled = false;
|
|
MaxReturnValuesCK.Checked = false;
|
|
ReturnBoundsLB.Visible = false;
|
|
ReturnBoundsCK.Visible = false;
|
|
AggregateLB.Visible = false;
|
|
AggregateCB.Visible = false;
|
|
ResampleIntervalLB.Visible = false;
|
|
ProcessingIntervalNP.Visible = false;
|
|
ResampleIntervalUnitsLB.Visible = false;
|
|
TimeStepLB.Visible = false;
|
|
TimeStepNP.Visible = false;
|
|
TimeStepUnitsLB.Visible = false;
|
|
UseSimpleBoundsLB.Visible = false;
|
|
UseSimpleBoundsCK.Visible = false;
|
|
TimeShiftBTN.Visible = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Event Handlers
|
|
private void StartTimeDP_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
m_timesChanged = true;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void DetectLimitsBTN_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
DateTime startTime = ReadFirstDate();
|
|
|
|
if (startTime != DateTime.MinValue)
|
|
{
|
|
StartTimeDP.Value = startTime;
|
|
}
|
|
|
|
DateTime endTime = ReadLastDate();
|
|
|
|
if (endTime != DateTime.MinValue)
|
|
{
|
|
EndTimeDP.Value = endTime;
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void StartTimeCK_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
StartTimeDP.Enabled = StartTimeCK.Checked;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void EndTimeCK_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
EndTimeDP.Enabled = EndTimeCK.Checked;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void MaxReturnValuesCK_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
MaxReturnValuesNP.Enabled = MaxReturnValuesCK.Checked;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void TimeShiftBTN_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
foreach (DataRowView row in m_dataset.Tables[0].DefaultView)
|
|
{
|
|
DataValue value = (DataValue)row.Row[9];
|
|
value.SourceTimestamp = value.SourceTimestamp.AddMilliseconds((double)TimeStepNP.Value);
|
|
value.ServerTimestamp = value.ServerTimestamp.AddMilliseconds((double)TimeStepNP.Value);
|
|
|
|
row[1] = value.SourceTimestamp.ToLocalTime().ToString("HH:mm:ss.fff");
|
|
row[2] = value.ServerTimestamp.ToLocalTime().ToString("HH:mm:ss.fff");
|
|
}
|
|
|
|
m_dataset.AcceptChanges();
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void InsertAnnotationMI_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (m_session == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NodeId propertyId = null;
|
|
|
|
if (m_properties != null)
|
|
{
|
|
foreach (PropertyWithHistory property in m_properties)
|
|
{
|
|
if (property.BrowseName == Opc.Ua.BrowseNames.Annotations)
|
|
{
|
|
propertyId = property.NodeId;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (propertyId == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Annotation annotation = new EditAnnotationDlg().ShowDialog(m_session, null, null);
|
|
|
|
if (annotation != null)
|
|
{
|
|
List<DataValue> valuesToUpdate = new List<DataValue>();
|
|
|
|
foreach (DataGridViewRow row in ResultsDV.SelectedRows)
|
|
{
|
|
DataRowView source = row.DataBoundItem as DataRowView;
|
|
DataValue value = (DataValue)source.Row[9];
|
|
|
|
}
|
|
|
|
HistoryUpdateResultCollection results = InsertReplace(propertyId, PerformUpdateType.Insert, true, valuesToUpdate);
|
|
|
|
ResultsDV.Columns[ResultsDV.Columns.Count - 1].Visible = true;
|
|
|
|
for (int ii = 0; ii < ResultsDV.SelectedRows.Count; ii++)
|
|
{
|
|
DataGridViewRow row = ResultsDV.SelectedRows[ii];
|
|
DataRowView source = row.DataBoundItem as DataRowView;
|
|
source.Row[10] = results[0].OperationResults[ii];
|
|
}
|
|
|
|
m_dataset.AcceptChanges();
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void EditValueMI_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (m_session == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (DataGridViewRow row in ResultsDV.SelectedRows)
|
|
{
|
|
DataRowView source = row.DataBoundItem as DataRowView;
|
|
DataValue value = (DataValue)source.Row[9];
|
|
|
|
DataValue newValue = new EditDataValueDlg().ShowDialog(value, null, null);
|
|
|
|
if (newValue == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UpdateRow(source.Row, newValue, null);
|
|
m_dataset.AcceptChanges();
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
ClientUtils.HandleException(this.Text, exception);
|
|
}
|
|
}
|
|
|
|
private void ShowServerTimestampMI_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
ServerTimestampCH.Visible = ShowServerTimestampMI.Checked;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|