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.

Long comments, URLs, and code tend to get flagged for spam moderation. No need to resubmit.

ALL comments submitted with fake or throw-away services are deleted, regardless of content.

Don't be a dweeb.

Leave a comment

55 thoughts on “Multiple MQTT Topics with Arduino PubSubClient

  1. HI, James

    I am lost as last years easter egg.

    these are my error codes, im new to this and its taken me a while to whittle down to these

    nodedht.ino: In function ‘void callback(char*, byte*, unsigned int)’:
    nodedht:73: error: expected ‘;’ before ‘)’ token
    nodedht:239: error: expected ‘}’ at end of input
    expected ‘;’ before ‘)’ token

    void callback(char* topic, byte* payload, unsigned int length) {
    Serial.print(“Message arrived on topic: “);
    Serial.print(topic);
    Serial.print(“. Message: “);
    char messageTemp;

    for (char i = 0; i < length; i++) {
    Serial.print((char)topic[i]);
    messageTemp += (char)payload[i];
    }
    Serial.println();

    // If a message is received on the topic box/relay_1, you check if the message is either on or off. Turns the relay GPIO according to the message
    if (strcmp)topic, "relay_1") == 0) {
    for (int i=0;i<length;i++) {
    char receivedChar = (char)payload[i];
    }
    if (receivedChar == '0') {
    digitalWrite(relay_1, HIGH);
    Serial.print("On");
    }
    if (receivedChar == '1')
    digitalWrite(relay_1, LOW);
    Serial.print("Off");
    }
    // If a message is received on the topic box/relay_2, you check if the message is either on or off. Turns the relay GPIO according to the message
    if (strcmp)topic, "relay_2") == 0) {
    for (int i=0;i<length;i++) {
    char receivedChar = (char)payload[i];
    }
    if (receivedChar == '0') {
    digitalWrite(relay_2, HIGH);
    Serial.print("On");
    }
    if (receivedChar == '1')
    digitalWrite(relay_2, LOW);
    Serial.print("Off");
    }
    // If a message is received on the topic box/relay_3, you check if the message is either on or off. Turns the relay GPIO according to the message
    if (strcmp)topic, "relay_3") == 0) {
    for (int i=0;i<length;i++) {
    char receivedChar = (char)payload[i];
    }
    if (receivedChar == '0') {
    digitalWrite(relay_3, HIGH);
    Serial.print("On");
    }
    if (receivedChar == '1')
    digitalWrite(relay_3, LOW);
    Serial.print("Off");
    }
    // If a message is received on the topic box/relay_3, you check if the message is either on or off. Turns the relay GPIO according to the message
    if (strcmp)topic, "relay_4") == 0) {
    for (int i=0;i<length;i++) {
    char receivedChar = (char)payload[i];
    }
    if (receivedChar == '0') {
    digitalWrite(relay_4, HIGH);
    Serial.print("On");
    }
    if (receivedChar == '1')
    digitalWrite(relay_4, LOW);
    Serial.print("Off");
    }
    }
    Serial.println();

    }

  2. Hello, dear
    I have a problem and I did not have any answer

    this part of code is working perfectly with mqtt and no have any problem

    void callback(char* topic, byte* payload, unsigned int length) {

    if (strcmp(topic,string1) ==0){
    // whatever you want for this topic
    Serial.print(“Message arrived [“);
    Serial.print(topic);
    Serial.print(“] “);
    stringTwo = “”;
    for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    stringTwo.concat((char)payload[i]);
    }
    Serial.println();

    if (stringTwo == "connect"){
    //———————————————
    if (out1_state == 1){
    val = "out1 on";
    client.publish(sender, val.c_str(),0);
    }

    if (out1_state == 0){
    val = "out1 off";
    client.publish(sender, val.c_str(),0);
    }
    //———————————————

    if (out2_state == 1){
    val = "out2 on";
    client.publish(sender, val.c_str(),0);
    }

    if (out2_state == 0){
    val = "out2 off";
    client.publish(sender, val.c_str(),0);
    }
    //———————————————

    if (out3_state == 1){
    val = "out3 on";
    client.publish(sender, val.c_str(),0);
    }

    if (out3_state == 0){
    val = "out3 off";
    client.publish(sender, val.c_str(),0);
    }
    //———————————————

    if (out4_state == 1){
    val = "out4 on";
    client.publish(sender, val.c_str(),0);
    }

    if (out4_state == 0){
    val = "out4 off";
    client.publish(sender, val.c_str(),0);
    }
    //———————————————
    }

    but the problem is when add other if statements then then the mqtt disconnected and give this message

    Attempting MQTT connection…failed, rc=-2 try again in 5 seconds

    if (out5_state == 1){
    val = "out5 on";
    client.publish(sender, val.c_str(),0);
    }

    if (out5_state == 0){
    val = "out5 off";
    client.publish(sender, val.c_str(),0);
    }

    if (out6_state == 1){
    val = "out6 on";
    client.publish(sender, val.c_str(),0);
    }

    if (out6_state == 0){
    val = "out6 off";
    client.publish(sender, val.c_str(),0);
    }

    could you please tell me why this happen?

  3. Hi James,

    I learn much from your MQTT tutorials and your website is so pleasant to read, thanks for all this work.
    I have a question, I’d like to retrieve some simple digit from the payload and wonder if the callback function should be simplified without the for() loop.
    I’m trying this without success :

    void callback(char* topic, byte* payload, unsigned int length){
    if(strcmp(topic, “my_topic”)==0){
    /*
    for (int i = 0; i < length; i++) {
    my_var = (char)payload[i];
    */
    my_var = payload;
    Serial.print(my_topic);
    }
    }

    I know it is a basic programming question that involves Types (since I'm looking for digits) but I'm not able yet to deal with those arrays passed to the callback.
    Is there a way to modify the parameter inside the callback or is it "strict" since the callback has a given signature:
    https://pubsubclient.knolleary.net/api.html#callback

    Thank you for your clarification.
    Best to your website 🙂

  4. Hi,
    I want to teach in a school the MQTT to do an IoT project… Here I use the Controllino MEGA Board and followimg code:

    // (Includes lost because comment system thought it was HTML)
    #include 
    #include 
    #include 
    #include  //MQTT Bibliothek
    
    #define CLIENT_ID       "Bua"
     //uint8_t mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
     uint8_t ip[] = { 192, 168, 6, 66 };
     uint8_t gateway[] = { 192, 168, 6, 53 };
     uint8_t subnet[] = { 255, 255, 255, 0 };
    
    void callback(char* topic, byte* payload, unsigned int length) {
      Serial.print("Message arrived [");
      Serial.print(topic);
      Serial.print("] ");
      for (int i=0;i>length;i++) {
        Serial.print((char)payload[i]);
      }
      Serial.println();
    }
    
    EthernetClient ethClient;
    PubSubClient client;
    
    void reconnect() {
      // Loop until we're reconnected
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Attempt to connect
        if (client.connect(CLIENT_ID)) {
          Serial.println("connected");
          // Once connected, publish an announcement...
          client.publish("outTopic","hello world");
          // ... and resubscribe
          client.subscribe("inTopic");
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          delay(5000);
        }
      }
    }
    
    void setup()
    {  Serial.begin(9600);
      delay(1500);
      Ethernet.begin( ip, gateway, subnet); //Ethernet.begin(mac, ip);
    
      Serial.println("Ethernet begin");
      client.setClient(ethClient);
      delay(1500);
      client.setServer("test.mosquitto.org",1883);
      delay(1500);
    }
    
    void loop()
    {  
      Serial.println("loop");
      //client.connect(CLIENT_ID);
      Serial.println("client no connect?");
      client.publish("jdsr","hello world");
      client.setCallback(callback);
      Serial.println("RX TX");
      if (!client.connected()) {
        reconnect();
      }
      client.loop();
    }
    

    There is no work. Also, no network ping is working. Do you have an idea?
    Thanks,
    Artur

  5. Hi James, thank you for your Arduino / ESP8266 / MQTT articles.
    I’m old hat on Arduino, but new to MQTT. This seems simple in practice, but I’m not sure how to code it:

    On an ESP8266:
    Subscribe to a topic & monitor its value
    If topic value = 1,
    do something (trigger a relay, light an LED, etc.) and write a 0 back to the topic.

    Context:
    IFTT & Adafruit.IO –> ESP8266
    I’m using an IFTT Google Assistant applet that will write a 1 to an A.IO feed/topic when I say a phrase.
    But the value stays at 1, so I figured the ESP8266 should write a 0 back to the topic after it takes action on the 1.

    Does that make sense?

    Thanks!

  6. I want to subscribe to myname/feeds/mytopic at Adafruit.com mqtt server, port 1883
    And I want to publish on my local Mosquitto mqtt server something and same port 1883.
    Using wifi to LAN
    I have tried many ways but I can not do both.

    Maybe not bossible?

    This should be interesting for some automation using voice to control things with Android + Google Asisstant + IFTTT

    Thank you

    • I think the client object can only connect to one server at a time. You might be able to create multiple objects for multiple servers. Another option is to run a script on the broker / local mosquitto server. Anytime it receives a message for the topic, it could publish it to AdafruitIO.

    • Hi Dag,
      Having a client connect to two brokers are a bit of an anti-pattern. Your client should connect to one broker only.
      It is the topics that should span multiple brokers (could though be renamed in transit) to serve subscribers that connect to them, not the clients. So set up your local Mosquito to connect to the Adafruit broker for the given topic and exchange messages.
      Have a look at this tutorial http://www.steves-internet-guide.com/mosquitto-bridge-configuration/
      However I’m not familiar with the Adafruit broker capability.

  7. Is it possible to both subscribe and publish to different Mqtt topics ď from an esp8288?
    The case is a garage ( or gate) opener that responds to commands, but also reports back temperature and gate open/closed state. I imagine this type of device could be possible – a controller that also reports back sensor data.

    Is there a better server/client platform to use than mqtt? ( This all connects to an openhab implementation for me )

  8. Late to the party again…

    “When the student is ready, the teacher will appear.” This is EXACTLY what I needed. I was even able to modify, extend and make it work without issue. Thanks for saving me a day of pounding through the nitty-gritty of the pubsub API.

    Another trick:
    You use strcmp() to compare the returned topic value with a constant string. If you define your topics as const char*, you can use strcmp() to compare them with what is returned.

    const char* Topic1 = “cheerlights”;
    const char* Topic2 = “cheerlights/rgb/9digits”;
    …..
    if (strcmp(topic,Topic1)==0){ *do one thing* };
    if (strcmp(topic,Topic2)==0){ *do another thing* };

    I like to put all those things up at the top so I only have to correct my typos once.

    Thanks again!