Пример #1
0
        /// <summary>
        /// Handler for the standard "keep alive" event sent by all OPC UA servers
        /// </summary>
        private static void StandardClient_KeepAlive(Session session, KeepAliveEventArgs e)
        {
            // Ignore if we are shutting down.
            if (PublisherShutdownInProgress == true)
            {
                return;
            }

            if (e != null && session != null && session.ConfiguredEndpoint != null)
            {
                OpcSession opcSession = null;
                try
                {
                    OpcSessionsSemaphore.Wait();


                    var opcSessions = OpcSessions.Where(s => s.Session != null);
                    opcSession = opcSessions.Where(s => s.Session.ConfiguredEndpoint.EndpointUrl.Equals(session.ConfiguredEndpoint.EndpointUrl)).FirstOrDefault();

                    if (!ServiceResult.IsGood(e.Status))
                    {
                        Trace($"Session endpoint: {session.ConfiguredEndpoint.EndpointUrl} has Status: {e.Status}");
                        Trace($"Outstanding requests: {session.OutstandingRequestCount}, Defunct requests: {session.DefunctRequestCount}");
                        Trace($"Good publish requests: {session.GoodPublishRequestCount}, KeepAlive interval: {session.KeepAliveInterval}");
                        Trace($"SessionId: {session.SessionId}");

                        if (opcSession != null && opcSession.State == SessionState.Connected)
                        {
                            opcSession.MissedKeepAlives++;
                            Trace($"Missed KeepAlives: {opcSession.MissedKeepAlives}");
                            if (opcSession.MissedKeepAlives >= OpcKeepAliveDisconnectThreshold)
                            {
                                Trace($"Hit configured missed keep alive threshold of {Program.OpcKeepAliveDisconnectThreshold}. Disconnecting the session to endpoint {session.ConfiguredEndpoint.EndpointUrl}.");
                                session.KeepAlive -= StandardClient_KeepAlive;
                                opcSession.Disconnect();
                            }
                        }
                    }
                    else
                    {
                        if (opcSession != null && opcSession.MissedKeepAlives != 0)
                        {
                            // Reset missed keep alive count
                            Trace($"Session endpoint: {session.ConfiguredEndpoint.EndpointUrl} got a keep alive after {opcSession.MissedKeepAlives} {(opcSession.MissedKeepAlives == 1 ? "was" : "were")} missed.");
                            opcSession.MissedKeepAlives = 0;
                        }
                    }
                }
                finally
                {
                    OpcSessionsSemaphore.Release();
                }
            }
            else
            {
                Trace("Keep alive arguments seems to be wrong.");
            }
        }
Пример #2
0
        /// <summary>
        /// Method to remove the node from the subscription and stop publishing telemetry to IoTHub.
        /// </summary>
        private ServiceResult OnUnpublishNodeCall(ISystemContext context, MethodState method, IList <object> inputArguments, IList <object> outputArguments)
        {
            if (inputArguments[0] == null || inputArguments[1] == null)
            {
                Trace("UnpublishNode: Invalid arguments!");
                return(ServiceResult.Create(StatusCodes.BadArgumentsMissing, "Please provide all arguments!"));
            }

            NodeId nodeId      = null;
            Uri    endpointUri = null;

            try
            {
                if (string.IsNullOrEmpty(inputArguments[0] as string) || string.IsNullOrEmpty(inputArguments[1] as string))
                {
                    Trace($"UnpublishNode: Arguments (0 (nodeId), 1 (endpointUrl)) are not valid strings!");
                    return(ServiceResult.Create(StatusCodes.BadArgumentsMissing, "Please provide all arguments as strings!"));
                }
                nodeId      = inputArguments[0] as string;
                endpointUri = new Uri(inputArguments[1] as string);
            }
            catch (UriFormatException)
            {
                Trace($"UnpublishNode: The endpointUrl is invalid '{inputArguments[1] as string}'!");
                return(ServiceResult.Create(StatusCodes.BadArgumentsMissing, "Please provide a valid OPC UA endpoint URL as second argument!"));
            }

            // find the session and stop monitoring the node.
            try
            {
                if (PublisherShutdownInProgress)
                {
                    return(ServiceResult.Create(StatusCodes.BadUnexpectedError, $"Publisher shutdown in progress."));
                }

                // find the session we need to monitor the node
                OpcSession opcSession = null;
                try
                {
                    OpcSessionsSemaphore.Wait();
                    opcSession = OpcSessions.FirstOrDefault(s => s.EndpointUri == endpointUri);
                }
                catch
                {
                    opcSession = null;
                }
                finally
                {
                    OpcSessionsSemaphore.Release();
                }
                if (opcSession == null)
                {
                    // do nothing if there is no session for this endpoint.
                    Trace($"UnpublishNode: Session for endpoint '{endpointUri.OriginalString}' not found.");
                    return(ServiceResult.Create(StatusCodes.BadSessionIdInvalid, "Session for endpoint of published node not found!"));
                }
                else
                {
                    Trace($"UnpublishNode: Session found for endpoint '{endpointUri.OriginalString}'");
                }

                // remove the node from the sessions monitored items list.
                opcSession.TagNodeForMonitoringStop(nodeId);
                Trace("UnpublishNode: Requested to stop monitoring of node.");

                // remove node from persisted config file
                try
                {
                    PublishDataSemaphore.Wait();
                    var entryToRemove = PublisherConfigFileEntries.Find(l => l.NodeId == nodeId && l.EndpointUri == endpointUri);
                    PublisherConfigFileEntries.Remove(entryToRemove);
                    File.WriteAllText(NodesToPublishAbsFilename, JsonConvert.SerializeObject(PublisherConfigFileEntries));
                }
                finally
                {
                    PublishDataSemaphore.Release();
                }
            }
            catch (Exception e)
            {
                Trace(e, $"UnpublishNode: Exception while trying to configure publishing node '{nodeId.ToString()}'");
                return(ServiceResult.Create(e, StatusCodes.BadUnexpectedError, $"Unexpected error publishing node: {e.Message}"));
            }
            return(ServiceResult.Good);
        }
