Skip to main content

Tutorial for using the Node.js MQTT client with FairCom's MQTT broker engine

This section contains MQTT Client tutorials for Node.js developers.

Introduction

This quick start guide includes two tutorials. Both are command-line programs that you can use to publish messages and monitor published messages. Thus, the tutorials perform double duty. They show you how to use MQTT and they create command-line utilities that you can use to learn and troubleshoot MQTT.

MQTT tutorials:

FairCom MQ is an MQTT broker. Programs use an MQTT client library to publish and subscribe to messages on the MQTT broker.

An MQTT client does the following:
  • Connects to an MQTT broker.

  • Publishes a message to a topic.

  • Subscribes to a topic and receives all messages published to that topic by any client.

Installation

Prerequisites:
  • Install FairCom MQ.

  • FairCom MQ (or another MQTT broker) must be running on 127.0.0.1 and listening on port 1883.

  • The latest stable version of Node.js must be installed.

  • In the directory, <faircom>/drivers/nodejs.mqtt/NodejsMQTTTutorial1, run npm install to load the required node_modules.

    Note

    It is important that your computer be connected to the internet when you run npm install because around 80 modules will be downloaded and installed.

Code dependencies

The tutorial uses the MQTT.js Client Library for Node.js to communicate with MQTT. The MQTT.js client library is an open-source project using the MIT license.

Note

FairCom chose the MQTT.js client library over the Paho MQTT library because it works well, supports all versions of MQTT, uses an MIT license and is an active, mature project on GitHub.

This tutorial is a command-line utility for publishing MQTT messages. It publishes a message to a specified topic on a specified broker. This is useful for testing and troubleshooting MQTT.

The source code is simple and self-explanatory and is located in the <faircom>/drivers/nodejs.mqtt/NodejsMQTTTutorial1/publish/publish.js file.

Command line usage

node publish.js -t topic -f fileName -q qos -c clientid -s hostname:port -u username -p password

Command line options

Options may be present in any order, and if absent, default values will be used.

Table 1. Command line options

Option

Description

-t topic

An optional topic to publish to. It defaults to testTopic.

-f fileName

A required file name to use for the payload in the published message. The file may contain anything.

-q QoS

An optional quality of service to use when publishing the message. It defaults to 1.

  • 0 provides no guarantee of delivery.

  • 1 guarantees delivery at least once.

  • 2 guarantees delivery at most once.

-c clientID

An optional client id that uniquely identifies the client to the MQTT broker. It defaults to testPubClientID.

-s hostname:port

An optional hostname and port of an MQTT broker. It defaults to 127.0.0.1:1883.

-u username

An optional user name to use when connecting to the broker. If absent, a connection without a username and password is attempted.

-p password

An optional password to use with the username provided above. If absent a username without a password is attempted.

-h

Prints the usage and exit.



Example 1. Command line
node publish.js -t testTopic -f /Users/username/myjsonfiles/data.json


Example 2. Output
connecting to client at: mqtt://127.0.0.1:1883

connected to client at: mqtt://127.0.0.1:1883

publishing to topic testTopic

Connection closed by client


Code

// Variable declarations and initialization
const argv            = require('yargs').argv,
      mqtt            = require('mqtt'),
      process         = require('process'),
      validation      = require('./validation')
const fs              = require('fs')
let client            = null,
    hasHelpParam      = validation.hasHelpParam(argv),
    hasRequiredParams = validation.hasRequiredParams(argv)
// Default settings used to configure MQTT client
var settings          = {
    brokerAddress: '127.0.0.1:1883',
    clientID     : 'testPubClientID',
    fileName     : null,
    qos          : 1,
    topic        : 'testTopic',
    username     : null,
    password     : null
}

if (hasHelpParam) {
    validation.usage()
}
/* Parameter exit conditions
      1 - User passed the 'help' parameter
      2 - User didn't pass required parameters
      3 - User pressed Ctrl + C */
if (hasHelpParam || !hasRequiredParams) {
    process.exit()
}
process.on('SIGINT', function () {
    console.log('\nshutting down MQTT client after Ctrl C')
    process.exit()
})

// Override default 'settings' object properties using params passed by user.
Object.keys(argv).forEach((key) => {
    let property = validation.getArgProperty(key)

    if (property != null) {
        settings[property] = argv[key]
    }
})

// Connect to client connection.
console.log(`connecting to client at: ${settings.brokerAddress}`)
client = mqtt.connect(`mqtt://${settings.brokerAddress}`, {
    clientId       : settings.clientID,
    connectTimeout : 30 * 1000,
    reconnectPeriod: 1000,
    protocolId     : 'MQIsdp',
    protocolVersion: 3,
    ...((settings.username !== null) && { username: settings.username }),
    ...((settings.password !== null) && { password: settings.password })
})

// Add mqtt client event listeners
client.on('connect', function () {
        console.log(`connected to broker at: ${settings.brokerAddress}`)

        // read in file from fileName path passed in by user.
        console.log(`reading file at ${settings.fileName}`)
        try {
            const fs = require('fs'),
                  msgData = fs.readFileSync(settings.fileName);
            publishMsg(msgData)
        } catch (e) {
            if (e.code !== 'MODULE_NOT_FOUND') {
                client.end()
                throw e
            }
        }
    },
)

