MQTT: The Go-To Protocol for Distributed IoT and Tutorial

press
Share on facebook
Share on reddit
Share on twitter
Share on linkedin
Share on email
Share on print

Imagine you have to deploy a dozen various devices throughout a factory floor. These consist of Linux PCs, low power embedded devices, a mobile phone app, simple sensors, and a remote database. Some devices are connected through Ethernet, while other more remote devices utilize a cell network to occasionally phone home. The problem you now have is, how do I get these devices communicating with each other in real time? MQTT is an ISO standard protocol used to solve this problem.

Intro

Message Queuing Telemetry Transport (MQTT) is a TCP/IP based protocol designed around the following:

  1. Asynchronous communication in near real-time between many different devices.
  2. Works on lossy and unreliable networks, such as a mobile connection
  3. Very low network overhead, functions over TCP/IP
  4. Follows a publish/subscribe paradigm, allowing a single unit to emit messages to many listeners
  5. Can encrypt data and send via TLS

These attributes make it ideal for (Machine to Machine) M2M and IoT applications. It’s especially useful where one is constrained by processing overhead, bandwidth limitations or intermittent network connections.

After a brief introduction to MQTT, this article will go over how to run an MQTT client application on your NetBurner device, and then we will create a simple application that will publish and listen for MQTT messages on a free cloud MQTT test server.

What is MQTT?

MQTT, at heart, consists of a publish/subscribe paradigm, so it is important to understand what this entails. A pub/sub model allows a single device to send data to all devices with a single packet. This is because the single device sends its data to a “broker”, which then distributes the data to all subscribers when they are available.

MQTT Publisher Broker Subscriber
Published data distributed to multiple subscribers via broker

To work within this model, a client should be able to execute five commands.

  1. Connect – Connect to a broker, utilize a keep alive if real time notification required
  2. Subscribe – Register yourself with the broker to listen for a message on a specific topic
  3. Publish – Post a message to a specific topic
  4. Unsubscribe – Remove your subscription to a specific topic
  5. Disconnect – Disconnect from a broker

What is Paho?

Instead of writing our own MQTT client, this example will utilize an open-source MQTT client library, called Paho. Paho consists of several MQTT clients written in a host of different languages to support the maximum number of devices. Language support includes Java, C/C++, GoLang, Python, and an Android Service. This article utilizes the embedded MQTT C/C++ library.

How To: Building Paho on a NetBurner / Connecting to Eclipse Cloud and sending a test message.

Now that you understand what MQTT is, let’s create a simple example that will publish to and subscribe to channels on a public MQTT testing server. You will need one of NetBurner’s System on Module Development Kits. For this example, we used an MOD55417 kit.

Step 1.

Begin by downloading this example from the NetBurner GitHub repository. It includes the relevant source from the Eclipse Paho MQTT C/C++ library.

Step 2.

Create a new project in NBEclipse, and import the source from the GitHub repository. If this is still new to you, use the method detailed in our getting started guide.

Step 3.

** important **

The Paho library was designed for a little-endian system. The NetBurner ColdFire® and ARM® modules are big-endian. Here’s a quick link if the term “endian” sounds new to you.

To account for a difference in endianness, the Paho source must be built with the defined symbol “REVERSED”. To do this, open the project properties by right clicking on the project and then selecting Properties.

Under C/C++ Build->Settings, Select GNU C++ Compiler->Preprocessor and add “REVERSED” to the defined symbols list. Just click the add page icon to the right of the window to add a define symbol. Add the same to the “GNU C Compiler” as well. “Apply and Close” to save these settings and return to the workspace.

MQTT Paho Library
Paho Library is little-endian and must be defined as”REVERSED” to work with the NetBurner C/C++ GNU Compilers, which are big-endian.

The Paho library does not include some platform specific functionality that changes based on the Operating System (OS). If you downloaded your code for this example from the NetBurner repository, it includes the platform specific functionality not provided by Paho. This includes opening and closing a network socket, handling timers, and generating logs.

Step 4.

Once the big-endian switch is made, you can load this example on to a NetBurner Ethernet device and it will begin sending its current uptime to the eclipse.org test MQTT server, located at www.iot.eclipse.org. It will also automatically subscribe to the same “topic” that it is sending the up-time to. So, you should see your post, and if any other devices are online and running this same example, you will see posts from them as well.

More Details on the Inner-Workings…

In the next section we’ll detail how some of the critical elements of this MQTT integration work.

Connect <code>

Let’s go over a few lines of code and describe a little about how the Paho library works. This will focus on three of the five commands (connect, subscribe, publish) listed above. For a more in-depth API discussion, see the Paho Embedded C/C++ documentation, which can be found in the GitHub repository for the library.

NBMQTTSocket mqttSocket;

MQTT::Client client = MQTT::Client(mqttSocket);

MQTTPacket_connectData connectOptions = MQTTPacket_connectData_initializer;
connectOptions.MQTTVersion = 3;
connectOptions.keepAliveInterval = 60; // We must send a keep-alive within this interval
connectOptions.cleansession = 1;
connectOptions.clientID.cstring = name;

In the beginning, we must create the MQTT client object. Then, a few connection options are set. In particular, the client must have a unique name that is sent to the broker. In this example, the name is set to nb-(the last two bytes of the mac address). This would not be an ideal name in a large network, as you may find another device with the same ending mac address. But it is sufficient for this example’s purposes.

The keep alive interval is also set to 60 seconds. This tells the broker to disconnect us from the service if we have not sent anything in 60 seconds. In our example, we will be sending a keep-alive packet every 30 seconds.

Subscribe <code>

client.subscribe("nbuptime", MQTT::QOS0, messageArrived);

void messageArrived(MQTT::MessageData& md)
{
    MQTT::Message &message = md.message;

    iprintf("Message %d arrived: qos %d, retained %d, dup %d, packetid %drnrn",
        ++arrivedcount, message.qos, message.retained, message.dup, message.id);

    iprintf("Message %d arrived: qos %d, retained %d, dup %d, packetid %drnPayload: %srn",
        ++arrivedcount, message.qos, message.retained, message.dup, message.id,
        (char*)message.payload);
}

Subscribing is handled in a single function call. This subscribe call notifies the broker that we want to receive messages from topic “nbuptime”. Then, we need to add a function handler for when a message comes in on this channel. This example will print out details of the incoming message.

Publish <code>

MQTT::Message message;
char buf[100] = { 0 };
siprintf(buf, "Uptime: %lu", Secs);
siprintf(buf, "%s -> Uptime: %lu", name, Secs);
message.qos = MQTT::QOS0;
message.retained = false;
message.dup = false;
message.payload = (void*)buf;
message.payloadlen = strlen(buf)+1;

client.publish("nbuptime",message);
client.yield(100); // Issue keep-alive

Finally, the application will publish a message to the broker. After configuring the options for the message, a string containing the current uptime of the device is published. This will immediately send out the message, and any subscriber listening to the topic “nbuptime” will get the payload. Finally, we issue the keep-alive. A “publish” also can function as a keep-alive packet, so this location is rather redundant. It is included to demonstrate how to send a keep-alive.

Check out our tutorial on using NetBurner MQTT with AWS IoT Core!

Share this post

Share on facebook
Share on twitter
Share on linkedin
Share on reddit
Share on email

Subscribe to our Newsletter

Get monthly updates from our Learn Blog with the latest in IoT and Embedded technology news, trends, tutorial and best practices. Or just opt in for product change notifications.

Leave a Reply

Your email address will not be published. Required fields are marked *