Пример #3
0
        /// <summary>
        /// Method to start monitoring a node and publish the data to IoTHub.
        /// </summary>
        private ServiceResult OnPublishNodeCall(ISystemContext context, MethodState method, IList <object> inputArguments, IList <object> outputArguments)
        {
            if (inputArguments[0] == null || inputArguments[1] == null)
            {
                Trace("PublishNode: Invalid Arguments when trying to publish a node.");
                return(ServiceResult.Create(StatusCodes.BadArgumentsMissing, "Please provide all arguments!"));
            }

            NodeToPublishConfig nodeToPublish;
            NodeId nodeId      = null;
            Uri    endpointUri = null;

            try
            {
                if (string.IsNullOrEmpty(inputArguments[0] as string) || string.IsNullOrEmpty(inputArguments[1] as string))
                {
                    Trace($"PublishNode: Arguments (0 (nodeId), 1 (endpointUrl)) are not valid strings!");
                    return(ServiceResult.Create(StatusCodes.BadArgumentsMissing, "Please provide all arguments as strings!"));
                }
                nodeId        = NodeId.Parse(inputArguments[0] as string);
                endpointUri   = new Uri(inputArguments[1] as string);
                nodeToPublish = new NodeToPublishConfig(nodeId, endpointUri, OpcSamplingInterval, OpcPublishingInterval);
            }
            catch (UriFormatException)
            {
                Trace($"PublishNode: The EndpointUri has an invalid format '{inputArguments[1] as string}'!");
                return(ServiceResult.Create(StatusCodes.BadArgumentsMissing, "Please provide a valid OPC UA endpoint URL as second argument!"));
            }
            catch (Exception e)
            {
                Trace(e, $"PublishNode: The NodeId has an invalid format '{inputArguments[0] as string}'!");
                return(ServiceResult.Create(StatusCodes.BadArgumentsMissing, "Please provide a valid OPC UA NodeId in 'ns=' syntax as first argument!"));
            }

            // find/create a session to the endpoint URL and start monitoring the node.
            try
            {
                if (PublisherShutdownInProgress)
                {
                    return(ServiceResult.Create(StatusCodes.BadUnexpectedError, $"Publisher shutdown in progress."));
                }

                // find the session we need to monitor the node
                OpcSession opcSession = null;
                try
                {
                    OpcSessionsSemaphore.Wait();
                    opcSession = OpcSessions.FirstOrDefault(s => s.EndpointUri == nodeToPublish.EndpointUri);

                    // add a new session.
                    if (opcSession == null)
                    {
                        // create new session info.
                        opcSession = new OpcSession(nodeToPublish.EndpointUri, OpcSessionCreationTimeout);
                        OpcSessions.Add(opcSession);
                        Trace($"PublishNode: No matching session found for endpoint '{nodeToPublish.EndpointUri.OriginalString}'. Requested to create a new one.");
                    }
                    else
                    {
                        Trace($"PublishNode: Session found for endpoint '{nodeToPublish.EndpointUri.OriginalString}'");
                    }

                    // add the node info to the subscription with the default publishing interval
                    opcSession.AddNodeForMonitoring(OpcPublishingInterval, OpcSamplingInterval, nodeToPublish.NodeId);
                    Trace($"PublishNode: Requested to monitor item with NodeId '{nodeToPublish.NodeId.ToString()}' (PublishingInterval: {OpcPublishingInterval}, SamplingInterval: {OpcSamplingInterval})");
                }
                finally
                {
                    OpcSessionsSemaphore.Release();
                }

                // update our data
                try
                {
                    PublishDataSemaphore.Wait();
                    PublishConfig.Add(nodeToPublish);

                    // add it also to the publish file
                    var publisherConfigFileEntry = new PublisherConfigFileEntry()
                    {
                        EndpointUri = endpointUri,
                        NodeId      = nodeId
                    };
                    PublisherConfigFileEntries.Add(publisherConfigFileEntry);
                    File.WriteAllText(NodesToPublishAbsFilename, JsonConvert.SerializeObject(PublisherConfigFileEntries));
                }
                finally
                {
                    PublishDataSemaphore.Release();
                }
                return(ServiceResult.Good);
            }
            catch (Exception e)
            {
                Trace(e, $"PublishNode: Exception while trying to configure publishing node '{nodeToPublish.NodeId.ToString()}'");
                return(ServiceResult.Create(e, StatusCodes.BadUnexpectedError, $"Unexpected error publishing node: {e.Message}"));
            }
        }