Connectivity Software User's Guide and Reference
Developing Sparkplug Host Applications
Rapid Toolkit for Sparkplug > Concepts > Developing Sparkplug Host Applications
In This Topic

Introduction

Sparkplug host application is a type of component in the Sparkplug system. The host application connects to the MQTT broker, and consumes real-time Sparkplug messages sent to it from other Sparkplug components - edge nodes and their devices. It can also (optionally) send commands to edge nodes and/or devices.

Rapid Toolkit for Sparkplug takes care of maintaining the proper message sequences, and cooperation between components in the Sparkplug system.

In Rapid Toolkit for Sparkplug, to develop your own Sparkplug host applications, you make use of the consumer object.

The Consumer Object

In Rapid Toolkit for Sparkplug, the consumer object is an instance of the EasySparkplugConsumer Class. You can create one or more instances of this object, and call methods on it/them. Together, the operations you make on these objects will appear as coming from a single Sparkplug host application (you can also use Rapid Toolkit for Sparkplug to write applications that act as multiple Sparkplug host applications in a single program, but that is rarely needed).

See Sparkplug Consumer Object Operations And Notifications for information how your code can subscribe to and publish Sparkplug data using the consumer object.

Implicit Host Descriptor

The design of the consumer object is such that an identification of the MQTT broker to connect to is passed into every operation. This way, applications that connect to more then one MQTT broker can easily do some without having to create a separate consumer object based on the broker URL. The MQTT broker URL, together with other related, is stored in a host descriptor, represented by an instance of the SparkplugHostDescriptor Class.

On the other hand, with this design, writing an application that connects to just one MQTT broker is also straightforward - simply pass the same broker connection data (usually just the URL) to all method calls on the consumer object.

If, for some reason, you do not want to pass the same broker connection data (more precisely, host descriptor) to every method call, you can configure an implicit host decsriptor on the consumer object, by setting it in the ImplicitHostDescriptor Property. Method calls on the consumer object can then leave the host descriptor in the method argumenst unfilled, which means that it will have the default value of SparkplugHostDescriptor.Null (note that this is not a null reference), and the consumer object will use the implicit host descriptor instead.

The following example illustrates the use of implicit host descriptor.

.NET

// This example shows how to specify an implicit host descriptor to be automatically used for subsequent operations on the
// consumer object.
//
// In order to publish or observe messages for this example, start the SparkplugEdgeNodeConsoleDemo program first.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-ConnectivityStudio/Latest/examples.html .
// Sparkplug examples in C# on GitHub: https://github.com/OPCLabs/Examples-ConnectivityStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using OpcLabs.EasySparkplug;
using OpcLabs.EasySparkplug.OperationModel;

namespace SparkplugDocExamples.Consumer._EasySparkplugConsumer
{
    class ImplicitNodeDescriptor
    {
        public static void Main1()
        {
            // Note that the default port for the "mqtt" scheme is 1883.
            var hostDescriptor = new SparkplugHostDescriptor("mqtt://localhost");

            // Instantiate the consumer object and hook events.
            // The implicit host descriptor is specified in the constructor call, and is subsequently used for all
            // operations on this consumer object where the host descriptor is not explicitly specified.
            var consumer = new EasySparkplugConsumer(hostDescriptor);
            consumer.MetricNotification += consumer_Main1_MetricNotification;

            Console.WriteLine("Subscribing...");
            // We are subscribing to two metrics separately, without having to repeat the host descriptor. The implicit
            // host descriptor that was specified in the constructor call is used automatically.
            consumer.SubscribeEdgeNodeMetric("easyGroup", "easySparkplugDemo", "Ramp");
            consumer.SubscribeEdgeNodeMetric("easyGroup", "easySparkplugDemo", "Random");

            Console.WriteLine("Processing notifications for 20 seconds...");
            System.Threading.Thread.Sleep(20 * 1000);

            Console.WriteLine("Unsubscribing...");
            consumer.UnsubscribeAllMetrics();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);

