Using the Node.js MQTT Client-Starting Guide

node-mqtt-client-iconThe node.js MQTT client is an open source client that can be used for publishing messages and subscribing to topics on an MQTT broker. It  can be installed using:

npm install mqtt --save 

and
npm install mqtt -g
To install the command line tools

Documentation for the client is available here

In this tutorial we cover the important client functions and create a simple publish subscribe node,js example script.

To use the client you need to use:

var mqtt=require('mqtt');

at the top of your script.

Overview

Node.js scripts are asynchronous and use events. Events are triggered when something happens e.g the client connects.

You create a listener for the events you are interested in and this listener calls a callback function to process the event.

The Connection Method

This is the main method, and when called it connects to an MQTT broker and returns a client class.

The method is called as follows:

var client = mqtt.connect(url,options)

e..g.

var client = mqtt.connect("mqtt://192.168.1.157",options)
var client = mqtt.connect("mqtt://192.168.1.157",{clientId:"mqttjs01"})

Usually they are many options that need to be passed to the method and so the options is usually created as a JavaScript object. E.G.

To use user name and password authentication and a clean session use the following options.

options={
clientId:"mqttjs01",
username:"steve",
password:"password",
clean:true};

The MQTT protocol acknowledges a connection with the CONNACK message.

This raises the on_connect event in the client which can be examined by creating a listener as follows:

