/// <summary> /// Initializes a new instance of the <see cref="MonitoredItemAttribute"/> class. /// </summary> /// <param name="nodeId">the NodeId to monitor.</param> /// <param name="attributeId">the attribute to monitor.</param> /// <param name="indexRange">the range of array indexes to monitor.</param> /// <param name="samplingInterval">the sampling interval.</param> /// <param name="queueSize">the length of the queue used by the server to buffer values.</param> /// <param name="discardOldest">a value indicating whether to discard the oldest entries in the queue when it is full.</param> /// <param name="dataChangeTrigger">the properties that trigger a data change.</param> /// <param name="deadbandType">the type of deadband calculation.</param> /// <param name="deadbandValue">the deadband value.</param> public MonitoredItemAttribute(string nodeId = null, uint attributeId = AttributeIds.Value, string indexRange = null, int samplingInterval = -1, uint queueSize = 0, bool discardOldest = true, DataChangeTrigger dataChangeTrigger = DataChangeTrigger.StatusValue, DeadbandType deadbandType = DeadbandType.None, double deadbandValue = 0.0) { this.NodeId = nodeId; this.AttributeId = attributeId; this.IndexRange = indexRange; this.SamplingInterval = samplingInterval; this.QueueSize = queueSize; this.DiscardOldest = discardOldest; this.DataChangeTrigger = dataChangeTrigger; this.DeadbandType = deadbandType; this.DeadbandValue = deadbandValue; }
/// <summary> /// Initializes a new instance of the <see cref="MonitoredItemAttribute"/> class. /// </summary> /// <param name="nodeId">the NodeId to monitor.</param> /// <param name="attributeId">the attribute to monitor.</param> /// <param name="indexRange">the range of array indexes to monitor.</param> /// <param name="samplingInterval">the sampling interval.</param> /// <param name="queueSize">the length of the queue used by the server to buffer values.</param> /// <param name="discardOldest">a value indicating whether to discard the oldest entries in the queue when it is full.</param> /// <param name="dataChangeTrigger">the properties that trigger a data change.</param> /// <param name="deadbandType">the type of deadband calculation.</param> /// <param name="deadbandValue">the deadband value.</param> public MonitoredItemAttribute(string nodeId, uint attributeId = AttributeIds.Value, string?indexRange = null, int samplingInterval = -1, uint queueSize = 0, bool discardOldest = true, DataChangeTrigger dataChangeTrigger = DataChangeTrigger.StatusValue, DeadbandType deadbandType = DeadbandType.None, double deadbandValue = 0.0) { NodeId = nodeId; AttributeId = attributeId; IndexRange = indexRange; SamplingInterval = samplingInterval; QueueSize = queueSize; DiscardOldest = discardOldest; DataChangeTrigger = dataChangeTrigger; DeadbandType = deadbandType; DeadbandValue = deadbandValue; }
private void DeadbandTypeCB_SelectedIndexChanged(object sender, EventArgs e) { DeadbandType deadbandType = (DeadbandType)DeadbandTypeCB.SelectedItem; DeadbandNC.Enabled = deadbandType != DeadbandType.None; if (deadbandType == DeadbandType.Percent) { DeadbandNC.Minimum = 0; DeadbandNC.Maximum = 100; } else { DeadbandNC.Minimum = Decimal.MinValue; DeadbandNC.Maximum = Decimal.MaxValue; } }
/// <summary> /// Returns true if the deadband was exceeded. /// </summary> private static bool ExceedsDeadband(double value1, double value2, DeadbandType deadbandType, double deadband, double range) { double baseline = 1; if (deadbandType == DeadbandType.Percent) { baseline = range / 100; } if (baseline > 0) { if (Math.Abs((value1 - value2)/baseline) <= (double)deadband) { return false; } } return true; }
/// <summary> /// Returns true if the deadband was exceeded. /// </summary> protected static bool ExceedsDeadband(object value1, object value2, DeadbandType deadbandType, double deadband, double range) { // cannot convert doubles safely to decimals. if (value1 is double) { return ExceedsDeadband((double)value1, (double)value2, deadbandType, deadband, range); } try { decimal decimal1 = Convert.ToDecimal(value1, CultureInfo.InvariantCulture); decimal decimal2 = Convert.ToDecimal(value2, CultureInfo.InvariantCulture); decimal baseline = 1; if (deadbandType == DeadbandType.Percent) { baseline = ((decimal)range) / 100; } if (baseline > 0) { if (Math.Abs((decimal1 - decimal2)/baseline) <= (decimal)deadband) { return false; } } } catch { // treat all conversion errors as evidence that the deadband was exceeded. } return true; }
/// <summary> /// Checks if the two values are equal. /// </summary> protected static bool Equals(object value1, object value2, DeadbandType deadbandType, double deadband, double range) { // check if reference to same object. if (Object.ReferenceEquals(value1, value2)) { return true; } // check for invalid values. if (value1 == null || value2 == null) { return value1 == value2; } // check for type change. if (value1.GetType() != value2.GetType()) { return false; } // check if values are equal. if (value1.Equals(value2)) { return true; } // check for arrays. Array array1 = value1 as Array; Array array2 = value2 as Array; if (array1 == null || array2 == null) { XmlElement xmlElement1 = value1 as XmlElement; XmlElement xmlElement2 = value2 as XmlElement; if (xmlElement1 != null && xmlElement2 != null) { return xmlElement1.OuterXml.Equals(xmlElement2.OuterXml); } // nothing more to do if no deadband. if (deadbandType == DeadbandType.None) { return false; } // check deadband. return !ExceedsDeadband(value1, value2, deadbandType, deadband, range); } // compare lengths. if (array1.Length != array2.Length) { return false; } // compare each element. bool isVariant = array1.GetType().GetElementType() == typeof(Variant); for (int ii = 0; ii < array1.Length; ii++) { object element1 = array1.GetValue(ii); object element2 = array2.GetValue(ii); if (isVariant) { element1 = ((Variant)element1).Value; element2 = ((Variant)element2).Value; } if (!Equals(element1, element2, deadbandType, deadband, range)) { return false; } } // must be equal. return true; }
/// <summary> /// Prompts the user to edit the monitored item. /// </summary> public bool ShowDialog(Session session, MonitoredItem monitoredItem, bool isEvent) { if (!monitoredItem.Created) { NodeBTN.Session = session; NodeBTN.SelectedNode = monitoredItem.StartNodeId; } // hide fields not used for events. NodeLB.Visible = !monitoredItem.Created; NodeTB.Visible = !monitoredItem.Created; NodeBTN.Visible = !monitoredItem.Created; AttributeLB.Visible = !isEvent && !monitoredItem.Created; AttributeCB.Visible = !isEvent && !monitoredItem.Created; IndexRangeLB.Visible = !isEvent && !monitoredItem.Created; IndexRangeTB.Visible = !isEvent && !monitoredItem.Created; DataEncodingLB.Visible = !isEvent && !monitoredItem.Created; DataEncodingCB.Visible = !isEvent && !monitoredItem.Created; MonitoringModeLB.Visible = !monitoredItem.Created; MonitoringModeCB.Visible = !monitoredItem.Created; SamplingIntervalLB.Visible = true; SamplingIntervalUP.Visible = true; QueueSizeLB.Visible = !isEvent; QueueSizeUP.Visible = !isEvent; DiscardOldestLB.Visible = true; DiscardOldestCK.Visible = true; DeadbandTypeLB.Visible = !isEvent; DeadbandTypeCB.Visible = !isEvent; DeadbandValueLB.Visible = !isEvent; DeadbandValueUP.Visible = !isEvent; TriggerTypeLB.Visible = !isEvent; TriggerTypeCB.Visible = !isEvent; // fill in values. SamplingIntervalUP.Value = monitoredItem.SamplingInterval; DiscardOldestCK.Checked = monitoredItem.DiscardOldest; if (!isEvent) { AttributeCB.SelectedIndex = (int)(monitoredItem.AttributeId - 1); IndexRangeTB.Text = monitoredItem.IndexRange; MonitoringModeCB.SelectedItem = monitoredItem.MonitoringMode; QueueSizeUP.Value = monitoredItem.QueueSize; DataChangeFilter filter = monitoredItem.Filter as DataChangeFilter; if (filter != null) { DeadbandTypeCB.SelectedItem = (DeadbandType)filter.DeadbandType; DeadbandValueUP.Value = (decimal)filter.DeadbandValue; TriggerTypeCB.SelectedItem = filter.Trigger; } if (!monitoredItem.Created) { // fetch the available encodings for the first node in the list from the server. IVariableBase variable = session.NodeCache.Find(monitoredItem.StartNodeId) as IVariableBase; DataEncodingCB.Items.Add(new EncodingInfo()); DataEncodingCB.SelectedIndex = 0; if (variable != null) { if (session.NodeCache.IsTypeOf(variable.DataType, Opc.Ua.DataTypeIds.Structure)) { foreach (INode encoding in session.NodeCache.Find(variable.DataType, Opc.Ua.ReferenceTypeIds.HasEncoding, false, true)) { DataEncodingCB.Items.Add(new EncodingInfo() { EncodingName = encoding.BrowseName }); if (monitoredItem.Encoding == encoding.BrowseName) { DataEncodingCB.SelectedIndex = DataEncodingCB.Items.Count - 1; } } } } } } else { AttributeCB.SelectedIndex = ((int)Attributes.EventNotifier - 1); } if (base.ShowDialog() != DialogResult.OK) { return(false); } // update monitored item. if (!monitoredItem.Created) { monitoredItem.StartNodeId = NodeBTN.SelectedNode; monitoredItem.DisplayName = session.NodeCache.GetDisplayText(monitoredItem.StartNodeId); monitoredItem.RelativePath = null; monitoredItem.AttributeId = (uint)(AttributeCB.SelectedIndex + 1); monitoredItem.MonitoringMode = (MonitoringMode)MonitoringModeCB.SelectedItem; } monitoredItem.SamplingInterval = (int)SamplingIntervalUP.Value; monitoredItem.DiscardOldest = DiscardOldestCK.Checked; if (!isEvent) { if (!monitoredItem.Created) { monitoredItem.IndexRange = IndexRangeTB.Text.Trim(); monitoredItem.Encoding = ((EncodingInfo)DataEncodingCB.SelectedItem).EncodingName; } monitoredItem.QueueSize = (uint)QueueSizeUP.Value; DataChangeTrigger trigger = (DataChangeTrigger)TriggerTypeCB.SelectedItem; DeadbandType deadbandType = (DeadbandType)DeadbandTypeCB.SelectedItem; if (monitoredItem.Filter != null || deadbandType != DeadbandType.None || trigger != DataChangeTrigger.StatusValue) { DataChangeFilter filter = new DataChangeFilter(); filter.DeadbandType = (uint)deadbandType; filter.DeadbandValue = (double)DeadbandValueUP.Value; filter.Trigger = trigger; monitoredItem.Filter = filter; } } else { if (!monitoredItem.Created) { monitoredItem.IndexRange = null; monitoredItem.Encoding = null; } monitoredItem.QueueSize = 0; monitoredItem.Filter = new EventFilter(); } return(true); }