            Console.WriteLine("Finished.");
        }


        static void consumer_Main1_MetricNotification(object sender, EasySparkplugMetricNotificationEventArgs eventArgs)
        {
            // Handle different types of notifications.
            Console.WriteLine();
            switch (eventArgs.NotificationType)
            {
                case SparkplugNotificationType.Connect:
                    Console.WriteLine($"Connected to Sparkplug host, client ID: {eventArgs.ClientId}.");
                    break;
                case SparkplugNotificationType.Disconnect:
                    Console.WriteLine("Disconnected from Sparkplug host.");
                    break;
                case SparkplugNotificationType.Data:
                    Console.WriteLine("Received data from Sparkplug host.");
                    Console.WriteLine($"Metric name: {eventArgs.MetricName}");
                    Console.WriteLine($"Value: {eventArgs.MetricData?.Value}");
                    break;
                case SparkplugNotificationType.Birth:
                    Console.WriteLine("Received birth message from Sparkplug host.");
                    Console.WriteLine($"Metric name: {eventArgs.MetricName}");
                    Console.WriteLine($"Value: {eventArgs.MetricData?.Value}");
                    break;
                case SparkplugNotificationType.Death:
                    Console.WriteLine("Received death message from Sparkplug host.");
                    Console.WriteLine($"Metric name: {eventArgs.MetricName}");
                    break;
            }
            if (!eventArgs.Succeeded)
                Console.WriteLine($"*** Failure: {eventArgs.ErrorMessageBrief}");
        }
    }
}
' This example shows how to specify an implicit host descriptor to be automatically used for subsequent operations on the
' consumer object.
'
' In order to publish or observe messages for this example, start the SparkplugEdgeNodeConsoleDemo program first.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-ConnectivityStudio/Latest/examples.html .
' Sparkplug examples in C# on GitHub: https://github.com/OPCLabs/Examples-ConnectivityStudio-CSharp .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports OpcLabs.EasySparkplug
Imports OpcLabs.EasySparkplug.OperationModel

Namespace Global.SparkplugDocExamples.Consumer._EasySparkplugConsumer
    Class ImplicitNodeDescriptor
        Public Shared Sub Main1()
            ' Note that the default port for the "mqtt" scheme is 1883.
            Dim hostDescriptor = New SparkplugHostDescriptor("mqtt://localhost")

            ' Instantiate the consumer object and hook events.
            ' The implicit host descriptor is specified in the constructor call, and is subsequently used for all
            ' operations on this consumer object where the host descriptor is not explicitly specified.
            Dim consumer = New EasySparkplugConsumer(hostDescriptor)
            AddHandler consumer.MetricNotification, AddressOf consumer_Main1_MetricNotification

            Console.WriteLine("Subscribing...")
            ' We are subscribing to two metrics separately, without having to repeat the host descriptor. The implicit
            ' host descriptor that was specified in the constructor call is used automatically.
            consumer.SubscribeEdgeNodeMetric("easyGroup", "easySparkplugDemo", "Ramp")
            consumer.SubscribeEdgeNodeMetric("easyGroup", "easySparkplugDemo", "Random")

            Console.WriteLine("Processing notifications for 20 seconds...")
            Threading.Thread.Sleep(20 * 1000)

            Console.WriteLine("Unsubscribing...")
            consumer.UnsubscribeAllMetrics()

            Console.WriteLine("Waiting for 5 seconds...")
            Threading.Thread.Sleep(5 * 1000)

            Console.WriteLine("Finished.")
        End Sub

        Private Shared Sub consumer_Main1_MetricNotification(ByVal sender As Object, ByVal eventArgs As EasySparkplugMetricNotificationEventArgs)
            ' Handle different types of notifications.
            Console.WriteLine()
            Select Case eventArgs.NotificationType
                Case SparkplugNotificationType.Connect
                    Console.WriteLine($"Connected to Sparkplug host, client ID: {eventArgs.ClientId}.")
                Case SparkplugNotificationType.Disconnect
                    Console.WriteLine("Disconnected from Sparkplug host.")
                Case SparkplugNotificationType.Data
                    Console.WriteLine("Received data from Sparkplug host.")
                    Console.WriteLine($"Metric name: {eventArgs.MetricName}")
                    Console.WriteLine($"Value: {eventArgs.MetricData?.Value}")
                Case SparkplugNotificationType.Birth
                    Console.WriteLine("Received birth message from Sparkplug host.")
                    Console.WriteLine($"Metric name: {eventArgs.MetricName}")
                    Console.WriteLine($"Value: {eventArgs.MetricData?.Value}")
                Case SparkplugNotificationType.Death
                    Console.WriteLine("Received death message from Sparkplug host.")
                    Console.WriteLine($"Metric name: {eventArgs.MetricName}")
            End Select
            If Not eventArgs.Succeeded Then
                Console.WriteLine($"*** Failure: {eventArgs.ErrorMessageBrief}")
            End If
        End Sub
    End Class
