MQTT 101 – How to Get Started with the lightweight IoT Protocol

Introduction

Everybody talks about the Internet of Things nowadays. Increasingly affordable micro controllers like Arduino and Raspberry Pi are enabling cheap devices that measure sensor data and send it over the internet. The goal of this post is to introduce the lightweight protocol MQTT and its capabilities to send data between devices and other systems and to demonstrate them by implementing two clients with Eclipse Paho.

The term Internet of Things was first used by Kevin Ashton in 2009 for interconnecting physical devices over the internet. The basic idea is very simple: Physical devices can exchange data between each other or being controlled by others. Examples of such devices would be a refrigerator, a car, a building or basically any other electronic device. One of the most common use cases is the collection, transmission, consolidation and displaying of sensor data. The results could be a web dashboard with the aggregated values or an alarm, when a threshold is exceeded.
The application scenarios are almost unlimited. Imagine your alarm clock would know that your train to work is 15 minutes late and adjust itself accordingly. Also your coffee maker is switched on automatically 15 minutes later to make you a hot cup of coffee before you leave for work. Sounds like the future ? All that is already possible today. Ericsson predicts that in 2020 50 billion devices are connected over the internet. The communication between the huge amount of devices is enabled by IPv6 and lightweight communication protocols like MQTT.

MQTT

MQTT was developed by Andy Stanford-Clark (IBM) and Arlen Nipper (Eurotech; now Cirrus Link) in 1999 for the monitoring of an oil pipeline through the desert. The goals were to have a protocol, which is bandwidth-efficient and uses little battery power, because the devices were connected via satellite link and this was extremely expensive at that time.
The protocol uses a publish/subscribe architecture in contrast to HTTP with its request/response paradigm. Publish/Subscribe is event-driven and enables messages to be pushed to clients. The central communication point is the MQTT broker, it is in charge of dispatching all messages between the senders and the rightful receivers. Each client that publishes a message to the broker, includes a topic into the message. The topic is the routing information for the broker. Each client that wants to receive messages subscribes to a certain topic and the broker delivers all messages with the matching topic to the client. Therefore the clients don’t have to know each other, they only communicate over the topic. This architecture enables highly scalable solutions without dependencies between the data producers and the data consumers.

MQTT Publish/Subscribe

MQTT Publish/Subscribe Architecture


