Exemplo n.º 1
0
        /// <summary>
        /// Prompts the user to specify the browse options.
        /// </summary>
        public bool ShowDialog(Session session, MonitoredItem monitoredItem)
        {
            if (monitoredItem == null) throw new ArgumentNullException("monitoredItem");

            DataChangeFilter filter = monitoredItem.Filter as DataChangeFilter;

            if (filter == null)
            {
                filter = new DataChangeFilter();

                filter.Trigger       = DataChangeTrigger.StatusValue;
                filter.DeadbandValue = 0;
                filter.DeadbandType  = (uint)(int)DeadbandType.None;
            }

            TriggerCB.SelectedItem      = filter.Trigger;
            DeadbandTypeCB.SelectedItem = (DeadbandType)(int)filter.DeadbandType;
            DeadbandNC.Value            = (decimal)filter.DeadbandValue;
            
            if (ShowDialog() != DialogResult.OK)
            {
                return false;
            }

            filter.Trigger       = (DataChangeTrigger)TriggerCB.SelectedItem;
            filter.DeadbandType  = Convert.ToUInt32(DeadbandTypeCB.SelectedItem);
            filter.DeadbandValue = (double)DeadbandNC.Value;

            monitoredItem.Filter = filter;

            return true;
        }
Exemplo n.º 2
0
        /// <summary>
        /// Constructs a new instance.
        /// </summary>
        public DataChangeMonitoredItem(
            MonitoredNode source,
            uint id,
            uint attributeId,
            NumericRange indexRange,
            QualifiedName dataEncoding,
            DiagnosticsMasks diagnosticsMasks,
            TimestampsToReturn timestampsToReturn,
            MonitoringMode monitoringMode,
            uint clientHandle,
            double samplingInterval,
            uint queueSize,
            bool discardOldest,
            DataChangeFilter filter,
            Range range,
            bool alwaysReportUpdates)
        {
            m_source              = source;
            m_id                  = id;
            m_attributeId         = attributeId;
            m_indexRange          = indexRange;
            m_dataEncoding        = dataEncoding;
            m_timestampsToReturn  = timestampsToReturn;
            m_diagnosticsMasks    = diagnosticsMasks;
            m_monitoringMode      = monitoringMode;
            m_clientHandle        = clientHandle;
            m_samplingInterval    = samplingInterval;
            m_nextSampleTime      = DateTime.UtcNow.Ticks;
            m_readyToPublish      = false;
            m_readyToTrigger      = false;
            m_queue               = null;
            m_filter              = filter;
            m_range               = 0;
            m_alwaysReportUpdates = alwaysReportUpdates;

            if (range != null)
            {
                m_range = range.High - range.Low;
            }

            if (queueSize > 1)
            {
                m_queue = new MonitoredItemQueue();
                m_queue.SetQueueSize(queueSize, discardOldest, diagnosticsMasks);
                m_queue.SetSamplingInterval(samplingInterval);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Creates a new data change monitored item.
        /// </summary>
        /// <param name="context">The system context.</param>
        /// <param name="monitoredItemId">The unique identifier for the monitiored item.</param>
        /// <param name="attributeId">The attribute to monitor.</param>
        /// <param name="indexRange">The index range to use for array values.</param>
        /// <param name="dataEncoding">The data encoding to return for structured values.</param>
        /// <param name="diagnosticsMasks">The diagnostics masks to use.</param>
        /// <param name="timestampsToReturn">The timestamps to return.</param>
        /// <param name="monitoringMode">The initial monitoring mode.</param>
        /// <param name="clientHandle">The handle assigned by the client.</param>
        /// <param name="samplingInterval">The sampling interval.</param>
        /// <param name="queueSize">The queue size.</param>
        /// <param name="discardOldest">Whether to discard the oldest values when the queue overflows.</param>
        /// <param name="filter">The data change filter to use.</param>
        /// <param name="range">The range to use when evaluating a percentage deadband filter.</param>
        /// <param name="alwaysReportUpdates">Whether the monitored item should skip the check for a change in value.</param>
        /// <returns>The new monitored item.</returns>
        public DataChangeMonitoredItem CreateDataChangeItem(
            ISystemContext context,
            uint monitoredItemId,
            uint attributeId,
            NumericRange indexRange,
            QualifiedName dataEncoding,
            DiagnosticsMasks diagnosticsMasks,
            TimestampsToReturn timestampsToReturn,
            MonitoringMode monitoringMode,
            uint clientHandle,
            double samplingInterval,
            uint queueSize,
            bool discardOldest,
            DataChangeFilter filter,
            Range range,
            bool alwaysReportUpdates)
        {
            System.Diagnostics.Contracts.Contract.Assume(context != null);
            var monitoredItem = new DataChangeMonitoredItem(
                this,
                monitoredItemId,
                attributeId,
                indexRange,
                dataEncoding,
                diagnosticsMasks,
                timestampsToReturn,
                monitoringMode,
                clientHandle,
                samplingInterval,
                queueSize,
                discardOldest,
                filter,
                range,
                alwaysReportUpdates);

            if (_monitoredItems == null)
            {
                _monitoredItems     = new List <DataChangeMonitoredItem>();
                Node.OnStateChanged = OnNodeChange;
            }

            _monitoredItems.Add(monitoredItem);

            return(monitoredItem);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Converts a monitoring filter to text for display.
        /// </summary>
        /// <param name="filter">The filter.</param>
        /// <returns>The deadback formatted as a string.</returns>
        private string DeadbandFilterToText(MonitoringFilter filter)
        {
            DataChangeFilter datachangeFilter = filter as DataChangeFilter;

            if (datachangeFilter != null)
            {
                if (datachangeFilter.DeadbandType == (uint)DeadbandType.Absolute)
                {
                    return(Utils.Format("{0:##.##}", datachangeFilter.DeadbandValue));
                }

                if (datachangeFilter.DeadbandType == (uint)DeadbandType.Percent)
                {
                    return(Utils.Format("{0:##.##}%", datachangeFilter.DeadbandValue));
                }
            }

            return("None");
        }
        /// <summary>
        /// Creates a new data change monitored item.
        /// </summary>
        /// <param name="context">The system context.</param>
        /// <param name="monitoredItemId">The unique identifier for the monitiored item.</param>
        /// <param name="attributeId">The attribute to monitor.</param>
        /// <param name="indexRange">The index range to use for array values.</param>
        /// <param name="dataEncoding">The data encoding to return for structured values.</param>
        /// <param name="diagnosticsMasks">The diagnostics masks to use.</param>
        /// <param name="timestampsToReturn">The timestamps to return.</param>
        /// <param name="monitoringMode">The initial monitoring mode.</param>
        /// <param name="clientHandle">The handle assigned by the client.</param>
        /// <param name="samplingInterval">The sampling interval.</param>
        /// <param name="queueSize">The queue size.</param>
        /// <param name="discardOldest">Whether to discard the oldest values when the queue overflows.</param>
        /// <param name="filter">The data change filter to use.</param>
        /// <param name="range">The range to use when evaluating a percentage deadband filter.</param>
        /// <param name="alwaysReportUpdates">Whether the monitored item should skip the check for a change in value.</param>
        /// <returns>The new monitored item.</returns>
        public DataChangeMonitoredItem CreateDataChangeItem(
            ISystemContext context,
            uint monitoredItemId,
            uint attributeId,
            NumericRange indexRange,
            QualifiedName dataEncoding,
            DiagnosticsMasks diagnosticsMasks,
            TimestampsToReturn timestampsToReturn,
            MonitoringMode monitoringMode,
            uint clientHandle,
            double samplingInterval,
            uint queueSize,
            bool discardOldest,
            DataChangeFilter filter,
            Range range,
            bool alwaysReportUpdates)
        {
            DataChangeMonitoredItem monitoredItem = new DataChangeMonitoredItem(
                this,
                monitoredItemId,
                attributeId,
                indexRange,
                dataEncoding,
                diagnosticsMasks,
                timestampsToReturn,
                monitoringMode,
                clientHandle,
                samplingInterval,
                queueSize,
                discardOldest,
                filter,
                range,
                alwaysReportUpdates);

            if (m_monitoredItems == null)
            {
                m_monitoredItems = new List<DataChangeMonitoredItem>();
                m_node.OnStateChanged = OnNodeChange;
            }

            m_monitoredItems.Add(monitoredItem);

            return monitoredItem;
        }
Exemplo n.º 6
0
        /// <summary>
        /// Changes the deadband for the currently selected monitored items.
        /// </summary>
        private void Monitoring_Deadband_Click(object sender, EventArgs e)
        {
            try
            {
                // check if operation is currently allowed.
                if (m_session == null || m_subscription == null || MonitoredItemsLV.SelectedItems.Count == 0)
                {
                    return;
                }

                // determine the filter being requested.
                DataChangeFilter filter = new DataChangeFilter();
                filter.Trigger = DataChangeTrigger.StatusValue;

                if (sender == Monitoring_Deadband_Absolute_5MI)
                {
                    filter.DeadbandType  = (uint)DeadbandType.Absolute;
                    filter.DeadbandValue = 5.0;
                }
                else if (sender == Monitoring_Deadband_Absolute_10MI)
                {
                    filter.DeadbandType  = (uint)DeadbandType.Absolute;
                    filter.DeadbandValue = 10.0;
                }
                else if (sender == Monitoring_Deadband_Absolute_25MI)
                {
                    filter.DeadbandType  = (uint)DeadbandType.Absolute;
                    filter.DeadbandValue = 25.0;
                }
                else if (sender == Monitoring_Deadband_Percentage_1MI)
                {
                    filter.DeadbandType  = (uint)DeadbandType.Percent;
                    filter.DeadbandValue = 1.0;
                }
                else if (sender == Monitoring_Deadband_Percentage_5MI)
                {
                    filter.DeadbandType  = (uint)DeadbandType.Percent;
                    filter.DeadbandValue = 5.0;
                }
                else if (sender == Monitoring_Deadband_Percentage_10MI)
                {
                    filter.DeadbandType  = (uint)DeadbandType.Percent;
                    filter.DeadbandValue = 10.0;
                }
                else
                {
                    filter = null;
                }

                // update the monitoring mode.
                List <MonitoredItem> itemsToChange = new List <MonitoredItem>();

                for (int ii = 0; ii < MonitoredItemsLV.SelectedItems.Count; ii++)
                {
                    MonitoredItem monitoredItem = MonitoredItemsLV.SelectedItems[ii].Tag as MonitoredItem;

                    if (monitoredItem != null)
                    {
                        monitoredItem.Filter = filter;
                        itemsToChange.Add(monitoredItem);
                    }
                }

                // apply the changes to the server.
                m_subscription.ApplyChanges();

                // update the display.
                for (int ii = 0; ii < itemsToChange.Count; ii++)
                {
                    ListViewItem item = itemsToChange[ii].Handle as ListViewItem;

                    if (item != null)
                    {
                        item.SubItems[8].Text = String.Empty;

                        if (ServiceResult.IsBad(itemsToChange[ii].Status.Error))
                        {
                            itemsToChange[ii].Filter = null;
                            item.SubItems[8].Text    = itemsToChange[ii].Status.Error.StatusCode.ToString();
                        }

                        item.SubItems[4].Text = DeadbandFilterToText(itemsToChange[ii].Status.Filter);
                    }
                }
            }
            catch (Exception exception)
            {
                ClientUtils.HandleException(this.Text, exception);
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Updates the deadband filters.
        /// </summary>
        /// <param name="items">The items.</param>
        public void UpdateDeadbandFilters(IList<ComDaGroupItem> items)
        {
            // update the monitored item filter.
            for (int ii = 0; ii < items.Count; ii++)
            {
                ComDaGroupItem item = items[ii];

                if (item == null)
                {
                    continue;
                }

                if (item.EuType != (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG)
                {
                    item.MonitoredItem.Filter = null;
                    continue;
                }

                // do nothing if the filter is not set and is not required.
                if (item.MonitoredItem.Filter == null)
                {
                    if (this.Deadband <= 0 && item.Deadband <= 0)
                    {
                        continue;
                    }
                }

                DataChangeFilter filter = new DataChangeFilter();
                filter.Trigger = DataChangeTrigger.StatusValue;

                if (this.Deadband <= 0 && item.Deadband <= 0)
                {
                    filter.DeadbandType = (uint)DeadbandType.None;
                }
                else
                {
                    filter.DeadbandType = (uint)DeadbandType.Percent;
                    filter.DeadbandValue = this.Deadband;
                }

                if (item.Deadband >= 0)
                {
                    filter.DeadbandValue = item.Deadband;
                }

                item.MonitoredItem.Filter = filter;
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SubscriptionBase"/> class.
        /// </summary>
        public SubscriptionBase()
        {
            this.application = UaApplication.Current;
            this.application?.Completion.ContinueWith(t => this.stateMachineCts?.Cancel());
            this.logger           = this.application?.LoggerFactory?.CreateLogger(this.GetType());
            this.errors           = new ErrorsContainer <string>(p => this.ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(p)));
            this.progress         = new Progress <CommunicationState>(s => this.State = s);
            this.propertyChanged += this.OnPropertyChanged;
            this.whenSubscribed   = new TaskCompletionSource <bool>();
            this.whenUnsubscribed = new TaskCompletionSource <bool>();
            this.whenUnsubscribed.TrySetResult(true);

            // register the action to be run on the ui thread, if there is one.
            if (SynchronizationContext.Current != null)
            {
                this.actionBlock = new ActionBlock <PublishResponse>(pr => this.OnPublishResponse(pr), new ExecutionDataflowBlockOptions {
                    SingleProducerConstrained = true, TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
                });
            }
            else
            {
                this.actionBlock = new ActionBlock <PublishResponse>(pr => this.OnPublishResponse(pr), new ExecutionDataflowBlockOptions {
                    SingleProducerConstrained = true
                });
            }

            // read [Subscription] attribute.
            var typeInfo = this.GetType().GetTypeInfo();
            var sa       = typeInfo.GetCustomAttribute <SubscriptionAttribute>();

            if (sa != null)
            {
                this.endpointUrl        = sa.EndpointUrl;
                this.publishingInterval = sa.PublishingInterval;
                this.keepAliveCount     = sa.KeepAliveCount;
                this.lifetimeCount      = sa.LifetimeCount;
            }

            // read [MonitoredItem] attributes.
            foreach (var propertyInfo in typeInfo.DeclaredProperties)
            {
                var mia = propertyInfo.GetCustomAttribute <MonitoredItemAttribute>();
                if (mia == null || string.IsNullOrEmpty(mia.NodeId))
                {
                    continue;
                }

                MonitoringFilter filter = null;
                if (mia.AttributeId == AttributeIds.Value && (mia.DataChangeTrigger != DataChangeTrigger.StatusValue || mia.DeadbandType != DeadbandType.None))
                {
                    filter = new DataChangeFilter()
                    {
                        Trigger = mia.DataChangeTrigger, DeadbandType = (uint)mia.DeadbandType, DeadbandValue = mia.DeadbandValue
                    };
                }

                var propType = propertyInfo.PropertyType;
                if (propType == typeof(DataValue))
                {
                    this.monitoredItems.Add(new DataValueMonitoredItem(
                                                target: this,
                                                property: propertyInfo,
                                                nodeId: NodeId.Parse(mia.NodeId),
                                                indexRange: mia.IndexRange,
                                                attributeId: mia.AttributeId,
                                                samplingInterval: mia.SamplingInterval,
                                                filter: filter,
                                                queueSize: mia.QueueSize,
                                                discardOldest: mia.DiscardOldest));
                    continue;
                }

                if (propType == typeof(BaseEvent) || propType.GetTypeInfo().IsSubclassOf(typeof(BaseEvent)))
                {
                    this.monitoredItems.Add(new EventMonitoredItem(
                                                target: this,
                                                property: propertyInfo,
                                                nodeId: NodeId.Parse(mia.NodeId),
                                                indexRange: mia.IndexRange,
                                                attributeId: mia.AttributeId,
                                                samplingInterval: mia.SamplingInterval,
                                                filter: new EventFilter()
                    {
                        SelectClauses = EventHelper.GetSelectClauses(propType)
                    },
                                                queueSize: mia.QueueSize,
                                                discardOldest: mia.DiscardOldest));
                    continue;
                }

                if (propType == typeof(ObservableQueue <DataValue>))
                {
                    this.monitoredItems.Add(new DataValueQueueMonitoredItem(
                                                target: this,
                                                property: propertyInfo,
                                                nodeId: NodeId.Parse(mia.NodeId),
                                                indexRange: mia.IndexRange,
                                                attributeId: mia.AttributeId,
                                                samplingInterval: mia.SamplingInterval,
                                                filter: filter,
                                                queueSize: mia.QueueSize,
                                                discardOldest: mia.DiscardOldest));
                    continue;
                }

                if (propType.IsConstructedGenericType && propType.GetGenericTypeDefinition() == typeof(ObservableQueue <>))
                {
                    var elemType = propType.GenericTypeArguments[0];
                    if (elemType == typeof(BaseEvent) || elemType.GetTypeInfo().IsSubclassOf(typeof(BaseEvent)))
                    {
                        this.monitoredItems.Add((MonitoredItemBase)Activator.CreateInstance(
                                                    typeof(EventQueueMonitoredItem <>).MakeGenericType(elemType),
                                                    this,
                                                    propertyInfo,
                                                    NodeId.Parse(mia.NodeId),
                                                    mia.AttributeId,
                                                    mia.IndexRange,
                                                    MonitoringMode.Reporting,
                                                    mia.SamplingInterval,
                                                    new EventFilter()
                        {
                            SelectClauses = EventHelper.GetSelectClauses(elemType)
                        },
                                                    mia.QueueSize,
                                                    mia.DiscardOldest));
                        continue;
                    }
                }

                this.monitoredItems.Add(new ValueMonitoredItem(
                                            target: this,
                                            property: propertyInfo,
                                            nodeId: NodeId.Parse(mia.NodeId),
                                            indexRange: mia.IndexRange,
                                            attributeId: mia.AttributeId,
                                            samplingInterval: mia.SamplingInterval,
                                            filter: filter,
                                            queueSize: mia.QueueSize,
                                            discardOldest: mia.DiscardOldest));
            }

            this.stateMachineCts  = new CancellationTokenSource();
            this.stateMachineTask = Task.Run(() => this.StateMachineAsync(this.stateMachineCts.Token));
        }
Exemplo n.º 9
0
        /// <summary>
        /// Constructs a new instance.
        /// </summary>
        public DataChangeMonitoredItem(
            MonitoredNode source,
            uint id,
            uint attributeId,
            NumericRange indexRange,
            QualifiedName dataEncoding,
            DiagnosticsMasks diagnosticsMasks,
            TimestampsToReturn timestampsToReturn,
            MonitoringMode monitoringMode,
            uint clientHandle,
            double samplingInterval,
            uint queueSize,
            bool discardOldest,
            DataChangeFilter filter,
            Range range,
            bool alwaysReportUpdates)
        {
            m_source = source;
            m_id = id;
            m_attributeId = attributeId;
            m_indexRange = indexRange;
            m_dataEncoding = dataEncoding;
            m_timestampsToReturn = timestampsToReturn;
            m_diagnosticsMasks = diagnosticsMasks;
            m_monitoringMode = monitoringMode;
            m_clientHandle = clientHandle;
            m_samplingInterval = samplingInterval;
            m_nextSampleTime = DateTime.UtcNow.Ticks;
            m_readyToPublish = false;
            m_readyToTrigger = false;
            m_queue = null;
            m_filter = filter;
            m_range = 0;
            m_alwaysReportUpdates = alwaysReportUpdates;
        
            if (range != null)
            {
                m_range = range.High  - range.Low;
            }

            if (queueSize > 1)
            {
                m_queue = new MonitoredItemQueue();
                m_queue.SetQueueSize(queueSize, discardOldest, diagnosticsMasks);
                m_queue.SetSamplingInterval(samplingInterval);
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Modifies the monitored item parameters,
        /// </summary>
        public ServiceResult Modify(
            DiagnosticsMasks diagnosticsMasks,
            TimestampsToReturn timestampsToReturn,
            uint clientHandle,
            double samplingInterval,
            uint queueSize,
            bool discardOldest,
            DataChangeFilter filter,
            Range range)
        {
            lock (m_lock)
            {
                m_diagnosticsMasks = diagnosticsMasks;
                m_timestampsToReturn = timestampsToReturn;
                m_clientHandle = clientHandle;

                // subtract the previous sampling interval.
                long oldSamplingInterval = (long)(m_samplingInterval*TimeSpan.TicksPerMillisecond);

                if (oldSamplingInterval < m_nextSampleTime)
                {
                    m_nextSampleTime -= oldSamplingInterval;
                }
                
                m_samplingInterval = samplingInterval;

                // calculate the next sampling interval.                
                long newSamplingInterval = (long)(m_samplingInterval*TimeSpan.TicksPerMillisecond);

                if (m_samplingInterval > 0)
                {
                    m_nextSampleTime += newSamplingInterval;
                }
                else
                {
                    m_nextSampleTime = 0;
                }

                // update the filter and the range.
                m_filter = filter;
                m_range = 0;

                if (range != null)
                {
                    m_range = range.High  - range.Low;
                }

                // update the queue size.
                if (queueSize > 1)
                {
                    if (m_queue == null)
                    {
                        m_queue = new MonitoredItemQueue();
                    }

                    m_queue.SetQueueSize(queueSize, discardOldest, diagnosticsMasks);
                    m_queue.SetSamplingInterval(samplingInterval);
                }
                else
                {
                    m_queue = null;
                }

                return ServiceResult.Good;
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Sets the data change filter for the monitored item.
        /// </summary>
        private void SetDataChangeFilter(MonitoredItem item, float deadband)
        {
            // construct filter.
            DataChangeFilter filter = null;

            if (deadband > 0)
            {
                filter = new DataChangeFilter();
                
                filter.DeadbandType  = (uint)DeadbandType.Percent;
                filter.DeadbandValue = deadband;
                filter.Trigger       = DataChangeTrigger.StatusValue;
            }

            item.Filter = filter;
        }
Exemplo n.º 12
0
        /// <summary>
        /// IOPCGroupStateMgt::SetState - Sets various properties of the group.
        /// </summary>
		public void SetState(
            System.IntPtr pRequestedUpdateRate, 
            out int       pRevisedUpdateRate, 
            System.IntPtr pActive, 
            System.IntPtr pTimeBias, 
            System.IntPtr pPercentDeadband, 
            System.IntPtr pLCID, 
            System.IntPtr phClientGroup)
		{
            int updateRate = 0;
            uint keepAliveCount = 0;
            float deadband = 0;
            int lcid = 0;
            int timebias = 0;
            bool updateRateChanged;

			try
			{                    
			    lock (m_lock)
			    {
				    if (m_subscription == null) throw ComUtils.CreateComException(ResultIds.E_FAIL);

					// validate update rate.
					if (pRequestedUpdateRate != IntPtr.Zero)
					{
						updateRate = Marshal.ReadInt32(pRequestedUpdateRate);

                        // throttle the publishing rate.
                        if (updateRate < 100)
                        {
                            updateRate = 100;
                        }

                        // calculate the new keep alive count based on the previous setting.
                        keepAliveCount = m_defaultKeepAliveCount;

                        if (m_keepAliveTime != 0)
                        {
                            keepAliveCount = (uint)((m_keepAliveTime/(uint)updateRate)+1);
                        }

                        // check if it is changing.
                        updateRateChanged = updateRate != m_updateRate;
                    }

					// validate deadband.
					if (pPercentDeadband != IntPtr.Zero)
					{
						float[] buffer = new float[1];
						Marshal.Copy(pPercentDeadband, buffer, 0, 1);
                        deadband = buffer[0];
                        
                        if (deadband < 0 || deadband > 100)
                        {
                            throw ComUtils.CreateComException(ResultIds.E_INVALIDARG);
                        }
                    }
                    
					// validate locale.
					if (pLCID != IntPtr.Zero)
					{
						lcid = Marshal.ReadInt32(pLCID);
                        
                        if (lcid != 0 && !m_server.IsLocaleSupported(lcid))
                        {
                            throw ComUtils.CreateComException(ResultIds.E_INVALIDARG);
                        }
					}

					// validate time bias.
					if (pTimeBias != IntPtr.Zero)
					{
						timebias = Marshal.ReadInt32(pTimeBias);
					}
                    
					// apply update rate.
					if (pRequestedUpdateRate != IntPtr.Zero)
					{
                        m_subscription.PublishingInterval = updateRate;
                        
                        // calculate the new keep alive count based on the previous setting.
                        if (keepAliveCount != 0)
                        {
                            m_subscription.KeepAliveCount = keepAliveCount;
                        }

                        // must update the individual items.
                        foreach (Item item in m_items.Values)
                        {
                            if (!item.SamplingRateSpecified)
                            {
                                item.MonitoredItem.SamplingInterval = updateRate;
                            }
                        }
					}

					// apply time bias.
					if (pTimeBias != IntPtr.Zero)
					{
						m_timebias = timebias;
					}

					// apply deadband.
					if (pPercentDeadband != IntPtr.Zero)
					{
						m_deadband = deadband;
                                                
                        DataChangeFilter filter = new DataChangeFilter();
                        
                        filter.DeadbandType  = (uint)(int)DeadbandType.Percent;
                        filter.DeadbandValue = m_deadband;
                        filter.Trigger       = DataChangeTrigger.StatusValue;

                        // must update the individual items.
                        foreach (Item item in m_items.Values)
                        {
                            if (item.DeadbandSupported)
                            {
                                if (m_deadband > 0)
                                {
                                    item.MonitoredItem.Filter = filter;
                                }
                            }
                        }
					}

					// apply locale.
					if (pLCID != IntPtr.Zero)
					{
						m_lcid = lcid;
					}

					// apply client handle.
					if (phClientGroup != IntPtr.Zero)
					{
						m_clientHandle = Marshal.ReadInt32(phClientGroup);
					}

                    // modify subscription.
                    m_subscription.Modify();

                    // apply changes to items.
                    m_subscription.ApplyChanges();
                    
                    // update keep alive time if it changed.
                    if (keepAliveCount != 0)
                    {
                        m_keepAliveTime = (int)(m_subscription.CurrentPublishingInterval*m_subscription.CurrentKeepAliveCount);
                    }
                    
                    // return the actual update rate.
					pRevisedUpdateRate = m_updateRate = (int)m_subscription.CurrentPublishingInterval;
            
                    // reset the update counter.
                    m_nextUpdate = DateTime.UtcNow.Ticks + m_updateRate*TimeSpan.TicksPerMillisecond;
                                        
                    // Utils.Trace(
                    //     "SetState: GroupHandle={0}, UpdateRate={1}, Active={2}", 
                    //     m_clientHandle,
                    //     m_updateRate,
                    //     m_active);

			    }		
                                        
			    // apply active.
			    if (pActive != IntPtr.Zero)
			    {                        
                    bool active = Marshal.ReadInt32(pActive) != 0;
                    PublishStateChanged(active, null);
			    }
			}
			catch (Exception e)
			{
                Utils.Trace(e, "Error setting group state.");
				throw ComUtils.CreateComException(e);
			}
		}
Exemplo n.º 13
0
		/// <summary>
		/// Adds the items to group.
		/// </summary>
		private void CloneItems(IEnumerable<Item> itemsToClone)
		{
			lock (m_lock)
			{
				if (m_subscription == null) throw ComUtils.CreateComException(ResultIds.E_FAIL);
  
                List<Item> itemsToAdd = new List<Item>();

                foreach (Item itemToClone in itemsToClone)
                {             
                    // create an item.
                    Item item = new Item();

                    item.ItemId                   = itemToClone.ItemId;
                    item.ClientHandle             = itemToClone.ClientHandle;
                    item.ServerHandle             = 0;
                    item.Active                   = itemToClone.Active;
                    item.ReqType                  = itemToClone.ReqType;
                    item.Variable                 = itemToClone.Variable;
                    item.SamplingRate             = itemToClone.SamplingRate;
                    item.SamplingRateSpecified    = itemToClone.SamplingRateSpecified;
                    item.DeadbandSupported        = itemToClone.DeadbandSupported;
                    item.Deadband                 = itemToClone.Deadband;
                    item.DeadbandSpecified        = itemToClone.DeadbandSpecified;
                    item.EnableBuffering          = itemToClone.EnableBuffering;

                    // create a monitored item.
                    MonitoredItem monitoredItem = new MonitoredItem();

                    monitoredItem.StartNodeId      = item.Variable.NodeId;
                    monitoredItem.AttributeId      = Attributes.Value;
                    monitoredItem.MonitoringMode   = (item.Active)?MonitoringMode.Reporting:MonitoringMode.Disabled;
                    monitoredItem.SamplingInterval = (item.SamplingRateSpecified)?item.SamplingRate:m_updateRate;
                    monitoredItem.QueueSize        = 0;
                    monitoredItem.DiscardOldest    = true;
                    monitoredItem.Encoding         = null;
                    monitoredItem.Filter           = null;
                    monitoredItem.IndexRange       = null;
                    
                    if (item.DeadbandSupported)
                    {
                        float deadband = (item.DeadbandSpecified)?item.Deadband:m_deadband;

                        DataChangeFilter filter = null;
                        
                        if (deadband > 0)
                        {
                            filter = new DataChangeFilter();
                            
                            filter.DeadbandType  = (uint)(int)DeadbandType.Percent;
                            filter.DeadbandValue = m_deadband;
                            filter.Trigger       = DataChangeTrigger.StatusValue;
                        }

                        monitoredItem.Filter = filter;
                    }

                    item.MonitoredItem = monitoredItem;
                    itemsToAdd.Add(item); 

                    // update the subscription.
                    m_subscription.AddItem(monitoredItem);
                }
                
                if (itemsToAdd.Count > 0)
                {                    
                    // create monitored items on the UA server.
                    m_subscription.ApplyChanges();

                    foreach (Item item in itemsToAdd)
                    {
                        // check for error during add.
                        int index = item.ServerHandle;
                        MonitoredItem monitoredItem = item.MonitoredItem;

                        if (ServiceResult.IsBad(monitoredItem.Status.Error))
                        {
                            m_subscription.RemoveItem(monitoredItem);
                            continue;
                        }
                        
                        // save server handle.
                        item.ServerHandle = Utils.ToInt32(monitoredItem.ClientHandle);

                        // add an entry in the cache.
                        CreateCacheEntry(item);

                        // index item.
                        m_items[item.ServerHandle] = item;
                    }
                }          
			}
		}
Exemplo n.º 14
0
        /// <summary>
        /// IOPCItemMgt::AddItems - Adds one or more items to a group.
        /// </summary>
		public void AddItems(
            int dwCount, 
            OPCITEMDEF[] pItemArray, 
            out System.IntPtr ppAddResults, 
            out System.IntPtr ppErrors)
		{
			lock (m_lock)
			{
                if (m_subscription == null) throw ComUtils.CreateComException(ResultIds.E_FAIL);

                // validate arguments.
                if (dwCount == 0 || pItemArray == null || dwCount != pItemArray.Length)
                {
                    throw ComUtils.CreateComException(ResultIds.E_INVALIDARG);
                }

                try
                {
                    // compile set of item modifications.
                    int[] errors = new int[dwCount];
                    OPCITEMRESULT[] results = new OPCITEMRESULT[dwCount];

                    List<Item> itemsToAdd = new List<Item>();

                    for (int ii = 0; ii < dwCount; ii++)
                    {
                        OPCITEMDEF itemToAdd = pItemArray[ii];
                           
                        // initialize result structure.
                        results[ii].hServer             = 0;
                        results[ii].dwBlobSize          = 0;
                        results[ii].pBlob               = IntPtr.Zero;
                        results[ii].vtCanonicalDataType = (short)VarEnum.VT_EMPTY;
                        results[ii].dwAccessRights      = 0;
                        results[ii].wReserved           = 0;

                        // parse node id.
                        NodeId nodeId = Server.ItemIdToNodeId(itemToAdd.szItemID);

                        if (nodeId == null)
                        {
                            errors[ii] = ResultIds.E_INVALIDITEMID;
                            continue;
                        }

                        // find node.
                        VariableNode variable = m_session.NodeCache.Find(nodeId) as VariableNode;
                        
                        if (variable == null)
                        {
                            errors[ii] = ResultIds.E_INVALIDITEMID;
                            continue;
                        }

                        // validated the requested datatype.
                        if (itemToAdd.vtRequestedDataType != 0)
                        {
                            if (ComUtils.GetSystemType(itemToAdd.vtRequestedDataType) == null)
                            {
                                errors[ii] = ResultIds.E_BADTYPE;
                                continue;
                            }
                        }
                                                
                        // fill in metadata.
                        results[ii].vtCanonicalDataType = (short)m_server.DataTypeToVarType(variable.DataType, variable.ValueRank);
                        results[ii].dwAccessRights      = ComUtils.GetAccessRights(variable.AccessLevel);

                        if (results[ii].vtCanonicalDataType == (short)VarEnum.VT_VARIANT)
                        {
                            results[ii].vtCanonicalDataType = (short)VarEnum.VT_EMPTY;
                        }

                        // create an item.
                        Item item = new Item();

                        item.ItemId       = itemToAdd.szItemID;
                        item.ClientHandle = itemToAdd.hClient;
                        item.ServerHandle = ii; // save this temporarily to correlate response to request list.
                        item.Active       = itemToAdd.bActive != 0;
                        item.ReqType      = (VarEnum)itemToAdd.vtRequestedDataType;
                        item.Variable     = variable;

                        // check if the item supports deadband.
                        INode euRange = m_session.NodeCache.Find(nodeId, ReferenceTypeIds.HasProperty, false, true, Opc.Ua.BrowseNames.EURange);

                        if (euRange != null)
                        {
                            item.DeadbandSupported = true;
                        }

                        // create a monitored item.
                        MonitoredItem monitoredItem = new MonitoredItem();

                        monitoredItem.StartNodeId      = nodeId;
                        monitoredItem.AttributeId      = Attributes.Value;
                        monitoredItem.MonitoringMode   = (item.Active)?MonitoringMode.Reporting:MonitoringMode.Disabled;
                        monitoredItem.SamplingInterval = m_updateRate;
                        monitoredItem.QueueSize        = 0;
                        monitoredItem.DiscardOldest    = true;
                        monitoredItem.Encoding         = null;
                        monitoredItem.Filter           = null;
                        monitoredItem.IndexRange       = null;
                        
                        if (m_deadband != 0 && item.DeadbandSupported)
                        {
                            DataChangeFilter filter = new DataChangeFilter();
                            
                            filter.DeadbandType  = (uint)(int)DeadbandType.Percent;
                            filter.DeadbandValue = m_deadband;
                            filter.Trigger       = DataChangeTrigger.StatusValue;

                            monitoredItem.Filter = filter;
                        }

                        item.MonitoredItem = monitoredItem;
                        itemsToAdd.Add(item); 

                        // update the subscription.
                        m_subscription.AddItem(monitoredItem);
                    }
                    
                    if (itemsToAdd.Count > 0)
                    {                    
                        // create monitored items on the UA server.
                        m_subscription.ApplyChanges();

                        foreach (Item item in itemsToAdd)
                        {
                            // check for error during add.
                            int index = item.ServerHandle;
                            MonitoredItem monitoredItem = item.MonitoredItem;

                            if (ServiceResult.IsBad(monitoredItem.Status.Error))
                            {
                                errors[index] = Server.MapReadStatusToErrorCode(monitoredItem.Status.Error.StatusCode);
                                m_subscription.RemoveItem(monitoredItem);
                                continue;
                            }

                            // save server handle.
                            results[index].hServer = item.ServerHandle = Utils.ToInt32(monitoredItem.ClientHandle);

                            // add an entry in the cache.
                            CreateCacheEntry(item);
                            
                            // index item.
                            m_items[item.ServerHandle] = item;
                        }
                    }
                        
                    // marshal the results.
                    ppAddResults = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(OPCITEMRESULT))*dwCount);
                    IntPtr pos = ppAddResults;
                                        
                    for (int ii = 0; ii < dwCount; ii++)
                    {
                        Marshal.StructureToPtr(results[ii], pos, false);
                        pos = (IntPtr)(pos.ToInt32() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMRESULT)));
                    }
                    
                    // marshal error codes.
                    ppErrors = ComUtils.GetInt32s(errors);
                }
                catch (Exception e)
                {
                    throw ComUtils.CreateComException(e);
                }
            }
		}
        /// <summary>
        /// Initializes a new instance of the <see cref="MonitoredItemCollection"/> class.
        /// Attributes found in the given subscription are added to the collection.
        /// </summary>
        /// <param name="subscription">the instance that will be inspected for [MonitoredItem] attributes.</param>
        public MonitoredItemCollection(ISubscription subscription)
        {
            var typeInfo = subscription.GetType().GetTypeInfo();

            foreach (var propertyInfo in typeInfo.DeclaredProperties)
            {
                var itemAttribute = propertyInfo.GetCustomAttribute <MonitoredItemAttribute>();
                if (itemAttribute == null || string.IsNullOrEmpty(itemAttribute.NodeId))
                {
                    continue;
                }

                MonitoringFilter filter = null;
                if (itemAttribute.AttributeId == AttributeIds.Value && (itemAttribute.DataChangeTrigger != DataChangeTrigger.StatusValue || itemAttribute.DeadbandType != DeadbandType.None))
                {
                    filter = new DataChangeFilter()
                    {
                        Trigger = itemAttribute.DataChangeTrigger, DeadbandType = (uint)itemAttribute.DeadbandType, DeadbandValue = itemAttribute.DeadbandValue
                    };
                }

                var propType = propertyInfo.PropertyType;
                if (propType == typeof(DataValue))
                {
                    this.Add(new DataValueMonitoredItem(
                                 target: subscription,
                                 property: propertyInfo,
                                 nodeId: NodeId.Parse(itemAttribute.NodeId),
                                 indexRange: itemAttribute.IndexRange,
                                 attributeId: itemAttribute.AttributeId,
                                 samplingInterval: itemAttribute.SamplingInterval,
                                 filter: filter,
                                 queueSize: itemAttribute.QueueSize,
                                 discardOldest: itemAttribute.DiscardOldest));
                    continue;
                }

                if (propType == typeof(ObservableQueue <DataValue>))
                {
                    this.Add(new DataValueQueueMonitoredItem(
                                 target: subscription,
                                 property: propertyInfo,
                                 nodeId: NodeId.Parse(itemAttribute.NodeId),
                                 indexRange: itemAttribute.IndexRange,
                                 attributeId: itemAttribute.AttributeId,
                                 samplingInterval: itemAttribute.SamplingInterval,
                                 filter: filter,
                                 queueSize: itemAttribute.QueueSize,
                                 discardOldest: itemAttribute.DiscardOldest));
                    continue;
                }

                if (propType == typeof(BaseEvent) || propType.GetTypeInfo().IsSubclassOf(typeof(BaseEvent)))
                {
                    this.Add(new EventMonitoredItem(
                                 target: subscription,
                                 property: propertyInfo,
                                 nodeId: NodeId.Parse(itemAttribute.NodeId),
                                 indexRange: itemAttribute.IndexRange,
                                 attributeId: itemAttribute.AttributeId,
                                 samplingInterval: itemAttribute.SamplingInterval,
                                 filter: new EventFilter()
                    {
                        SelectClauses = EventHelper.GetSelectClauses(propType)
                    },
                                 queueSize: itemAttribute.QueueSize,
                                 discardOldest: itemAttribute.DiscardOldest));
                    continue;
                }

                if (propType.IsConstructedGenericType && propType.GetGenericTypeDefinition() == typeof(ObservableQueue <>))
                {
                    var elemType = propType.GenericTypeArguments[0];
                    if (elemType == typeof(BaseEvent) || elemType.GetTypeInfo().IsSubclassOf(typeof(BaseEvent)))
                    {
                        this.Add((MonitoredItemBase)Activator.CreateInstance(
                                     typeof(EventQueueMonitoredItem <>).MakeGenericType(elemType),
                                     subscription,
                                     propertyInfo,
                                     NodeId.Parse(itemAttribute.NodeId),
                                     itemAttribute.AttributeId,
                                     itemAttribute.IndexRange,
                                     MonitoringMode.Reporting,
                                     itemAttribute.SamplingInterval,
                                     new EventFilter()
                        {
                            SelectClauses = EventHelper.GetSelectClauses(elemType)
                        },
                                     itemAttribute.QueueSize,
                                     itemAttribute.DiscardOldest));
                        continue;
                    }
                }

                this.Add(new ValueMonitoredItem(
                             target: subscription,
                             property: propertyInfo,
                             nodeId: NodeId.Parse(itemAttribute.NodeId),
                             indexRange: itemAttribute.IndexRange,
                             attributeId: itemAttribute.AttributeId,
                             samplingInterval: itemAttribute.SamplingInterval,
                             filter: filter,
                             queueSize: itemAttribute.QueueSize,
                             discardOldest: itemAttribute.DiscardOldest));
            }
        }
        /// <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);
        }
Exemplo n.º 17
0
        /// <summary>
        /// Modifies the monitored item parameters,
        /// </summary>
        public ServiceResult Modify(
            DiagnosticsMasks diagnosticsMasks,
            TimestampsToReturn timestampsToReturn,
            uint clientHandle,
            double samplingInterval,
            uint queueSize,
            bool discardOldest,
            DataChangeFilter filter,
            Range range)
        {
            lock (m_lock)
            {
                m_diagnosticsMasks   = diagnosticsMasks;
                m_timestampsToReturn = timestampsToReturn;
                m_clientHandle       = clientHandle;

                // subtract the previous sampling interval.
                long oldSamplingInterval = (long)(m_samplingInterval * TimeSpan.TicksPerMillisecond);

                if (oldSamplingInterval < m_nextSampleTime)
                {
                    m_nextSampleTime -= oldSamplingInterval;
                }

                m_samplingInterval = samplingInterval;

                // calculate the next sampling interval.
                long newSamplingInterval = (long)(m_samplingInterval * TimeSpan.TicksPerMillisecond);

                if (m_samplingInterval > 0)
                {
                    m_nextSampleTime += newSamplingInterval;
                }
                else
                {
                    m_nextSampleTime = 0;
                }

                // update the filter and the range.
                m_filter = filter;
                m_range  = 0;

                if (range != null)
                {
                    m_range = range.High - range.Low;
                }

                // update the queue size.
                if (queueSize > 1)
                {
                    if (m_queue == null)
                    {
                        m_queue = new MonitoredItemQueue();
                    }

                    m_queue.SetQueueSize(queueSize, discardOldest, diagnosticsMasks);
                    m_queue.SetSamplingInterval(samplingInterval);
                }
                else
                {
                    m_queue = null;
                }

                return(ServiceResult.Good);
            }
        }
Exemplo n.º 18
0
        public MonitoredItemView CreateMonitoredItem(uint subscriptionId, ushort namespaceIndex, string identifierNode, int samplingInterval, bool discardOldest, uint queueSize, int monitoringMode, int filterTrigger, uint deadbandType, double deadbandValue)
        {
            Subscription sub = GetSubscription(subscriptionId);
            NodeId       node;
            //Initialize Filter Parameters
            DataChangeTrigger _trigger;
            string            filterTriggerView;

            switch (filterTrigger)
            {
            case 0:
                _trigger          = DataChangeTrigger.Status;
                filterTriggerView = "Status";
                break;

            case 1:
                _trigger          = DataChangeTrigger.StatusValue;
                filterTriggerView = "StatusValue";
                break;

            case 2:
                _trigger          = DataChangeTrigger.StatusValueTimestamp;
                filterTriggerView = "StatusValueTimestamp";
                break;

            default:
                _trigger          = DataChangeTrigger.StatusValue;
                filterTriggerView = "StatusValue";
                break;
            }

            string deadbandTypeView;

            switch (deadbandType)
            {
            case 0:
                deadbandTypeView = "None";
                break;

            case 1:
                deadbandTypeView = "Absolute";
                break;

            case 2:
                deadbandTypeView = "Percent";
                break;

            default:
                deadbandTypeView = null;
                break;
            }

            DataChangeFilter filter = new DataChangeFilter()
            {
                Trigger       = _trigger,
                DeadbandType  = deadbandType,
                DeadbandValue = deadbandValue
            };

            //Initialize Monitored Item Parameters
            MonitoringMode _monitoringMode;

            switch (monitoringMode)
            {
            case 0:
                _monitoringMode = MonitoringMode.Disabled;
                break;

            case 1:
                _monitoringMode = MonitoringMode.Sampling;
                break;

            case 2:
                _monitoringMode = MonitoringMode.Reporting;
                break;

            default:
                _monitoringMode = MonitoringMode.Reporting;
                break;
            }

            //Set NodeId della variabile che si vuole leggere con gestione dell'identifier sia string che integer
            node = new NodeId(identifierNode, namespaceIndex);
            try
            {
                session.ReadNode(node);
            }
            catch (ServiceResultException)
            { throw new NoNodeToReadException("Node not found!"); }

            MonitoredItem monitoredItem = new MonitoredItem(clientHandle)
            {
                AttributeId      = Attributes.Value,
                DiscardOldest    = discardOldest,
                Filter           = filter,
                MonitoringMode   = _monitoringMode,
                NodeClass        = NodeClass.Variable,
                QueueSize        = queueSize,
                SamplingInterval = samplingInterval,
                StartNodeId      = node
            };

            clientHandle++; //Identifier di un singolo monitored item --> univoco solo all'interno della subscription

            monitoredItem.Notification += new MonitoredItemNotificationEventHandler(OnNotificationItem);

            //Aggiunge l'item tra i monitored items della subscription senza crearlo

            sub.AddItem(monitoredItem);

            //Se aggiungiamo altri monitoredItem la funzione successiva li creerà tutti

            //Comunica con il server e crea effettivamente il monitoredItem
            IList <MonitoredItem> createdMonitoredItems = sub.CreateItems();

            sub.ApplyChanges();
            //Questa funzione ritorna la lista dei monitoredItems creati al momento della chiamata

            return(new MonitoredItemView(monitoredItem.ClientHandle, monitoredItem.ResolvedNodeId.NamespaceIndex, monitoredItem.ResolvedNodeId.Identifier.ToString(), subscriptionId, monitoredItem.SamplingInterval, filterTriggerView, deadbandTypeView, deadbandValue));
        }
        /// <summary>
        /// Validates a data change filter provided by the client.
        /// </summary>
        /// <param name="context">The system context.</param>
        /// <param name="source">The node being monitored.</param>
        /// <param name="attributeId">The attribute being monitored.</param>
        /// <param name="requestedFilter">The requested monitoring filter.</param>
        /// <param name="filter">The validated data change filter.</param>
        /// <param name="range">The EU range associated with the value if required by the filter.</param>
        /// <returns>Any error condition. Good if no errors occurred.</returns>
        protected ServiceResult ValidateDataChangeFilter(
            ISystemContext context,
            NodeState source,
            uint attributeId,
            ExtensionObject requestedFilter,
            out DataChangeFilter filter,
            out Range range)
        {
            filter = null;
            range = null;

            // check for valid filter type.
            filter = requestedFilter.Body as DataChangeFilter;

            if (filter == null)
            {
                return StatusCodes.BadMonitoredItemFilterUnsupported;
            }

            // only supported for value attributes.
            if (attributeId != Attributes.Value)
            {
                return StatusCodes.BadMonitoredItemFilterUnsupported;
            }

            // only supported for variables.
            BaseVariableState variable = source as BaseVariableState;
            
            if (variable == null)
            {
                return StatusCodes.BadMonitoredItemFilterUnsupported;
            }

            // check the datatype.
            BuiltInType builtInType = TypeInfo.GetBuiltInType(variable.DataType, Server.TypeTree);

            if (!TypeInfo.IsNumericType(builtInType))
            {
                return StatusCodes.BadMonitoredItemFilterUnsupported;
            }
            
            // validate filter.
            ServiceResult error = filter.Validate();

            if (ServiceResult.IsBad(error))
            {
                return error;
            }

            if (filter.DeadbandType ==(uint)DeadbandType.Percent)
            {
                BaseVariableState euRange = variable.FindChild(context, BrowseNames.EURange) as BaseVariableState;

                if (euRange == null)
                {
                    return StatusCodes.BadMonitoredItemFilterUnsupported;
                }

                range = euRange.Value as Range;
                
                if (range == null)
                {
                    return StatusCodes.BadMonitoredItemFilterUnsupported;
                }
            }

            // all good.
            return ServiceResult.Good;
        }
Exemplo n.º 20
0
        /// <summary>
        /// Reads an verifies all of the nodes.
        /// </summary>
        private bool DoDeadbandTest(bool modifyDeadband)
        {
            // follow tree from each starting node.
            bool success = true;
                                 
            // collection writeable variables that don't change during the test.
            lock (m_variables)
            {
                m_lastWriteTime = DateTime.MinValue;
                m_writeDelayed = false;
                m_writeTimerCounter++;
                m_variables.Clear();

                // collection writeable variables that don't change during the test.
                for (int ii = 0; ii < WriteableVariables.Count; ii++)
                {
                    AddVariableToTest(WriteableVariables[ii], m_variables, true);
                }

                // reduce list based on coverage.
                List<TestVariable> variables = new List<TestVariable>();

                int counter = 0;

                foreach (TestVariable variable in m_variables)
                {
                    if (!CheckCoverage(ref counter))
                    {
                        continue;
                    }

                    variables.Add(variable);
                }

                // check if there is anything to work with.
                if (variables.Count == 0)
                {
                    Log("WARNING: No writeable variables found.");
                    Log(WriteTest.g_WriteableVariableHelpText);
                    return true;
                }

                m_variables.Clear();
                m_variables.AddRange(variables);

                ReadEURanges(m_variables);
                
                InitialWrite();

                // check if there is anything to work with.
                if (m_variables.Count == 0)
                {
                    Log("WARNING: No writeable variables found.");
                    Log(WriteTest.g_WriteableVariableHelpText);
                    return true;
                }

                Log("Starting DeadbandTest for {0} Variables ({1}% Coverage, Start={2})", m_variables.Count, Configuration.Coverage, m_variables[0].Variable);

                m_stopped = 0;
                m_writeInterval = 1000;
                m_deadbandCounter = 0;
                m_useDeadbandValues = true;

                m_errorEvent.Reset();
            }
           
            Subscription subscription = new Subscription();

            subscription.PublishingInterval = 1000;
            subscription.PublishingEnabled = true;
            subscription.Priority = 0;
            subscription.KeepAliveCount = 100;
            subscription.LifetimeCount = 100;
            subscription.MaxNotificationsPerPublish = 100;
            
            Session.AddSubscription(subscription);    
            subscription.Create();

            m_publishingTime = subscription.CurrentPublishingInterval;

            m_writerTimer = new Timer(DoWrite, m_writeTimerCounter, 0, m_writeInterval);
        
            if (m_errorEvent.WaitOne(1000, false))
            {
                success = false;
            }
            
            DataChangeFilter[] filters = new DataChangeFilter[5];

            if (success)
            {                    
                DataChangeFilter filter = new DataChangeFilter();
                filter.DeadbandType = (uint)DeadbandType.Absolute;
                filter.DeadbandValue = 2;
                filter.Trigger = DataChangeTrigger.StatusValue;
                filters[0] = filter;

                filter = new DataChangeFilter();
                filter.DeadbandType = (uint)DeadbandType.Absolute;
                filter.DeadbandValue = 5;
                filter.Trigger = DataChangeTrigger.StatusValue;
                filters[1] = filter;

                filter = new DataChangeFilter();
                filter.DeadbandType  = (uint)DeadbandType.Absolute;
                filter.DeadbandValue = 10;
                filter.Trigger = DataChangeTrigger.StatusValue;
                filters[2] = filter;

                filter = new DataChangeFilter();
                filter.DeadbandType  = (uint)DeadbandType.Percent;
                filter.DeadbandValue = 1;
                filter.Trigger = DataChangeTrigger.StatusValue;
                filters[3] = filter;

                filter = new DataChangeFilter();
                filter.DeadbandType = (uint)DeadbandType.Percent;
                filter.DeadbandValue = 10;
                filter.Trigger = DataChangeTrigger.StatusValue;
                filters[4] = filter;

                lock (m_variables)
                {
                    m_monitoredItems = new Dictionary<uint,TestVariable>();

                    for (int ii = 0; ii < m_variables.Count; ii++)
                    {
                        VariableNode variable = m_variables[ii].Variable;

                        for (int jj = 0; jj < filters.Length; jj++)
                        {
                            if (m_variables[ii].EURange == null && filters[jj].DeadbandType == (uint)DeadbandType.Percent)
                            {
                                continue;
                            }

                            MonitoredItem monitoredItem = new MonitoredItem();

                            monitoredItem.StartNodeId = variable.NodeId;
                            monitoredItem.AttributeId = Attributes.Value;
                            monitoredItem.RelativePath = null;
                            monitoredItem.IndexRange = null;
                            monitoredItem.SamplingInterval = 100;
                            monitoredItem.QueueSize = 0;
                            monitoredItem.DiscardOldest = true;
                            monitoredItem.Filter = filters[jj];
                            monitoredItem.MonitoringMode = MonitoringMode.Reporting;
                            monitoredItem.Handle = m_variables[ii];

                            m_variables[ii].Notifications[monitoredItem.ClientHandle] = new List<Notification>();
                            m_monitoredItems[monitoredItem.ClientHandle] = m_variables[ii];

                            subscription.AddItem(monitoredItem);
                        }
                    }
                }

                subscription.ApplyChanges();
                
                // check results.
                foreach (MonitoredItem monitoredItem in subscription.MonitoredItems)
                {
                    if (!CheckDeadbandError(monitoredItem))
                    {
                        success = false;
                        break;
                    }
                }
            }
            
            // modify sampling interval.
            if (success)
            {       
                if (modifyDeadband)
                {
                    if (!ModifyDeadband(subscription))
                    {
                        success = false;
                    }
                }
            }

            // wait for first data change.
            if (m_errorEvent.WaitOne(1000, false))
            {
                success = false;
            }

            lock (m_variables)
            {
                m_writeCount = 0;
                m_startTime = DateTime.UtcNow;
            }
            
            if (success)
            {
                double increment = MaxProgress/10;
                double position  = 0;

                for (int ii = 0; ii < 20; ii++)
                {               
                    if (m_errorEvent.WaitOne(1000, false))
                    {
                        success = false;
                        break;
                    }

                    position += increment;
                    ReportProgress(position);
                }   
            }
            
            int writeCount = 0;

            lock (m_variables)
            {
                m_stopped = 1;
                m_endTime = DateTime.UtcNow;
                writeCount = m_writeCount;
                m_writerTimer.Dispose();
                m_writerTimer = null;
            }

            Session.RemoveSubscription(subscription);

            // wait for last data change.
            if (m_errorEvent.WaitOne(1000, false))
            {
                success = false;
            }
            
            if (success)
            {
                double duration = CalculateInterval(m_startTime, m_endTime);                
                double expectedWrites = Math.Truncate(duration/m_writeInterval);

                if (Math.Abs(expectedWrites - writeCount) > 1)
                {
                    Log(
                        "WARNING: unexpected number of writes for monitored items: Expected={0}, Actual={1}",
                        expectedWrites,
                        writeCount);
                }

                lock (m_variables)
                {
                    int errorCount = 0;

                    foreach (MonitoredItem monitoredItem in subscription.MonitoredItems)
                    {
                        if (ServiceResult.IsBad(monitoredItem.Status.Error))
                        {
                            continue;
                        }

                        DataChangeFilter filter = monitoredItem.Status.Filter as DataChangeFilter;
                      
                        if (filter == null)
                        {
                            continue;
                        }

                        if (errorCount > 10)
                        {
                            break;
                        }
                        
                        TestVariable variable = (TestVariable)monitoredItem.Handle;
                                                
                        double writesPerPublish = m_publishingTime/m_writeInterval;
                        double totalPublishes = duration/m_publishingTime;

                        Range euRange = variable.EURange;
                        
                        if (euRange != null)
                        {
                            if (euRange.High - euRange.Low <= 0)
                            {
                                Log(
                                    "Invalid EU range for variable {0}. NodeId={1}, EURange={2}, EURange={3}",
                                    variable.Variable,
                                    variable.Variable.NodeId,
                                    variable.EURangeNode.NodeId,
                                    euRange);

                                success = false;
                                errorCount++;
                                continue;
                            }
                        }

                        IList<Notification> notifications = variable.Notifications[monitoredItem.ClientHandle];

                        for (int ii = 0; ii < notifications.Count-1; ii++)
                        {
                            Notification before = notifications[ii];
                            Notification after = notifications[ii+1];

                            decimal difference = CalculateDifference(before.Value.Value, after.Value.Value);

                            if (filter.DeadbandType == (uint)DeadbandType.Absolute)
                            {
                                if (difference < (decimal)filter.DeadbandValue)
                                {
                                    Log(
                                        "Values did not exceed deadband {0}. NodeId={1}, DeadbandType={2}, Deadband={3}, Before={4}, After={5}",
                                        variable.Variable,
                                        variable.Variable.NodeId,
                                        (DeadbandType)filter.DeadbandType,
                                        filter.DeadbandValue,
                                        before.Value.WrappedValue,
                                        after.Value.WrappedValue);

                                    success = false;
                                    errorCount++;
                                    continue;
                                }
                            }

                            if (filter.DeadbandType == (uint)DeadbandType.Percent)
                            {
                                double range = euRange.High - euRange.Low;

                                if (((double)difference)/range < filter.DeadbandValue/range)
                                {
                                    Log(
                                        "Values did not exceed deadband {0}. NodeId={1}, DeadbandType={2}, Deadband={3}, Before={4}, After={5}, EURange={6}",
                                        variable.Variable,
                                        variable.Variable.NodeId,
                                        (DeadbandType)filter.DeadbandType,
                                        filter.DeadbandValue,
                                        before.Value.WrappedValue,
                                        after.Value.WrappedValue,
                                        euRange);

                                    success = false;
                                    errorCount++;
                                    continue;
                                }
                            }
                        }
                    }
                }
            }

            lock (m_variables)
            {
                Log("Completed DeadbandTest for {0} Nodes", m_variables.Count);
            }

            return success;
        }
        /// <summary>
        /// Applies the filter to value to determine if the new value should be kept.
        /// </summary>
        public static bool ValueChanged(
            DataValue value,
            ServiceResult error,
            DataValue lastValue,
            ServiceResult lastError, 
            DataChangeFilter filter,
            double range)
        {
            if (value == null) throw new ArgumentNullException("value");

            // select default data change filters.
            double deadband = 0.0;
            DeadbandType deadbandType = DeadbandType.None;
            DataChangeTrigger trigger = DataChangeTrigger.StatusValue;

            // apply filter.
            if (filter != null)
            {
                trigger = filter.Trigger;
                deadbandType = (DeadbandType)(int)filter.DeadbandType;
                deadband = filter.DeadbandValue;

                // when deadband is used and the trigger is StatusValueTimestamp, then it should behave as if trigger is StatusValue.
                if ((deadbandType != DeadbandType.None) && (trigger == DataChangeTrigger.StatusValueTimestamp))
                {
                    trigger = DataChangeTrigger.StatusValue;
                }
            }
            
            // get the current status.
            uint status = StatusCodes.Good;
            
            if (error != null)
            {
                status = error.StatusCode.Code;
            }
            else if (lastValue != null)
            {
                status = value.StatusCode.Code;
            }

            // get the last status.
            uint lastStatus = StatusCodes.Good;

            if (lastError != null)
            {
                lastStatus = lastError.StatusCode.Code;
            }
            else if (lastValue != null)
            {
                lastStatus = lastValue.StatusCode.Code;
            }

            // value changed if any status change occurrs.
            if (status != lastStatus)
            {
                return true;
            }

            // value changed if only one is null.
            if (value == null || lastValue == null)
            {
                return lastValue != null || value != null;
            }

            // check if timestamp has changed.
            if (trigger == DataChangeTrigger.StatusValueTimestamp)
            {
                if (lastValue.SourceTimestamp != value.SourceTimestamp)
                {
                    return true;
                }
            }

            // check if value changes are ignored.
            if (trigger == DataChangeTrigger.Status)
            {
                return false;
            }

            // check if reference to same object.
            if (!Equals(lastValue.Value, value.Value, deadbandType, deadband, range))
            {
                return true;
            }

            // must be equal.
            return false;
        }
Exemplo n.º 22
0
        public virtual bool MonitorTag(Subscription subscription, out string error, bool bApplySubscription = true, bool bReadInitialValue = true)
        {
            error = null;
            if (subscription == null || subscription.Session == null)
            {
                error = "Error: No OPC session.";
                return(false);
            }

            lock (subscription.MonitoredItems)
            {
                if (MyMonitoredItem != null && !subscription.MonitoredItems.Contains(MyMonitoredItem))
                {
                    // Monitored item was removed: recreate from scratch. Otherwise modify in place
                    MyMonitoredItem = null;
                }


                if (!this.IsSubscribedAsThing && !this.IsSubscribedAsProperty)
                {
                    // Nothing to be monitored
                    error = "Error: Nothing to be monitored";
                    return(false);
                }

                if (TheThing.GetSafePropertyBool(MyBaseThing, "DontMonitor") || SampleRate < -1)
                {
                    return(false);
                }
                // can only subscribe to local variables.
                //if (TagRef == null || TagRef.NodeId.IsAbsolute || TagRef.NodeClass != NodeClass.Variable)
                var resolvedNodeId = GetResolvedNodeIdName();
                if (resolvedNodeId == null) // || NodeId.IsAbsolute || TagRef.NodeClass != NodeClass.Variable)
                {
                    error = "Error: No or invalid NodeId";
                    return(false);
                }


                var previousMonitoredItem = subscription.MonitoredItems.FirstOrDefault(mi => mi.Handle == this || this.RefersToSamePropertyAndTag(mi.Handle));
                if (previousMonitoredItem != null)
                {
                    if (!previousMonitoredItem.StartNodeId.Equals(resolvedNodeId))
                    {
                        TheBaseAssets.MySYSLOG.WriteToLog(78201, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("OPC", $"[{MyOPCServer.GetLogAddress()}] Internal Error - monitored item {previousMonitoredItem.StartNodeId} replaced with {resolvedNodeId}. Change will not take effect!", eMsgLevel.l4_Message));
                    }
                    MyMonitoredItem = previousMonitoredItem;
                }
                else
                {
                    MyMonitoredItem = new MonitoredItem(subscription.DefaultItem);
                }
                //MyMonitoredItem.StartNodeId = (NodeId)TagRef.NodeId;
                MyMonitoredItem.StartNodeId    = resolvedNodeId;
                MyMonitoredItem.AttributeId    = Attributes.Value;
                MyMonitoredItem.DisplayName    = DisplayName; // Utils.Format("{0}", TagRef);
                MyMonitoredItem.MonitoringMode = MonitoringMode.Reporting;
                if ((!this.HistoryStartTime.HasValue || this.HistoryStartTime.Value == DateTimeOffset.MinValue) && MyOPCServer.DefHistoryStartTime != DateTimeOffset.MinValue)
                {
                    this.HistoryStartTime = MyOPCServer.DefHistoryStartTime;
                }

                if (this.HistoryStartTime.HasValue && this.HistoryStartTime.Value != DateTimeOffset.MinValue)
                {
                    MyMonitoredItem.Filter = new AggregateFilter()
                    {
                        StartTime          = this.HistoryStartTime.Value.UtcDateTime,
                        ProcessingInterval = this.SampleRate,
                        AggregateType      = ObjectIds.AggregateFunction_Interpolative,
                    };
                    MyMonitoredItem.QueueSize        = uint.MaxValue;
                    MyMonitoredItem.SamplingInterval = 0;
                }
                else
                {
                    DataChangeFilter filter = null;
                    // TODO Remove this special case: pass parameters for deadband filters and StatusValueTimestamp (this breaks P08!!!)
                    if (this.DeadbandFilterValue != 0)
                    {
                        filter = new DataChangeFilter
                        {
                            DeadbandType  = (uint)(this.DeadbandFilterValue > 0 ? DeadbandType.Absolute : DeadbandType.Percent),
                            DeadbandValue = Math.Abs(this.DeadbandFilterValue)
                        };
                    }

                    if (ChangeTrigger != 1)
                    {
                        if (filter == null)
                        {
                            filter = new DataChangeFilter();
                        }
                        filter.Trigger = (DataChangeTrigger)ChangeTrigger;
                    }

                    if (filter != null)
                    {
                        MyMonitoredItem.Filter = filter;
                    }
                    MyMonitoredItem.SamplingInterval = SampleRate;

                    // For Events, the sample rate should be 0 (per spec), but is really ignored and thus should not affect the aggregate sample rate for the server
                    // All other sample rates are at least 50ms per other checks

                    if (SampleRate <= subscription.PublishingInterval * 2 && SampleRate > 0)
                    {
                        // 3.220: PublishingInterval is now independent of the sample rate: it only affects the frequency of the traffic from the server, not the content
                        //MyOPCServer.Subscription.PublishingInterval = SampleRate;

                        // Request the QueueSize to be 50 times the expected data points, so that no data is lost in normal operation
                        MyMonitoredItem.QueueSize = (uint)Math.Ceiling((((double)subscription.PublishingInterval) / SampleRate) * 50);
                        if (MyMonitoredItem.QueueSize < 50)
                        {
                            MyMonitoredItem.QueueSize = 50;
                        }
                    }
                    else
                    {
                        MyMonitoredItem.QueueSize = 50; // Request at least 50
                    }
                }
                MyMonitoredItem.DiscardOldest = true;

                MyMonitoredItem.Notification -= MonitoredItem_Notification;
                MyMonitoredItem.Notification += MonitoredItem_Notification;

                TheOPCMonitoredItemBase previousTag = null;
                if (previousMonitoredItem != null && previousMonitoredItem.Handle != this)
                {
                    previousTag = previousMonitoredItem.Handle as TheOPCMonitoredItemBase;
                    if (previousTag != null)
                    {
                        previousTag.ReleaseMonitoredItem();
                    }
                }

                MyMonitoredItem.Handle = this;

                InitializeMonitoredItem(previousTag);

                if (previousMonitoredItem == null)
                {
                    subscription.AddItem(MyMonitoredItem);
                }
            }
            if (bApplySubscription)
            {
#if OLD_UA
                var items = subscription.ApplyChanges();
                if (!items.Contains(MyMonitoredItem))
#else
                subscription.ApplyChanges();
                if (!subscription.MonitoredItems.Contains(MyMonitoredItem))
#endif
                {
                    TheBaseAssets.MySYSLOG.WriteToLog(78201, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("OPC", $"[{MyOPCServer.GetLogAddress()}] Internal Error: Monitored item not found after applying changes {GetNodeIdForLogs()}. Actual values: Sampling {MyMonitoredItem.Status.SamplingInterval}, Queue {MyMonitoredItem.Status.QueueSize}", eMsgLevel.l1_Error));
                    error = "Error: Monitored item not found after applying changes";
                    return(false);
                }
                else
                {
                    TheBaseAssets.MySYSLOG.WriteToLog(78201, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("OPC", $"[{MyOPCServer.GetLogAddress()}] Added monitored item {GetNodeIdForLogs()}. Actual values: Sampling {MyMonitoredItem.Status.SamplingInterval}, Queue {MyMonitoredItem.Status.QueueSize}", eMsgLevel.l4_Message));
                }
            }

            if (ServiceResult.IsBad(MyMonitoredItem.Status.Error))
            {
                TheThing.SetSafePropertyString(MyBaseThing, "LastMessage", MyMonitoredItem.Status.Error.StatusCode.ToString());
                TheBaseAssets.MySYSLOG.WriteToLog(78201, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("OPC", $"[{MyOPCServer.GetLogAddress()}] Error adding monitored item {GetNodeIdForLogs()}", eMsgLevel.l4_Message, MyMonitoredItem.Status.Error.ToString()));
                error = "Error: " + MyMonitoredItem.Status.Error.ToString();
                return(false);
            }
            else
            {
                MyOPCServer.RegisterEvent("DisconnectComplete", sinkDisconnected);
            }

            TheThing.SetSafePropertyBool(MyBaseThing, "IsActive", true);
            return(true);
        }