End Namespace

 

Host Application ID

In Sparkplug, host application are required to report their online and offline status in the MQTT topics structure. For this purpose, each Sparkplug host application must a unique host application ID, so that its status can be distinguished from the others in the MQTT topic structure. The status of the Sparkplug host application accessible by its host application ID, can then be used by other components in the Sparkplug systems, e.g. by edge nodes configured to use this application as their primary host application, and only only publish their data when the primary host application is online.

Unless instructed otherwise, Rapid Toolkit for Sparkplug auto-generates a host ID that is conformant with the Sparkplug syntactic rules, and it also attempts to make it unique within the Sparkplug system.

If you want you program to behave as a Sparkplug host application with specific ID, you can do so by setting the HostId Property in the host descriptor passed to the methods on the consumer object. Just make sure to pass the same host descriptor all such method calls.

The following example illustares how to specify the Sparkplug host application ID.

.NET

// This example shows how to consume Sparkplug data while specifying own Sparkplug host application ID.
//
// In order to publish or observe messages for this example, start the SparkplugEdgeNodeConsoleDemo program first.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-ConnectivityStudio/Latest/examples.html .
// Sparkplug examples in C# on GitHub: https://github.com/OPCLabs/Examples-ConnectivityStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using OpcLabs.EasySparkplug;
using OpcLabs.EasySparkplug.OperationModel;
using System;
using System.Collections.Generic;

namespace SparkplugDocExamples.Consumer._SparkplugHostDescriptor
{
    class HostId
    {
        public static void Main1()
        {
            // Note that the default port for the "mqtt" scheme is 1883.
            // The second parameter is the host ID of this Sparkplug host application. Other Sparkplug components can use
            // this host ID to detect whether the application is online or offline.
            var hostDescriptor = new SparkplugHostDescriptor("mqtt://localhost", "easyApplication");

            // Instantiate the consumer object.
            var consumer = new EasySparkplugConsumer();

            Console.WriteLine("Subscribing...");
            consumer.SubscribeEdgeNodePayload(hostDescriptor, "easyGroup", "easySparkplugDemo",
                (sender, eventArgs) =>
                {
                    // Handle different types of notifications.
                    Console.WriteLine();
                    switch (eventArgs.NotificationType)
                    {
                        case SparkplugNotificationType.Connect:
                            Console.WriteLine($"Connected to Sparkplug host, client ID: {eventArgs.ClientId}.");
                            break;
                        case SparkplugNotificationType.Disconnect:
                            Console.WriteLine("Disconnected from Sparkplug host.");
                            break;
                        case SparkplugNotificationType.Data:
                        case SparkplugNotificationType.Birth:
                            Console.WriteLine("Received birth or data message from Sparkplug host.");
                            // Display the metrics name and data for each metric delivered in the payload.
                            foreach (KeyValuePair<string, SparkplugMetricElement> pair in eventArgs.Payload)
                                Console.WriteLine($"{pair.Key}: {pair.Value.MetricData}");
                            break;
                        case SparkplugNotificationType.Death:
                            Console.WriteLine("Received death message from Sparkplug host.");
                            break;
                    }
                    if (!eventArgs.Succeeded)
                        Console.WriteLine($"*** Failure: {eventArgs.ErrorMessageBrief}");
                });

            Console.WriteLine("Processing notifications for 20 seconds...");
            System.Threading.Thread.Sleep(20 * 1000);

            Console.WriteLine("Unsubscribing...");
            consumer.UnsubscribeAllPayloads();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);