client.on("connect",function(){	
console.log("connected");

The listener waits for the connect event and calls a callback function; which in the example simply prints a message when the client connects.

We can now try our first example script.

This script connects to the test.mosquitto.org MQTT broker and prints a message when connected.

var mqtt    = require('mqtt');
var client  = mqtt.connect("mqtt://test.mosquitto.org",{clientId:"mqttjs01"});
client.on("connect",function(){	
console.log("connected");
})

The Interesting thing to note is that the cursor of the command prompt is on a new line and blinking.

simple-connect-node-script

This is because the client is still connected to the broker and is sitting in an event loop.

However we are at the end of the script so the only thing that can happen is an event. So our script just sits there and does nothing.

You can terminate the script by closing the client connection using.

client.end();

The on_connect event also sets a flag called connected to true. You can access this flag using: client.connected.

I’ve modified our simple script to print this flag before and after:

var client  = mqtt.connect("mqtt://test.mosquitto.org",{clientId:"mqttjs01"});
console.log("connected flag  "+client.connected);
client.on("connect",function(){	
console.log("connected  "+client.connected);
})

If you run the script you should see the following:

node-connection-script-2

Connection Failures

What happens if the connection fails?

The node client provides the error event for a connection failure. So to monitor this we need to create a listener for this event as follows:

client.on("error",function(error){ console.log("Can't connect"+error);

Unfortunately this will only catch failures like authentication failures.

If you try to connect on the wrong port or the wrong address no error is generated and you will find the client sits there and attempts to reconnect.

If the error detects an authentication failure then you will need to quit otherwise the client will continually attempt to connect.

Therefore the on_error event listener should be something like the one below:

client.on("error",function(error){
console.log("Can't connect" + error);
process.exit(1)});

Publishing Messages

To publish a message use:

client.publish(topic, message, [options], [callback])

the options and callback parameters are optional. Options include retain message flag,qos etc.
e.g.

client.publish("testtopic", "test message")

and

var options={
retain:true,
qos:1};
client.publish("testtopic", "test message",options)

Before publishing it is wise to check that you are connected using:

if (client.connected==true){
client.publish("testtopic", "test message",options)
}

However this is unlikely to work as the if statement will probably be tried before the client is connected as the connection is asynchronous.

Therefore if you want to simply- connect publish and disconnect, then you should call the publish in the on_connect callback.

If you need to publish at regular intervals e.g when sending status information then use the setInterval function as shown below.

var message="test message";
var topic="testtopic";
//publish every 5 secs
var timer_id=setInterval(function(){publish(topic,message,options);},5000);

//publish function
function publish(topic,msg,options){
  console.log("publishing",msg);
if (client.connected == true){
  client.publish(topic,msg,options);
}

Subscribing to Topics

To subscribe use the client.subscribe method. The general format is:

client.subscribe(topic/topic array/topic object, [options], [callback])

You use a topic string method if you only want to subscribe to a single topic.

You use the array method if you want to subscribe to multiple topics with the same qos. i.e. the qos you pass in the options is for all topics in the array.

You use the object method when you want to subscribe to multiple topics with different qos settings.
Example usage:

var topic_s="topic";
var topic_list=["topic2","topic3","topic4"];
var topic_o={"topic22":0,"topic33":1,"topic44":1};
client.subscribe(topic_s,{qos:1});
client.subscribe(topic_list,{qos:1});
client.subscribe(topic_o);

Receiving Messages

Before you can receive any messages you will need to be subscribed to a topic.

The message event is triggered when a new message arrives.

To process this event you need to create a listener .e.g.

client.on('message',function(topic, message, packet){
	console.log("message is "+ message);
	console.log("topic is "+ topic);
});

The callback needs to accept three parameters.-topic,message and packet.

The packet object contains the message,topic and message details like QOS,retain etc.

To see its contents use:

console.log(JSON.stringify(packet)

Below is a screen shot of an example received packet:

nodejs-received-packet

 

If we want to look at the retain flag we use:

console.log("packet retain =" +packet.retain);

To print the topic, message,packet and retain use the following code:

client.on('message',function(topic, message, packet){
	console.log("message is "+ message);
	console.log("topic is "+ topic);
	console.log("packet =" +JSON.stringify(packet));
	console.log("packet retain =" +packet.retain);
});

Final Script Example

The final script will connect to a broker subscribe to a collection of topics and publish a message on one of those topics every x seconds.

It will print out received messages to the console and quit after two loops.

var mqtt    = require('mqtt');
var count =0;
var client  = mqtt.connect("mqtt://192.168.1.157",{clientId:"mqttjs01"});
console.log("connected flag  " + client.connected);

//handle incoming messages
client.on('message',function(topic, message, packet){
	console.log("message is "+ message);
	console.log("topic is "+ topic);
});


client.on("connect",function(){	
console.log("connected  "+ client.connected);

})
//handle errors
client.on("error",function(error){
console.log("Can't connect" + error);
process.exit(1)});
//publish
function publish(topic,msg,options){
console.log("publishing",msg);

if (client.connected == true){
	
client.publish(topic,msg,options);

}
count+=1;
if (count==2) //ens script
	clearTimeout(timer_id); //stop timer
	client.end();	
}

//////////////

var options={
retain:true,
qos:1};
var topic="testtopic";
var message="test message";
var topic_list=["topic2","topic3","topic4"];
var topic_o={"topic22":0,"topic33":1,"topic44":1};
console.log("subscribing to topics");
client.subscribe(topic,{qos:1}); //single topic
client.subscribe(topic_list,{qos:1}); //topic list
client.subscribe(topic_o); //object
var timer_id=setInterval(function(){publish(topic,message,options);},5000);
//notice this is printed even before we connect
console.log("end of script");

Here is a screen shot of the script being run:

node-mqtt-script-example

You should notice that the end of script message is printed even though the script is obviously running.

This illustrates the asynchronous nature of node.js.

Using SSL

You can secure the connection using SSL. Below is a simple connection script that connects to a broker using SSL:

var mqtt    = require('mqtt');
const fs = require('fs');
var caFile = fs.readFileSync("ca.crt");

var options={
clientId:"mqttjs01",
//port:8883,
//host:'192.168.1.71',
//protocol:'mqtts',
rejectUnauthorized : false,
ca:caFile 
}
var client  = mqtt.connect("mqtts://192.168.1.71:8883",options);
console.log("connected flag  " + client.connected);
client.on("connect",function(){	
console.log("connected  "+ client.connected);
})

Notes: The rejectUnauthorized : false option is only necessary if there is a domain mismatch on the certificate and should normally not be used.

Notice how the certificate file is first read and passed as an option.

If you are also using client certificates then use the following:

var KEY = fs.readFileSync(‘client-certs\\client.key’);
var CERT = fs.readFileSync(‘client-certs\\client.crt’);

and in options:

key: KEY,
cert: CERT,

Here is a working connect SSL example script:

//https://github.com/mqttjs/MQTT.js/issues/264
var mqtt    = require('mqtt');
const fs = require('fs');
//var cert="ca.crt";
var caFile = fs.readFileSync("ca.crt");
//if using client certificates
var KEY = fs.readFileSync('client-certs\\client.key');
var CERT = fs.readFileSync('client-certs\\client.crt');
//
var options={
clientId:"mqttjs01",
//port:8883,
//host:'192.168.1.71',
//protocol:'mqtts',
rejectUnauthorized : false,
//if using client certificates
key: KEY,
cert: CERT,
//
ca:caFile 

}
var client  = mqtt.connect("mqtts://192.168.1.71:8883",options);
console.log("connected flag  " + client.connected);
client.on("connect",function(){	
console.log("connected  "+ client.connected);
})

See Github reference for more details

Was This Useful?

Resources:

Demo script used in this tutorial

download

Related Tutorials and Resources:

Please rate? And use Comments to let me know more

53 comments

  1. client.publish(“testtopic”, “test message”,””,()=>{console.log(“Message published”);})

    // Check if you are connected or not
    if(client.connected){
    client.publish(“TOPIC”,”TEST MESSAGE”)
    }

    // If you want to subscribe to topics
    client.subscribe(“testtopic”)

    // Once subscribed you need to listen to events
    client.on(‘message’,(topic,message,packet)=>{
    console.log(“Topic is::”+topic);
    console.log(“Message::”+message);
    console.log(“Packet is::”+packet);
    console.log(JSON.parse(JSON.stringify(packet)));
    })
    i published this message then on subscribing to it why it does not print test message in data but prints
    this :
    Message published
    connected true
    Topic is::testtopic
    Message::LED_Off
    Packet is::[object Object]
    {
    cmd: ‘publish’,
    retain: true,
    qos: 0,
    dup: false,
    length: 18,
    topic: ‘testtopic’,
    payload: {
    type: ‘Buffer’,
    data: [
    76, 69, 68, 95,
    79, 102, 102
    ]
    }
    }

  2. To handle with files(audio), like multer when using mqtt with rest API. Which library we should use to fetch files in node.js. I’ve seen binary.js. But that doesn’t maintained well.

  3. Thanks, Steve, for this awesome tutorial!

    I am developing a ReactJS application to control an embedded system using IOT. I utilize the shiftr.io mqtt broker, so a unique URL was generated for my project, which I use to connect both hardware and React application clients to it. However, I am getting an issue with the following error message despite the fact that I see multiple instances of clients on the shiftr.io dashboard:
    ws.js?725c:109 WebSocket connection to ‘ws://tatrawo.cloud.shiftr.io/’ failed:

    Here is how I initiated the client:

    const client = mqtt.connect(‘mqtt://tatrawo:K1FvDvCrcoL4aYaf@ttrww.cloud.shiftr.io’, {clientId: ‘tttrww’})

    What could be responsible for the error?

    1. Sorry but I’m not familiar with any of the applications you are using. Suggest you try the client with a working ws broker at test.mosquitto.org to rule out the broker configuration.
      Rgds
      Steve

  4. Hi,

    I am getting null as my first value after starting the subscribe.js code. Each code starts with null as the first value. I don,t know why. can you help me pls? Here is my code.

    var mqtt = require(‘mqtt’);
    var count =0;
    // current timestamp in milliseconds
    const timestamp = Date.now();
    const fs = require(‘fs’);

    var client = mqtt.connect(“mqtt://url”,{clientId:”mqtt01″});
    console.log(“connected flag ” + client.connected);

    //handle incoming messages
    client.on(‘message’,function(topic, message, packet){
    let array=[];
    console.log(“message is “+ message);

    fs.appendFileSync(‘file.json’, message + “,” + “\r\n”, err => {
    if (err) {
    console.error(err);
    }
    // done!
    });
    console.log(“”);
    });

    client.on(“connect”,function(){
    console.log(“connected “+ client.connected);
    })

    //handle errors
    client.on(“error”,function(error){
    console.log(“Can’t connect” + error);
    process.exit(1)});
    console.log(“”);

    var topic=”publish/temp”;
    console.log(“subscribing to topics”);
    client.subscribe(topic,{qos:0}); //single topic
    console.log(“end of script”);

  5. Following my question from a few hours ago, I have found the problem: the protocol should have been wss and not mqtts.

    Thank you Steve for your tutorials!!

  6. Hi Steve,

    I’m following your tutorials with massive success; many thanks for sharing your knowledge!!

    I have a problem with setting up MQTT.js client to connect to my broker using WebSocket over TLS; the broker is mosquitto version 2.0.14 runs on Ubuntu 20.04 in AWS, and Cloudflare manages the domain nameservers; the broker’s conf file holds the following (BTW – the certificate files I created based on this answer https://stackoverflow.com/a/70337211/8288589):

    ####################################
    listener 1883
    listener 8443
    protocol websockets
    allow_anonymous false
    password_file /home/ubuntu/mqttBrokerPassword.txt
    acl_file /etc/mosquitto/conf.d/acfile.acl
    cafile /etc/mosquitto/certs/ca-root-cert.crt
    keyfile /etc/mosquitto/certs/server.key
    certfile /etc/mosquitto/certs/server.crt
    tls_version tlsv1
    ####################################

    I have a python client that connects to that broker using the following with no problems:

    ####################################
    client = mqtt.Client(‘”55fa721d0c1880c3’, transport=”websockets”)
    client.ws_set_options(path=”/mqtt”, headers=None)
    client.tls_set(ca_certs=”ca-root-cert.crt”)
    client.username_pw_set(username=”admin”,password=”my!Super@Password”)
    client.connect(“not.myreal.domain.com”, 8443, 60)
    ####################################

    The problem is when I try to use the same settings with the MQTT.js I can’t connect to the broker, this is the code I’m using:

    ///////////////////////////////////////////////
    mqtt = require(‘mqtt’)
    fs = require(‘fs’)
    var username = “admin”
    var pass = “my!Super@Password”
    var host = “not.myreal.domain.com ”
    var port = 8443
    var CAfile = fs.readFileSync(myPath + ‘/Misc/ca-root-cert.crt’) // same file the python uses
    client = mqtt.connect({servers : [{ host: host, port: port}], username:username, password:pass, clientId: ‘mqttjs55fa721d0c1880c3”, rejectUnauthorized:false, protocol:’mqtts’, ca: CAfile});
    ///////////////////////////////////////////////

    Can you pls let me know what is it I’m missing here?
    Many thanks in advance!!!
    Cheers,
    Ram

  7. I have a question.
    The code below succeeds in javascript but fails in vue.
    const client = mqtt.connect(‘wss://192.168.0.108’, {
    port: port,
    username: ‘ijoon’,
    password: ‘cadasic’,
    clientId: ‘mqttjs_’ + Math.random().toString(16).substr(2, 8),
    protocolId: ‘MQTT’,
    secureProtocol: ‘TLSv1_method’,
    protocolVersion: 4,
    rejectUnauthorized: false,
    })
    Why?

  8. i have a website built on vue.js
    is it possible to connect hive-mq cloud cluster using web-socket ?
    whats the port number? 8883 doesn’t work.

  9. I want to try connect mqtt broker at ip ‘100.31.29.1’ over websocket but i receive error [ECONNREFUSED 127.0.0.1:9001]
    var client = mqtt.connect({
    host:’100.31.29.1′,
    protocol: ‘ws’,
    port: 9001,
    clientId: ‘hello’
    });
    can anyone help me why my host is localhost while i set it is ip 100.31.29.1 and solve it

  10. I have tested the demo publish.js script with my mqtt broker. It works. I am able to see ‘testtopic = test message’. How do I change the code to view in this format?
    { id: ‘e79341ccf8ea’, address: ‘e7:93:41:cc:f8:ea’, rssi: -60, serviceData:{ model: ‘H’, modelName: ‘WoHand’, mode: false, state: false, battery: 97 } }
    To be exact, I have a scan.js file that outputs the above json when I run ‘sudo node scacn.js’. I would like publish to my mqtt broker using your script.

    1. var m_out ={ id: ‘e79341ccf8ea’, address: ‘e7:93:41:cc:f8:ea’, rssi: -60, serviceData:{ model: ‘H’, modelName: ‘WoHand’, mode: false, state: false, battery: 97 } };
      //This is an object so
      m_out=JSON.stringify(m_out);
      //now JSON
      client.publish(topic,m_out,options);

      1. Thank you for your reply. I have followed your sample above and got it working. Can you explain how I can run status.js (which will split out an object) within your code? A search came up with adding ‘ar childProcess = require(‘child_process’);’. But I am still uncertain how to code it into ‘var m_out’

          1. status.js is node I created that reads data from a switchbot bot device via bluetooth in json format. I want to import the data to my mqtt broker. The below code is from status.js

            // https://github.com/futomi/node-switchbot#SwitchbotDeviceWoHand-object
            // Load the node-switchbot and get a `Switchbot` constructor object

            const Switchbot = require(‘node-switchbot’);
            // Create an `Switchbot` object
            let switchbot = new Switchbot();

            // Set a callback function called when a packet is received
            switchbot.onadvertisement = (ad) => {
            console.log(ad);
            };

            switchbot.discover({
            duration: 5000,
            quick: true
            });

            // Start to scan advertising packets
            switchbot.startScan().then(() => {
            // Wait for 10 seconds
            return switchbot.wait(4000);
            }).then(() => {
            // Stop to scan
            switchbot.stopScan();
            process.exit();
            }).catch((error) => {
            console.error(error);
            });

  11. Hello Steve, I need to populate the list of topics while subscribing, can i do that dynamically if I want to do so.

  12. Hi Steve, your tutorials are always very helpful. What if the certificates are signed by an authorized CA? Haven’t been able to connect through my nodejs client to my broker though I can connect using the MQTT box.

  13. Hi steve,
    Thanks for your clarifyings.
    About mqtt node.js, http bridge, would you give a start to implemet multi parallel connections?
    I mounted the bridge but only one user works. thank you!

    1. Hi
      Tks for the link I’ve been asked several times about React but I haven’t got around to learning it yet.
      Rgds
      Steve

  14. Hi,
    Just a remark.
    Eclipse Paho doesn’t provide Node.js MQTT client but only Javascript MQTT client for browsers.
    So, the MQTT Client you talked about is a npm package written by mcollina but not
    by the Eclipse Paho Team.

  15. Hi
    Great tutorial!

    I have a question, in the tutorial the mqtt connection is made to each new connected client.
    Is it possible to connect only the nodejs server to the Mqtt server and not each client?
    Because I want to communicate with the Mqtt server even when no client is connected.

    Thank you

    1. Hi
      Not sure what you mean here. The nodejs server I assume is an HTTP server in which case it would need an mqtt client to connect to mosquitto.
      Does that make sense
      rgds
      steve

      1. Hi
        Excuse me, I was not clear in my question.

        Thanks to Node-js I want to make a home automation server + an HTTP server.

        My Node-js server must connect to the MQTT server to retrieve information from my house and process it even if no HTTP client is connected.

        When an HTTP client connects to my Node-js server, they must receive the information that the Node-js server has processed.

        Once all HTTP clients have left the site, the connection with the MQTT server must still be active.

        My problems :
        – When no HTML client is connected, I cannot connect to the MQTT server.

        – If several HTML clients are connected, several subscriptions are created on the same MQTT topic. While I would like only one to be created for the Node-js server.

        Can you help me ? please.

        I’m sorry for my English translation.

        1. Hi
          It looks like you need to connect the clients to the node-js server and the node-js server you The MQTT broker.
          This means that the node-js server should be equipped with an MQTT client for collecting data from the broker.
          What are you using as the node-je server? Is it your own code?
          rgds
          steve

          1. Thank you for your reply 🙂

            I don’t really understand the question: which js node server I use …
            I use express for the HTML part and the websocket to communicate with the client HTTP. If this is the answer you are waiting for.

            All the code was done with my hands.

            How to connect the Node-js server to the MQTT server? Please.
            I searched for hours on the internet without finding a reponce.

            Thank you

  16. Thanks for creating these educational walk-throughs.

    I ran into a few issues with this excellent how-to when using mosquitto 1.5.7 on Linux and npm mqtt (on NodeJS 10.16.3)

    Trying to force TLS version and protocol causes “wrong version number” or “unsupported protocol” SSL3 messages in the log. Instead, remove both mosquitto.conf tls version and NodeJS secureProtocol, and instead use ‘protocol: “mqtts” and let OpenSSL figure out the handshake, like so:

    const client = mqtt.connect({
    // Don’t set protocol in conf.d for mosquitto or in NodeJS
    // Instead, use ‘mqtts’ for protocol.
    protocol: ‘mqtts’,
    host: ‘mqttmanager’,
    port: 8883,

    clientId: ‘mqttjs01’,

    // Self-signed requirement for NodeJS
    rejectUnauthorized : false,
    ca: ‘ca.crt’,
    })
    Thanks!

  17. Good morning, I can’t connect my index.js file to cloudmqtt broker. Is there how to make this connection to an external broker through nodejs?
    Thank you

  18. Dear Steve,

    Do i have to install mosquitto broker in my computer and create the topic in the MQTT broker before making this test?

    Thank you!

    1. No you can use a public broker that supports websockets.
      The hive broker does
      broker.hivemq.com on port 8000
      I also think the broker
      test ,mosquitto.org on port 8080 does but I couldn’t verify it as it was down.
      Installing mosquitto has the advantage that you can debug problems easier as you can see the messages on the broker console.
      Rgds
      Steve
      You don’t create topics on the broker they are created by the client whed it subscribes to a topic.

  19. Hi Steve, great post thanks! I know it might be out of the scope of this project, but I have two questions which might help others that would like to do a sort of IOT app. Here goes nothing:

    1. How would you go about to store the information every X seconds to let’s say a MongoDB?
    2. What would be the easiest way to send the nodejs information to a client frontend such as react?

    1. Hi
      I Have written python data loggers for flat files and sqllite and they can be downloaded there is also anode-red flow.
      This tutorial has the links
      http://www.steves-internet-guide.com/logging-mqtt-sensor-data
      These should serve as a guide when creating a node.js version.
      I found this tutorial on the web that might help with node.js and react
      https://medium.com/@etherealm/node-and-react-a-brief-introduction-99b672262fed
      I’m afraid I’ve never worked with react
      Hope it helps
      Rgds
      Steve

  20. Dear Steve,

    is it true to say that the mqtt used in Node.js is just another mqtt-client running natively? not somekind of ajax passing the .js running in browser? If so, the easiest way to access from “outside” using express, get and post? I am so sorry that I am not clear about these

    Thanks a lot!!!

    1. Sorry but I don’t really understand.
      The node.js client is a node.js application.
      If you look at node-red which uses express and has an MQTT node that may help.
      Rgds
      Steve

  21. I need to write a MQTT subcriber in a browser where i should not use Websockets. Is it possible to create such a subcriber? Will server sent do any benefits here? Please help me. Thank you in advance.

    1. Hi
      You need to use websockets as the brokers only support websockets and so does the browser.
      Rgds
      Steve

  22. I have a question. In “final script example”, it is written “var client = mqtt.connect(“mqtt://192.168.1.157″,{clientId:”mqttjs01″});”. Is number “192.168.1.157” IP address of the device that behaves as a mqtt server, aka broker, or something else?
    I want my raspberry Pi to serve as mqtt broker and my own computer to serve as a mqtt client, can I connect them by writing my raspberry Pi’s IP address as you did?
    Thank you.

Leave a Reply

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