Multiple MQTT Topics with Arduino PubSubClient

Adding a few more subscriptions is pretty easy.

multiple mqtt topics

In my Arduino MQTT Examples, I kept things simple by only subscribing to a single topic. One of the strengths of MQTT is that a device can subscribe (or publish) to multiple topics. The broker will sort things out. Even though my first example only showed one, it is straight forward to get the Arduino PubSubClient library to subscribe to Multiple MQTT topics.

The quick answer is that you need to look at the MQTT response to find out which topic sent the payload.

tl;dr version

If you’re looking for a quick answer, here’s the magic code we’ll add to the callback() function.

void callback(char* topic, byte* payload, unsigned int length) {
if (strcmp(topic,"pir1Status")==0)
  // whatever you want for this topic
}

Keep reading for a more detailed explanation of how to Subscribe to Multiple MQTT topics with Arduino’s PubSubClient. Obviously, this code will work on Arduino boards with a TCP/IP interface and, of course, the ESP8266 based boards.

Subscribing to Multiple MQTT Topics

Subscribing to multiple MQTT topics is just a matter of repeating the subscribe code. For example, here I subscribe to topics called “red,” “green,” and “blue.” (Guess what they represent.)

boolean reconnect() {
  if (client.connect("arduinoClient")) {
    client.subscribe("pir1Status");
    client.subscribe("red");
    client.subscribe("green");
    client.subscribe("blue");
    return client.connected();
  }
  Serial.println("I think connect failed.");
  return 0;
}

Once subscribed, turn your attention to PubSubClient’s callback function. Whenever a message is received, the callback function handles it.

MQTT reply

The callback() function provides a character array called “topic.” You might be tempted to convert this into an Arduino String object. This overused object probably seems easier to use, since you could use a “==” operator to match strings.

You don’t need the overhead of the String object. Instead, leave “topic” as a character array. There is a function in libc (and avr-libc) that helps, strcmp(). My guess is that “strcmp” stands for “string compare.”

strcmp() takes two arguments: string1 and string2. The value it returns tells you something about how the two strings compare to each other. It’s a simple function to use but has a few things you need to know.

Issues using strcmp()

The first thing to know is that you can’t use a switch statement with strcmp(). I wish you could; it would make the code much easier to read. At least, in my eyes.

Next, you should understand that strcmp() doesn’t return what most people expect. Instead ‘0’, or false, comes back when there is a match.

Note on Substrings. Since strcmp() is part of libc, there is plenty of documentation to explain how it works in detail. You should understand why it might return a negative number or something more than zero.  I’m not going to cover handling substrings here. I carefully pick my topics to avoid substring matches.

Here’s an example of callback() that could support receiving a message while subscribed to multiple topics.

void callback(char* topic, byte* payload, unsigned int length) {
  if (strcmp(topic,"pir1Status")==0){
    // whatever you want for this topic
  }

  if (strcmp(topic,"red")==0) {
    // obvioulsy state of my red LED
  }

  if (strcmp(topic,"blue")==0) {
    // this one is blue...
  }  

  if (strcmp(topic,"green")==0) {
    // i forgot, is this orange?
  }  
}

It’s a simple matter of using strcmp() to match the topic received in the PubSubClient packet.

Conclusion

No doubt, there are probably more optimized ways to handle both the subscribing and receive processing. But I like the code being straight forward and easy to read. The key to handling multiple MQTT topics is processing the packet that PubSubClient provides.

Question: What other MQTT questions can I help answer? You can leave a comment by clicking here.

Your questions, comments, and even corrections are encouraged and very much appreciated! However. I have zero-tolerance for inappropriate or harassing comments. I try to reply to everyone... -James

Leave a comment

12 thoughts on “Multiple MQTT Topics with Arduino PubSubClient

  1. Hi James. Good tutorial, thanks !

    Can I have two PubSubclient clients – onte connected to a one broker, one to another ?

    Like:

    const char* mqtt_server1 = "iot.eclipse.org";
    const char* mqtt_server2 = "odilon.local";
    #define mqtt_port 17546
    
    WiFiClient espClient;   //this is a ESP8266 client; the connection is not aborded here
    
    PubSubClient MQTTclient1(espClient);
    PubSubClient MQTTclient2(espClient);
    
    .....
    .....
    
       MQTTclient1.setServer(mqtt_server1, mqtt_port);
       MQTTclient1.setCallback(callback1);
    
       MQTTclient2.setServer(mqtt_server2, mqtt_port);
       MQTTclient2.setCallback(callback2);
    

    Something like this.

    Thanks again !

    Odilon

    • I think I’ve connected to multiple brokers before (one inside my network and one public). But can’t find the code. (Maybe I haven’t.) I would imagine in addition to setCallback, you also need to add the second client to the reconnect function.

      • Hi James.

        Multiple brokers with a PubSubClient library are not supported. I took a look at the source, there is only one instance of the class in PubSubClient.h:

        private:
           Client* _client;
           uint8_t buffer[MQTT_MAX_PACKET_SIZE];
           uint16_t nextMsgId;
           unsigned long lastOutActivity;
           unsigned long lastInActivity;
           bool pingOutstanding;
           MQTT_CALLBACK_SIGNATURE;
           uint16_t readPacket(uint8_t*);
           boolean readByte(uint8_t * result);
           boolean readByte(uint8_t * result, uint16_t * index);
           boolean write(uint8_t header, uint8_t* buf, uint16_t length);
           uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
           IPAddress ip;
           const char* domain;
           uint16_t port;
           Stream* stream;
           int _state;
        

        I’ll take a look at this library to see if I can modify it.

        Best regards !

      • Hi james,

        I was wrong. Yes, it is possible to connect to two different brokers simultaneously.

        However, it is also necessary to double the Ethernet client:

        Const char * mqtt_server1 = "192.168.2.111";
        Const char * mqtt_server2 = "test.mosquitto.org";
        Const int mqtt_port1 = 1883;
        Const int mqtt_port2 = 1883;
        
        WiFiClient espClient1, espClient2;
        PubSubClient MQTTclient1 (espClient1);
        PubSubClient MQTTclient2 (espClient2);
        
        I made the connection up - to the broker on my local network and to the test broker at mosquitto.org. I sent and received messages from both.
        
        Regards !!
        
      • The reconnect function can be parameterized:

        void reconnect(PubSubClient MQTTclient, char* cliente) {
           // Loop until we're reconnected
           while (!MQTTclient.connected()) {
              Serial.print("Attempting MQTT connection...");
              // Attempt to connect
              if (MQTTclient.connect(cliente)) {
        
  2. Hi James,
    Tkx again for this tutorial, you make things simple ! In a project I’m trying to publish payload from my arduino or ESP8266 to a webpage, which updates the information. This goes about mqtt client in javascript. I’ve looked on the net but the info is scarse (or I don’t search well 🙂 Maybe you can give an example of how this could be done ?
    Thanks !