            Console.WriteLine("Finished.");
        }
    }
}
' This example shows how to consume Sparkplug data while specifying own Sparkplug host application ID.
'
' In order to publish or observe messages for this example, start the SparkplugEdgeNodeConsoleDemo program first.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-ConnectivityStudio/Latest/examples.html .
' Sparkplug examples in C# on GitHub: https://github.com/OPCLabs/Examples-ConnectivityStudio-CSharp .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports OpcLabs.EasySparkplug
Imports OpcLabs.EasySparkplug.OperationModel

Namespace Global.SparkplugDocExamples.Consumer._SparkplugHostDescriptor
    Class HostId
        Public Shared Sub Main1()
            ' Note that the default port for the "mqtt" scheme is 1883.
            ' The second parameter is the host ID of this Sparkplug host application. Other Sparkplug components can use
            ' this host ID to detect whether the application is online or offline.
            Dim hostDescriptor = New SparkplugHostDescriptor("mqtt://localhost", "easyApplication")

            ' Instantiate the consumer object.
            Dim consumer = New EasySparkplugConsumer()

            Console.WriteLine("Subscribing...")
            consumer.SubscribeEdgeNodePayload(hostDescriptor, "easyGroup", "easySparkplugDemo",
                Sub(sender, eventArgs)
                    ' Handle different types of notifications.
                    Console.WriteLine()
                    Select Case eventArgs.NotificationType
                        Case SparkplugNotificationType.Connect
                            Console.WriteLine($"Connected to Sparkplug host, client ID: {eventArgs.ClientId}.")
                        Case SparkplugNotificationType.Disconnect
                            Console.WriteLine("Disconnected from Sparkplug host.")
                        Case SparkplugNotificationType.Data,
                            SparkplugNotificationType.Birth
                            Console.WriteLine("Received birth or data message from Sparkplug host.")
                            ' Display the metrics name and data for each metric delivered in the payload.
                            For Each pair As KeyValuePair(Of String, SparkplugMetricElement) In eventArgs.Payload
                                Console.WriteLine($"{pair.Key}: {pair.Value.MetricData}")
                            Next
                        Case SparkplugNotificationType.Death
                            Console.WriteLine("Received death message from Sparkplug host.")
                    End Select
                    If Not eventArgs.Succeeded Then
                        Console.WriteLine($"*** Failure: {eventArgs.ErrorMessageBrief}")
                    End If
                End Sub)

            Console.WriteLine("Processing notifications for 20 seconds...")
            System.Threading.Thread.Sleep(20 * 1000)

            Console.WriteLine("Unsubscribing...")
            consumer.UnsubscribeAllPayloads()

            Console.WriteLine("Waiting for 5 seconds...")
            Threading.Thread.Sleep(5 * 1000)

            Console.WriteLine("Finished.")
        End Sub
    End Class
End Namespace

 

Controlling the Host Application

Normally, Rapid Toolkit for Sparkplug takes care of starting and stopping the Sparkplug application. The Sparkplug host application is started when the first subscription is made, and stopped after all subscriptions are removed. While started, the Sparkplug host application attempts to stay connected to the Sparkplug system (MQTT broker).

