Friday, April 1, 2016

Develop for Intel Edison with NodeJS: MQTT


MQTT.

MQTT (MQ Telemetry Transport Protocol) is a protocol widely used in IoT space.
It is a messaging protocol designed to be used primarily in resource-constrained environment.

For example:
·       Situation where the bandwidth is limited, the latency is high;
·       Situation where the transmitting device has limited processing power and memory (e.g.: 8 bit micro-controller, 32 KB memory) and where you want to limit power consumption.

MQTT is now an OASIS standard (MQTT 3.1.1); See:


This is the definition that you find in OASIS site:
Providing a lightweight publish/subscribe reliable messaging transport protocol suitable for communication in M2M/IoT contexts where a small code footprint is required and/or network bandwidth is at a premium.

The protocol overhead is minimal (message header can be as short as 2 bytes).

It is based on the Publish/Subscribe Design Pattern.
Communication with MQTT requires a MQTT Broker: the client publish a message to the broker, on a client-defined topic. On the other side, several applications can subscribe to this topic, and receive messages.
Each application can act both as publisher and subscriber.
The same message can be consumed by more than one application (this is an useful feature, you can easily add more processing logic simply adding more subscribers to the same topic).

MQTT is based on TCP (this can be seen as a limitation[1]) but adds to TCP some reliability features.
A client must be connected before sending a message to the broker. In addition, there is a continuous exchange of ping and acknowledge messages between the client and the broker, to ensure that the broker knows if a client is still connected.

You can specify a Quality of Service (QoS):
·       QoS = 0 (best effort, no guaranteed delivery);
·       QoS = 1 (a message is received at least once);
·       QoS = 2 (a message is received once and only once);

Another important feature is that the communication can be made secure. You can protect the connection with username/password or, more, you can encrypt the communication with MQTT over TLS, ensuring confidentiality and integrity.

An OpenSource MQTT broker.

A widely used MQTT OpenSource broker is Mosquitto. See:


Mosquitto is a very light broker, written in C, now an Eclipse project.
It can be easily installed on Linux, Mac OS and other OS.
You will find it already installed and running on Intel Edison board.

With Mosquitto, you also get two utilities useful to test the MQTT broker:
·       mosquitto_pub, that can be used to publish messages;
·       mosquito_sub, that can be used to subscribe to topics and receive messages.

In our tests we will use Mosquitto installed on MacBook (OSX) and on a Raspberry PI 2, that act as an IoT gateway.

Some initial tests with Mosquitto.

You can start Mosquitto directly from the command-line. There is a configuration file, mosquitto.conf, where you can set many configuration parameters (for example the port the broker is listening on).

I have created on my MacBook a script that starts Mosquitto:

vi start_mosquitto.sh

/usr/local/sbin/mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf –v


On the console you see:

1459525061: mosquitto version 1.4.2 (build date 2015-05-08 13:55:22-0700) starting
1459525061: Config loaded from /usr/local/etc/mosquitto/mosquitto.conf.
1459525061: Opening ipv4 listen socket on port 1883.
1459525061: Opening ipv6 listen socket on port 1883.

(1883 is the default port for MQTT).

To test that the broker configuration is working correctly you can use mosquito_sub and mosquito_pub.

With mosquitto_sub you can register a subscriber on the topic “temp” (you can use whatever string you want).

./mosquitto_sub -h localhost -t temp

(you here specify that the broker is on localhost, but it can be on whatever machine is connected through TCP).

After this command you see on the Mosquitto console:

New client connected from ::1 as mosqsub/609-MacBook-Pro (c1, k60).
1459525180: Sending CONNACK to mosqsub/609-MacBook-Pro (0, 0)
1459525180: Received SUBSCRIBE from mosqsub/609-MacBook-Pro
1459525180:      temp (QoS 0)
1459525180: mosqsub/609-MacBook-Pro 0 temp
1459525180: Sending SUBACK to mosqsub/609-MacBook-Pro
1459525240: Received PINGREQ from mosqsub/609-MacBook-Pro
1459525240: Sending PINGRESP to mosqsub/609-MacBook-Pro