The difference to HTTP is that a client doesn’t have to pull the information it needs, but the broker pushes the information to the client, in the case there is something new. Therefore each MQTT client has a permanently open TCP connection to the broker. If this connection is interrupted by any circumstances, the MQTT broker can buffer all messages and send them to the client when it is back online.
As mentioned before the central concept in MQTT to dispatch messages are topics. A topic is a simple string that can have more hierarchy levels, which are separated by a slash. A sample topic for sending temperature data of the living room could be house/living-room/temperature. On one hand the client can subscribe to the exact topic or on the other hand use a wildcard. The subscription to house/+/temperature would result in all message send to the previously mention topic house/living-room/temperature as well as any topic with an arbitrary value in the place of living room, for example house/kitchen/temperature. The plus sign is a single level wild card and only allows arbitrary values for one hierarchy. If you need to subscribe to more than one level, for example to the entire subtree, there is also a multilevel wildcard (#). It allows to subscribe to all underlying hierarchy levels. For example house/# is subscribing to all topics beginning with house.

Eclipse Paho

Now with the concept of topics explained, it is time to jump right into the first implementation and to show how the publishing and subscribing can be done using source code. But first a quick introduction of Eclipse Paho, the MQTT implementation used in this example. It has been founded under the umbrella of the Eclipse Foundation at the beginning of 2012 with the goal to provide open IoT protocol implementations. The implementation of MQTT is the de-facto reference implementation and available in Java, C, C++, JavaScript, Lua, Python and soon also C#. The origin of most of the implementations is the codebase of IBM and Eurotech, who have used them in many internal projects in production.

Use Case

In order to make the subsequent code more understandable, we will use the transferring of sensor data from a temperature and brightness sensor to a control center over the internet as an example. The sensors will be connected to a Raspberry Pi, which acts as gateway to the MQTT broker, which resides in the cloud. On the other side is a second device, the control center, that also has an MQTT client and receives the data. Additionally we will implement a notification, which alerts the control center if the sensor is disconnected.

Use Case Communication Flow

Communication between the sensor client and the control center over MQTT


Implementation

First we will implement the sensor client, which is simulating a thermometer and a brightness sensor. It should send a current value every second to the MQTT broker. In this case we are using the HiveMQ public broker on the MQTT Dashboard. The first step is to create an instance of the MqttClient class.

public class Publisher
{
     public static final String BROKER_URL = "tcp://broker.mqttdashboard.com:1883";
     private MqttClient client;

     public Publisher()
     {

          String clientId = Utils.getMacAddress() + "-pub";
          try
          {
               client = new MqttClient(BROKER_URL, clientId);
          }
          catch (MqttException e)
         {
              e.printStackTrace();
              System.exit(1);
          }
     }
}

As parameters for the constructor it is necessary to specify the URL of the broker (tcp://broker.mqttdashboard.com:1883) and also the client id. The latter is an unique identifier overall the broker. A good choice for the client id is the MAC address of the computer, because that is automatically unique. In the example -pub is added to the mac address, because otherwise it wouldn’t work starting both clients on the same machine for testing. After creating the instance, it is possible to try to connect to the broker with calling client.connect(). Apart from a simple connect, it is also possible to hand over more parameters. One example is the clean session flag. When it is set to true, the broker will wipe the session every time the client disconnects, otherwise it will keep the subscription and buffer the messages sent with Quality of Service 1 and 2 (more on this later). The session is assigned to the client id, therefore it is truly important to have it unique. Another option is Last Will and Testament (LWT), which helps detecting failures of other clients. As stated above every client has an open connection, so when the client disconnects ungracefully the broker can detect that. If the client has set a LWT topic and message on connect, the broker will send that to the specified topic, which allows the client to notify others about its failure.

//...

MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
options.setWill(client.getTopic("home/LWT"),
"I'm gone".getBytes(), 2, true);

client.connect(options);

//...

Now we have to implement the business logic to retrieve the values and send them every second, therefore we use an infinite loop and the methods publishTemperature and publishBrightness. Each method creates a MqttTopic object and a random value, which will then be published. The complete examples of both clients can be found on GitHub.

     public static final String TOPIC_TEMPERATURE = "home/temperature";

     //...
     while (true)
     {
          publishBrightness();
          Thread.sleep(500);
          publishTemperature();
          Thread.sleep(500);
     }
     //...

     private void publishTemperature() throws MqttException {
         final MqttTopic temperatureTopic = client.getTopic(TOPIC_TEMPERATURE);

         final int temperatureNumber = Utils.createRandomNumberBetween(20, 30);
         final String temperature = temperatureNumber + "°C";

         temperatureTopic.publish(new MqttMessage(temperature.getBytes()));
     }

     //publishBrightness() wird analog zu publishTemperature() implementiert

Each message can be published with one of three quality of service levels (QoS). These levels are associated with different guarantees. A message send with level 0 doesn’t have a guarantee at all, it implies fire and forget. Level 1 guarantees that the message will at least arrive once, but can arrive more than once. Level 2 is the most sophisticated choice, which guarantees that the message arrives at the destination exactly once. The choice of QoS is a trade-off, between protocol overhead and the guarantee that the message arrives, because ensuring QoS 2 is using more bandwidth than QoS 0.

The next step is implementing the subscribing client, which is reading the values on the topics home/temperature and “home/brightness”, plus observes the home/LWT topic for the last will message to detect a failure of the sensor client. The initialization of the MqttClient instance is almost the same, except we use -sub as a suffix for the client id. For receiving the messages sent by the sensor simulator, it is necessary to implement the MqttCallback interface. The MqttCallback interface defines three methods that need to implemented: connectionLost, messageArrived and deliveryComplete. connectionLost is called when the connection is unexpectedly closed form the MQTT broker. This method is the best place for a reconnect logic. The method messageArrived is called when the broker sends a new message to this particular client. Finally, there is the deliveryComplete method that is called after a message with QoS 1 or 2 reaches the broker. For our use case implementing the messageArrived method is enough. All arriving messages should be print out with topic and payload and if it is sent on the home/LWT topic, we additionally print out Sensor gone!.

public class SubscribeCallback implements MqttCallback
{

     @Override
     public void connectionLost(Throwable cause) {}

     @Override
     public void messageArrived(MqttTopic topic, MqttMessage message)
     {
          System.out.println("Message arrived. Topic: " + topic.getName() + " Message: " + message.toString());

          if ("home/LWT".equals(topic.getName()))
          {
               System.err.println("Sensor gone!");
          }
     }

     @Override
     public void deliveryComplete(MqttDeliveryToken token) {}

}

After implementing the callback, we have to make it known to the MqttClient before connecting. Also after the successful connection is established, it is necessary to subscribe to all topics, which should be sent to the client. In this case it should be everything that starts with home, so the usage of a multi-level wildcard saves us from subscribing to 3 different topics: home/#.

mqttClient.setCallback(new SubscribeCallback());
mqttClient.connect();
mqttClient.subscribe("home/#");

Run both clients

Now that the sensor client and the Control Center are implemented, it is time to run both applications. We start the Control Center first and then the sensor client. Once the sensor client starts, messages arrive at the Control Center. If you will now exit the sensor client ungracefully, this is recognized by the Control Center immediately through the Last Will and Testament message.
Congratulations, you have now build your first Internet of Things application with MQTT!

Summary

This simple application is just an example and can be easily adapted and reused for more advanced purposes. You could simply extend the existing code so that multiple clients in different rooms measure the temperature and brightness, and the Control Center also indicates that. Another possibility would be to replace the Control Center through a web dashboard where the values are displayed in several charts using the Paho JavaScript library.

As we have seen, it is possible with very little effort to create application that communicates over MQTT. The Eclipse Paho library implements all the functionality that is described in the MQTT specification and MQTT should be a tool in the repertoire of every developer, who deals with the Internet of Things or the requirement of connecting mobile devices.

About the Authors