In some scenarios, you may want to control the starting and stopping of the host Sparkplug host application yourself, but without a need to unsubscribe from everything in order to disconnect the application from the MQTT broker. To achieve this, first obtain the host application object (an instance of the EasySparkplugHostApplication Class) using the FindOrCreateHostApplication Method, and set its AutoStartStop Property to false. You can then use the Start Method and Stop Method to start and stop the Sparkplug host application explicitly.

Note that when the Sparkplug host application is disconnected from the MQTT broker, the subscriptions that you have made on the consumer object receive a data notification with error indication (see Data Notifications in Sparkplug Consumer and Rapid Toolkit for Sparkplug Consumer Error Model); also, publishing Sparkplug commands will not be possible in this state and will result in an error (reported by an exception thrown from synchronous publishing methods).

The following example illustrates how to start and stop the host application.

Example

.NET

// This example shows how to manually start and stop the host application.
//
// In order to publish or observe messages for this example, start the SparkplugEdgeNodeConsoleDemo program first.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-ConnectivityStudio/Latest/examples.html .
// Sparkplug examples in C# on GitHub: https://github.com/OPCLabs/Examples-ConnectivityStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using OpcLabs.EasySparkplug;
using OpcLabs.EasySparkplug.OperationModel;
using OpcLabs.EasySparkplug.System;

namespace SparkplugDocExamples.Consumer._EasySparkplugHostApplication
{
    class Start_Stop
    {
        public static void Main1()
        {
            // Note that the default port for the "mqtt" scheme is 1883.
            // The second parameter is the host ID of this Sparkplug host application. Other Sparkplug components can use
            // this host ID to detect whether the application is online or offline.
            var hostDescriptor = new SparkplugHostDescriptor("mqtt://localhost", "easyApplication");

            // Pre-create the host application, so that we can control it.
            EasySparkplugHostApplication hostApplication = EasySparkplugInfrastructure.Instance.FindOrCreateHostApplication(hostDescriptor);

            // Configure the host application so that we can manually start and stop it.
            hostApplication.AutoStartStop = false;
            
            // Instantiate the consumer object.
            var consumer = new EasySparkplugConsumer();

            // The lifetime of subscriptions is independent of the state of the host application. We can subscribe before
            // the application is started.
            Console.WriteLine("Subscribing...");
            // Thanks to implicit conversion, EasySparkplugHostApplication can be used in place of SparkplugHostDescriptor.
            consumer.SubscribeEdgeNodePayload(hostApplication, "easyGroup", "easySparkplugDemo",
                (sender, eventArgs) =>
                {
                    // Handle different types of notifications.
                    switch (eventArgs.NotificationType)
                    {
                        case SparkplugNotificationType.Connect:
                            Console.WriteLine($"Connected to Sparkplug host, client ID: {eventArgs.ClientId}.");
                            break;
                        case SparkplugNotificationType.Disconnect:
                            Console.WriteLine("Disconnected from Sparkplug host.");
                            break;
                        case SparkplugNotificationType.Data:
                            Console.Write("Data; ");
                            break;
                        case SparkplugNotificationType.Birth:
                            Console.Write("Birth; ");
                            break;
                        case SparkplugNotificationType.Death:
                            Console.Write("Death; ");
                            break;
                    }
                    if (!eventArgs.Succeeded)
                        Console.WriteLine($"*** Failure: {eventArgs.ErrorMessageBrief}");
                });

            Console.WriteLine();
            Console.WriteLine("Press Enter to start the application...");
            Console.ReadLine();
            hostApplication.Start();

            Console.WriteLine();
            Console.WriteLine("Press Enter to stop the application...");
            Console.ReadLine();
            hostApplication.Stop();

            Console.WriteLine();
            Console.WriteLine("Press Enter to unsubscribe...");
            Console.ReadLine();

            Console.WriteLine("Unsubscribing...");
            consumer.UnsubscribeAllPayloads();

            Console.WriteLine("Waiting for 5 seconds...");
            System.Threading.Thread.Sleep(5 * 1000);

            Console.WriteLine("Finished.");
        }
    }
}
' This example shows how to manually start and stop the host application.
'
' In order to publish or observe messages for this example, start the SparkplugEdgeNodeConsoleDemo program first.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-ConnectivityStudio/Latest/examples.html .
' Sparkplug examples in C# on GitHub: https://github.com/OPCLabs/Examples-ConnectivityStudio-CSharp .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports OpcLabs.EasySparkplug
Imports OpcLabs.EasySparkplug.OperationModel
Imports OpcLabs.EasySparkplug.System