Now, you can send on the same (temp) topic a message simulating a value read from a temperature sensor:

./local/bin/mosquitto_pub -t temp -h localhost -m "36"

(m is the message. A sequence of bytes).

And the result on the window where you have launched the subscriber is:

./mosquitto_sub -h localhost -t temp
36

So, this way you have simulated a client that publish a message on a topic, and a subscriber that receives this message.

From this example, you can understand that you can test integration through MQTT protocol, using the utilities mosquitto_pub and mosquitto_sub.

For example: you can create a NodeJS application, running on Intel Edison, that reads values from a temperature sensor attached and send the values to a MQTT broker on a Raspberry PI, connected to the same WI-FI network. Then, you can simulate an application subscribing to the topic using mosquitto_sub, run on the RPI 2.


Why MQTT (How many clients)?

In my honest opinion, there are several reasons for using MQTT in IoT space:

1.     If you want to manage readings from sensors, you’re in the original use-case for MQTT (Telemetry);
2.     The protocol is lightweight;
3.     It is a reliable protocol; You can therefore guarantee the delivery of messages;
4.     You have client libraries available for many languages: C, Java; Python, JavaScript (NodeJS);


NodeJS and MQTT.

There is a good client library for MQTT written in JavaScript, available for the NodeJS platform: MQTT.js.


And here you see an example of a NodeJS program, tested on Intel Edison, that:

1.     Connect to a MQTT broker (on a RPI 2);
2.     Simulate a reading from a sensor, periodically;
3.     Send a message to the broker on a topic; The message is a JSON formatted message with the ID of the sensor and the value of the temperature;

var TOPIC_NAME = 'temp';
var SENSOR_ID =  'SN1';
var BROKER_URL = 'mqtt://thethingbox';
var SLEEP_TIME = 30000; // 30 seconds

var mqtt = require('mqtt');

var mqtt_client  = mqtt.connect(BROKER_URL, {'keepalive' : 60});
   
mqtt_client.on('close', handle_mqtt_close);
mqtt_client.on('connect', handle_mqtt_connect);
mqtt_client.on('reconnect', handle_mqtt_reconnect);
mqtt_client.on('error', handle_mqtt_err);
mqtt_client.on('message', handle_messsage);

var msg = {};
var count = 0;

function handle_mqtt_connect()
{
    console.log("MQTT Connect...");

    mqtt_client.subscribe('control/sn1', handle_mqtt_subscribe);
}

function handle_mqtt_subscribe(err, granted)
{
    console.log("MQTT Subscribe...");
   
    if (err)
    {
        console.log(err);
    }
}

function handle_mqtt_reconnect(err)
{
    console.log("MQTT Reconnect...");

    if (err)
    {
        console.log(err);
    }
    mqtt_client  = mqtt.connect(BROKER_URL, {'keepalive' : 60});
}

function handle_mqtt_err(err)
{
    console.log("MQTT Error...");
   
    if (err)
    {
        console.log(err);
    }
}

function handle_mqtt_close()
{
    console.log("MQTT Close...");
}

function after_publish()
{
    // for now nothing...
}

function handle_messsage(topic, message, packet)
{
    console.log('Message received!');
   
    console.log('msg = ' + message.toString());
}

//
// this function is called periodically, simulate reading and send the msg
//
function readSensors()
{
  count = count + 1;
  console.log('***********************');
  console.log("Iteration n. %d", count);

  // now use sensors module (sensors.js)
  var rounded_temp = 99;
 
  // it is simple to build the msg object   
  // build the object message
  // that will be sent as a JSON message
  msg.id = SENSOR_ID;
  msg.temp = rounded_temp.toString();
   
  // send with qos = 2
  if (rounded_temp)
    mqtt_client.publish(TOPIC_NAME, JSON.stringify(msg), {'qos' : 2}, after_publish);
 
  //call the indicated function after SLEEP_TIME (in msec)
  setTimeout(readSensors, SLEEP_TIME);
}


readSensors();




[1] Other protocols, like COAP, are based on UDP, that is lighter than TCP.

No comments:

Post a Comment