/// <summary> /// Raised when a publish response arrives from the server. /// </summary> static void Session_Notification(Session session, NotificationEventArgs e) { NotificationMessage message = e.NotificationMessage; // check for keep alive. if (message.NotificationData.Count == 0) { Console.WriteLine( "===>>> Subscription KeepAlive: SubscriptionId={0} MessageId={1} Time={2:HH:mm:ss.fff}", e.Subscription.Id, message.SequenceNumber, message.PublishTime.ToLocalTime()); return; } DataChangeNotification dcn = (DataChangeNotification)ExtensionObject.ToEncodeable(message.NotificationData[0]); // Console.WriteLine("{0:mm:ss.fff} - SeqNo={1}, Items={2}", message.PublishTime, message.SequenceNumber, dcn.MonitoredItems.Count); int count = 0; // get the data changes (oldest to newest). foreach (MonitoredItemNotification datachange in message.GetDataChanges(false)) { // lookup the monitored item. MonitoredItem monitoredItem = e.Subscription.FindItemByClientHandle(datachange.ClientHandle); if (monitoredItem == null) { Console.WriteLine("MonitoredItem ClientHandle not known: {0}", datachange.ClientHandle); continue; } // this is called on another thread so we need to synchronize before accessing the node. lock (m_lock) { NodeOfInterest node = monitoredItem.Handle as NodeOfInterest; //Console.WriteLine( // "Update for {0}: {1} Status={2} Timestamp={3:HH:mm:ss.fff}", // node.DisplayName, // datachange.Value.WrappedValue, // datachange.Value.StatusCode, // datachange.Value.SourceTimestamp.ToLocalTime()); node.Value = datachange.Value; Save(datachange.ClientHandle, node.Value); count++; } } if (count > NotificationsPerPublish) { Console.WriteLine("Too many notifications in Publish: {0}/{1}", count, NotificationsPerPublish); } lock (m_publishes) { m_notifications++; if (m_lastDump.AddSeconds(1) > DateTime.UtcNow) { return; } int sampleCount = 0; int itemCount = 0; DateTime timestamp = DateTime.MinValue; while (m_publishes.Count > 0) { DataValue value1 = m_publishes.Dequeue(); if (timestamp < value1.SourceTimestamp) { if (timestamp != DateTime.MinValue) { //Console.WriteLine( // "Items = {1}, Timestamp = {0:mm:ss.fff}", // timestamp, // itemCount); } timestamp = value1.SourceTimestamp; itemCount = 0; } sampleCount++; itemCount++; } //Console.WriteLine( // "Items = {1}, Timestamp = {0:mm:ss.fff}", // timestamp, // itemCount); uint expectedSamples = 10000; // (uint)((1000.0/SamplingInterval)*ItemsToMonitor); uint expectedNotifications = 50; Console.WriteLine( "{0:mm:ss.fff}-{1:mm:ss.fff}, Messages = {2}/{3}, Samples = {4}/{5}, MissedSamples = {6}", m_lastDump, m_lastDump.AddSeconds(1), m_notifications, expectedNotifications, sampleCount, expectedSamples, (int)m_expectedSamples - (int)m_actualSamples); m_lastDump = m_lastDump.AddSeconds(1); m_lastMessage = message.SequenceNumber; m_dumpCount++; m_notifications = 0; m_actualSamples += (uint)sampleCount; m_expectedSamples += expectedSamples; if (m_dumpCount == 10) { m_actualSamples = 0; m_expectedSamples = 0; } } }
/// <summary> /// Returns the node ids for a set of relative paths. /// </summary> /// <param name="session">An open session with the server to use.</param> /// <param name="startNodeId">The starting node for the relative paths.</param> /// <param name="relativePaths">The relative paths.</param> /// <returns>A collection of local nodes.</returns> static List<NodeOfInterest> GetNodeIds( Session session, NodeId startNodeId, params string[] relativePaths) { // build the list of browse paths to follow by parsing the relative paths. BrowsePathCollection browsePaths = new BrowsePathCollection(); if (relativePaths != null) { for (int ii = 0; ii < relativePaths.Length; ii++) { BrowsePath browsePath = new BrowsePath(); // The relative paths used indexes in the namespacesUris table. These must be // converted to indexes used by the server. An error occurs if the relative path // refers to a namespaceUri that the server does not recognize. // The relative paths may refer to ReferenceType by their BrowseName. The TypeTree object // allows the parser to look up the server's NodeId for the ReferenceType. browsePath.RelativePath = RelativePath.Parse( relativePaths[ii], session.TypeTree, session.NamespaceUris, session.NamespaceUris); browsePath.StartingNode = startNodeId; browsePaths.Add(browsePath); } } // make the call to the server. BrowsePathResultCollection results; DiagnosticInfoCollection diagnosticInfos; ResponseHeader responseHeader = session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); // ensure that the server returned valid results. Session.ValidateResponse(results, browsePaths); Session.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); Console.WriteLine("Translated {0} browse paths.", relativePaths.Length); // collect the list of node ids found. List<NodeOfInterest> nodes = new List<NodeOfInterest>(); for (int ii = 0; ii < results.Count; ii++) { // check if the start node actually exists. if (StatusCode.IsBad(results[ii].StatusCode)) { ServiceResult error = new ServiceResult( results[ii].StatusCode, diagnosticInfos[ii], responseHeader.StringTable); Console.WriteLine("Path '{0}' is not valid. Error = {1}", relativePaths[ii], error); continue; } // an empty list is returned if no node was found. if (results[ii].Targets.Count == 0) { Console.WriteLine("Path '{0}' does not exist.", relativePaths[ii]); continue; } // Multiple matches are possible, however, the node that matches the type model is the // one we are interested in here. The rest can be ignored. BrowsePathTarget target = results[ii].Targets[0]; if (target.RemainingPathIndex != UInt32.MaxValue) { Console.WriteLine("Path '{0}' refers to a node in another server.", relativePaths[ii]); continue; } // The targetId is an ExpandedNodeId because it could be node in another server. // The ToNodeId function is used to convert a local NodeId stored in a ExpandedNodeId to a NodeId. NodeOfInterest node = new NodeOfInterest(); node.NodeId = ExpandedNodeId.ToNodeId(target.TargetId, session.NamespaceUris); nodes.Add(node); } Console.WriteLine("Translate found {0} local nodes.", nodes.Count); // return whatever was found. return nodes; }
/// <summary> /// Returns the node ids for a set of relative paths. /// </summary> /// <param name="session">An open session with the server to use.</param> /// <param name="startNodeId">The starting node for the relative paths.</param> /// <param name="relativePaths">The relative paths.</param> /// <returns>A collection of local nodes.</returns> static List <NodeOfInterest> GetNodeIds( Session session, NodeId startNodeId, params string[] relativePaths) { // build the list of browse paths to follow by parsing the relative paths. BrowsePathCollection browsePaths = new BrowsePathCollection(); if (relativePaths != null) { for (int ii = 0; ii < relativePaths.Length; ii++) { BrowsePath browsePath = new BrowsePath(); // The relative paths used indexes in the namespacesUris table. These must be // converted to indexes used by the server. An error occurs if the relative path // refers to a namespaceUri that the server does not recognize. // The relative paths may refer to ReferenceType by their BrowseName. The TypeTree object // allows the parser to look up the server's NodeId for the ReferenceType. browsePath.RelativePath = RelativePath.Parse( relativePaths[ii], session.TypeTree, session.NamespaceUris, session.NamespaceUris); browsePath.StartingNode = startNodeId; browsePaths.Add(browsePath); } } // make the call to the server. BrowsePathResultCollection results; DiagnosticInfoCollection diagnosticInfos; ResponseHeader responseHeader = session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); // ensure that the server returned valid results. Session.ValidateResponse(results, browsePaths); Session.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); Console.WriteLine("Translated {0} browse paths.", relativePaths.Length); // collect the list of node ids found. List <NodeOfInterest> nodes = new List <NodeOfInterest>(); for (int ii = 0; ii < results.Count; ii++) { // check if the start node actually exists. if (StatusCode.IsBad(results[ii].StatusCode)) { ServiceResult error = new ServiceResult( results[ii].StatusCode, diagnosticInfos[ii], responseHeader.StringTable); Console.WriteLine("Path '{0}' is not valid. Error = {1}", relativePaths[ii], error); continue; } // an empty list is returned if no node was found. if (results[ii].Targets.Count == 0) { Console.WriteLine("Path '{0}' does not exist.", relativePaths[ii]); continue; } // Multiple matches are possible, however, the node that matches the type model is the // one we are interested in here. The rest can be ignored. BrowsePathTarget target = results[ii].Targets[0]; if (target.RemainingPathIndex != UInt32.MaxValue) { Console.WriteLine("Path '{0}' refers to a node in another server.", relativePaths[ii]); continue; } // The targetId is an ExpandedNodeId because it could be node in another server. // The ToNodeId function is used to convert a local NodeId stored in a ExpandedNodeId to a NodeId. NodeOfInterest node = new NodeOfInterest(); node.NodeId = ExpandedNodeId.ToNodeId(target.TargetId, session.NamespaceUris); nodes.Add(node); } Console.WriteLine("Translate found {0} local nodes.", nodes.Count); // return whatever was found. return(nodes); }