Namespace Global.SparkplugDocExamples.Consumer._EasySparkplugHostApplication
    Class Start_Stop
        Public Shared Sub Main1()
            ' Note that the default port for the "mqtt" scheme is 1883.
            ' The second parameter is the host ID of this Sparkplug host application. Other Sparkplug components can use
            ' this host ID to detect whether the application is online or offline.
            Dim hostDescriptor = New SparkplugHostDescriptor("mqtt://localhost", "easyApplication")

            ' Pre-create the host application, so that we can control it.
            Dim hostApplication As EasySparkplugHostApplication = EasySparkplugInfrastructure.Instance.FindOrCreateHostApplication(hostDescriptor)

            ' Configure the host application so that we can manually start and stop it.
            hostApplication.AutoStartStop = False

            ' Instantiate the consumer object.
            Dim consumer = New EasySparkplugConsumer()

            ' The lifetime of subscriptions is independent of the state of the host application. We can subscribe before
            ' the application is started.
            Console.WriteLine("Subscribing...")
            ' Thanks to implicit conversion, EasySparkplugHostApplication can be used in place of SparkplugHostDescriptor.
            consumer.SubscribeEdgeNodePayload(hostApplication, "easyGroup", "easySparkplugDemo",
                Sub(sender, eventArgs)
                    ' Handle different types of notifications.
                    Select Case eventArgs.NotificationType
                        Case SparkplugNotificationType.Connect
                            Console.WriteLine($"Connected to Sparkplug host, client ID: {eventArgs.ClientId}.")
                        Case SparkplugNotificationType.Disconnect
                            Console.WriteLine("Disconnected from Sparkplug host.")
                        Case SparkplugNotificationType.Data
                            Console.Write("Data; ")
                        Case SparkplugNotificationType.Birth
                            Console.Write("Birth; ")
                        Case SparkplugNotificationType.Death
                            Console.Write("Death; ")
                    End Select
                    If Not eventArgs.Succeeded Then
                        Console.WriteLine($"*** Failure: {eventArgs.ErrorMessageBrief}")
                    End If
                End Sub)

            Console.WriteLine()
            Console.WriteLine("Press Enter to start the application...")
            Console.ReadLine()
            hostApplication.Start()

            Console.WriteLine()
            Console.WriteLine("Press Enter to stop the application...")
            Console.ReadLine()
            hostApplication.Stop()

            Console.WriteLine()
            Console.WriteLine("Press Enter to unsubscribe...")
            Console.ReadLine()

            Console.WriteLine("Unsubscribing...")
            consumer.UnsubscribeAllPayloads()

            Console.WriteLine("Waiting for 5 seconds...")
            Threading.Thread.Sleep(5 * 1000)

            Console.WriteLine("Finished.")
        End Sub
    End Class
End Namespace

 

 

Sparkplug is a trademark of Eclipse Foundation, Inc. "MQTT" is a trademark of the OASIS Open standards consortium. Other related terms are trademarks of their respective owners. Any use of these terms on this site is for descriptive purposes only and does not imply any sponsorship, endorsement or affiliation.