client.on('error', function (err) {
    console.log('Error: ' + err)
    if (err.code === 'ENOTFOUND') {
        console.log(
            'Network error: Verify the passed hostname:port and that ' +
            'your MQTT server is running.')
    }
})

client.on('close', function () {
    console.log('connection closed by client')
    if (client.isConnected) {
        client.end()
    }
    process.exit()
})

function publishMsg (msgData) {
    console.log(`publishing to topic ${settings.topic}`)
    client.publish(settings.topic,
        JSON.stringify(msgData),
        { qos: settings.qos })
    client.end()
}

This tutorial is a utility for subscribing to MQTT messages in a topic. Each message sent to the topic is output to the console and optionally written as a file to the specified folder. This utility is useful for testing and troubleshooting MQTT.

The source code is simple and self-explanatory and is located in the <faircom>/drivers/nodejs.mqtt/NodejsMQTTTutorial1/subscribe/subscribe.js file.

Command line usage

node subscribe.js -t topic -d directory -q QoS -c clientID -s hostname:port -u username -p password

Command line options

Options may be present in any order, and if absent, default values will be used.

Table 2. Command line options

Option

Description

-t topic

An optional topic to subscribe to. It defaults to testTopic.

-d directory

An optional directory to save messages as files. If omitted, messages will be printed to screen and not saved to files. If you specify a directory that does not exist, it is created. Existing files in the directory with the same name are overwritten.

-q QoS

An optional quality of service to use when when subscribing to the topic. It defaults to 1.

  • 0 provides no guarantee of delivery.

  • 1 guarantees delivery at least once.

  • 2 guarantees delivery only once.

-c clientID

An optional client id that uniquely identifies the client to the MQTT broker. It defaults to testSubClientID.

-s hostname:port

An optional hostname and port of an MQTT broker. It defaults to tcp://127.0.0.1:1883.

-u username

An optional user name to use when connecting to the broker. If absent, a connection without a username and password is attempted.

-p password

An optional password to use with the username provided above. Ignored if the username is absent.

-h

Prints the usage and exit.



Example 3. Command line
node subscribe.js -t testTopic -d testDir -c testSubClientID


Example 4. Output
connecting to broker at: 127.0.0.1:1883

connected to broker at: 127.0.0.1:1883

subscribing to topic: testTopic

 

Messages that arrive will be printed to the screen.

received message: {

       "property":    "value",

       "string":      "string",

       "number":      1,

       "boolean":     true,

       "null...


Store incoming message

When a directory is specified, the utility writes the payload of each received message to a file. The name of the file is the name of the topic you specified followed by an underscore plus a sequential number. Topic names are case-sensitive. The file has no extension because an MQTT payload can be anything.

Examples of file/topic names:
  • testTopic_000001

  • testTopic_000002

  • testTopic_000003

  • testTopic_000004

Code

module.exports         = {
    getArgProperty: function (arg) {
        let property = null
        switch (arg.toLowerCase()) {
            case 's':
            case 'server':
            case 'broker':
            case 'brokeraddress':
                property = 'brokerAddress'
                break
            case 't':
            case 'topic':
                property = 'topic'
                break
            case 'c':
            case 'client':
            case 'clientid':
                property = 'clientID'
                break
            case 'f':
            case 'file':
            case 'filename':
                property = 'fileName'
                break
            case 'u':
            case 'user':
            case 'username':
                property = 'username'
                break
            case 'p':
            case 'pass':
            case 'password':
                property = 'password'
                break
            case 'q':
            case 'qos':
                property = 'qos'
                break
        }

        return property
    },

    hasHelpParam: function(argv) {
        return Object.keys(argv).some(k => (k === 'h')) || Object.keys(argv).some(k => k.startsWith('help') );
    },

    hasRequiredParams: function(argv) {
        let hasFileNameProperty = Object.keys(argv).some(k => (k === 'f')) || Object.keys(argv).some(k => k.startsWith('file') )

        if (!hasFileNameProperty && !this.hasHelpParam(argv)) {
            console.log(`The fileName (-f) parameter is required.`)
            return false;
        }

        return true;
    },

    usage: function () {
        console.log(`
            Usage: node publish.js -f /pathtofile/sample.json
            Publish the contents of a file to a broker using the specified topic.
            
            Options:
               -s server     Server address.  Defaults to \"127.0.0.1:1883\"
               -t topic      The topic to publish to.  Defaults to \"testTopic\".
               -c clientID   The unique ID to use when connecting to the broker.  
                             Defaults to \"testPubClientID\".
               -f fileName   The file to use as a payload to publish.
               -u username   An optional username to authenticate with when 
                             connecting to the broker.  If absent, a connection 
                             without credentials will be attempted.
               -p password   The password to use with the username provided 
                             above.  Ignored if the username is absent.
               -q qos        The Quality Of Service to publish with.  
                             Defaults to 1.
               -h help       Print the usage and exit.
               
            Options may be present in any order, and if absent, default values 
            will be used. Invalid options will be ignored.
        `)
    },
}

Don't hesitate to contact us with questions, suggestions, and bug reports. We want you to be successful.

Contact info:
  • Address:

    6300 W. Sugar Creek Drive

    Columbia, Missouri 65203-9052

  • Phone:

    800.234.8180