Problem with MQTT multiple subscriptions and TOPIC separation.

I know I asked about how to get multiple MQTT subscriptions a while back.

I have sort of worked it out, I hope.
It seems to be working, but it doesn't seem to be able to separate the TOPICS.

Though this part is the part in questions for now:

  if (topic == "TEST")
  {
    header(3);
    header(2);
    header(1);
    header(0);
    
  }

Which doesn't seem to work/be invoked if I send a message with the TOPIC as TEST.

Yet, the topic is shown in this part:

  Serial.print("Message arrived [");
  Serial.print(topic);            //  <<----   Topic printed here.
  Serial.print("] ");

  for (int i = 0; i < length; i++)         //  <<-----  Payload.
  {
    Serial.print((char)payload[i]);
  }
  Serial.println();

Where the topic is clearly printed out, and I see [TEST] printed. Given the [ and ] are added, as you can see.

As it is, I can send a <1> or <0> in either IFF, TEST or the third topic to which I am subscribed.
Any topic the LED turn on/off.
But, I wasn't really wanting that.

I only want the LED to turn on/off with a certain topic.
You can see in the code I have bits where it conditionally has code similar to the part shown above for TEST, but it doesn't work.

This is the entire routine:

And below is an extract of how I subscribe to multiple channels, in case I am not doing it right.

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();

  if (topic == "TEST")
  {
    header(3);
    header(2);
    header(1);
    header(0);
    
  }
  
  char x;
  byte y = 0;

//  //    **************  2019 02 23   IFF channel detection.
//  if (topic == "IFF")
//  {
    //    IFF Channel message received.
    if ((char)payload[0] == 'X')
    {
      //
      IPAddress ip = WiFi.localIP();
      snprintf(ip_addr, 60, "{\"WIFI_DEVICE\":\"GPS\",\"IP_Address\":\"%ld.%ld.%ld.%ld\"}" , ip[0], ip[1], ip[2], ip[3]);
      Serial.println(ip_addr);
      client.publish(idTopic, ip_addr);
      blinker();
    }
//  }
  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') 
  {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is acive low on the ESP-01)
  } 
  else 
  if ((char)payload[0] == '0') 
  {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  } 
  else 
/*
  if ((char)payload[0] == '2') 
  {
    IPAddress ip = WiFi.localIP();
    snprintf(ip_addr, 60, "{\"WIFI_DEVICE\":\"GPS\",\"IP_Address\":\"%ld.%ld.%ld.%ld\"}" , ip[0], ip[1], ip[2], ip[3]);
    Serial.println(ip_addr);
    client.publish(idTopic, ip_addr);
  }
  else 
*/
  if ((char)payload[0] == '3') 
  {
    display_active = 1;
    wipe(15);
  }
  else 
  if ((char)payload[0] == '4') 
  {
    {
      Serial.print("  First  digit received ");
      Serial.println((char)payload[1]);
      y = (payload[1]);

      if ((char)payload[2] != 'M')
      {
        Serial.print("  Second digit received ");
        Serial.println((char)payload[2]);
        y = (payload[1]*10) + (payload[2]);
      }

      Serial.print("   Constructed digit ");
      if (y > 9)
      {
        //
        Serial.print(" * ");
        Serial.print((char)(y/10));
      }
      Serial.println((char)(y%10));
    }
    display_active = 1;
    display_brightness(y);
  }
  else 
  if ((char)payload[0] == '5')    //  Not used any more I hope.
  {
    display_active = 1;
    display_brightness(0);
  }
  else
  if ((char)payload[0] == '6') 
  {
    //
    //display_brightness(15);   //  WRONG.   Need to change all values sent to 15.
    //
    Serial.println("******  DISPLAY TURNED OFF  ********");
    display_active = 0;
  }
  else
  if ((char)payload[0] == '7') 
  {
    //  Display E's on screen.
    test();
  }
  if ((char)payload[0] == '8') 
  {
    //  Another test routine.
    test2();
  }
  if ((char)payload[0] == '9') 
  {
    //  Another test routine.
    test4();
  }
}

Subscribe to multiple channels:

const char* idTopic = "STATUS/WIFIDEVICEID";
const char* inTopic1 = "IFF";
const char* inTopic2 = "DISPLAY_BRIGHTNESS";
const char* outTopic = "outTopic";
void reconnect() 
{
  // Loop until we're reconnected
  Serial.println("Reconnecting");
  while (!client.connected()) 
  {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(mqtt_server, willTopic, willQoS, willRetain, willMessage)) 
    {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish(outTopic, "hello world");
      // ... and resubscribe
      client.subscribe(inTopic1);
      client.subscribe(inTopic2);
      client.subscribe("TEST/#");
      //  Publish IP address back to server for future use.
      IPAddress ip = WiFi.localIP();

You need extra code in the callback to check the topic, I use something like the posted code below.

const char* idTopic = "STATUS/WIFIDEVICEID";

void callback(char* topic, byte * data, unsigned int length)// Callback for subscribed MQTT topics
{
  Serial.print(topic);
  Serial.print(": ");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)data[i]);
  }
  Serial.println();
  
  
  if (strncmp(topic, idTopic, strlen(idTopic)) == 0)        // Check it's the right topic
  {
    if(data[0] == '0')                                      // LED off
    {
      // TURN LED OFF
    }
    if(data[0] == '1')                                      // LED on
    {
      // TURN LED ON
    }
  }
}

Hi.

Looking at the code:

const char* idTopic = "STATUS/WIFIDEVICEID";

void callback(char* topic, byte * data, unsigned int length)// Callback for subscribed MQTT topics
{
  Serial.print(topic);
  Serial.print(": ");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)data[i]);
  }
  Serial.println();
 
 
  if (strncmp(topic, idTopic, strlen(idTopic)) == 0)        // Check it's the right topic
  {
    if(data[0] == '0')                                      // LED off
    {
      // TURN LED OFF
    }
    if(data[0] == '1')                                      // LED on
    {
      // TURN LED ON
    }
  }
}

So the line:

  if (strncmp(topic, idTopic, strlen(idTopic)) == 0)        // Check it's the right topic

That looks and compares it to idTopic.

So THAT is the real topic, rather than the topic given in line:

void callback(char* topic, byte * data, unsigned int length)// Callback for subscribed MQTT topics

Ok. I never would have got that.

Thanks. Shall apply and see what happens as soon as possible.

I'm not quite getting something.

const char* idTopic = "STATUS/WIFIDEVICEID";

void callback(char* topic, byte * data, unsigned int length)// Callback for subscribed MQTT topics
{
  Serial.print(topic);
  Serial.print(": ");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)data[i]);
  }
  Serial.println();
 
 
  if (strncmp(topic, idTopic, strlen(idTopic)) == 0)        // Check it's the right topic
  {
    if(data[0] == '0')                                      // LED off
    {
      // TURN LED OFF
    }
    if(data[0] == '1')                                      // LED on
    {
      // TURN LED ON
    }
  }
}

Ok, so what is the difference between idTopic and inTopic?

I'll do some digging, but just would like to ask all the same.
In the code I have:

const char* idTopic = "STATUS/WIFIDEVICEID";
const char* inTopic1 = "IFF";
const char* inTopic2 = "DISPLAY_BRIGHTNESS";
const char* outTopic = "outTopic";

I thought that the inTopic1 and inTopic2 were the names of the ..... topics to which it is listening.
As outTopic is the one to which it publishes.

You will need to compare each topic in turn and then check the payload (data).
The below will point you in the right direction but the payload code will need changing to suit.

const char* idTopic = "STATUS/WIFIDEVICEID";
const char* inTopic1 = "IFF";
const char* inTopic2 = "DISPLAY_BRIGHTNESS";


void callback(char* topic, byte * data, unsigned int length)// Callback for subscribed MQTT topics
{
  // "STATUS/WIFIDEVICEID"
  if (strncmp(topic, idTopic, strlen(idTopic)) == 0)        // Check it's the right topic
  {
    if(data[0] == '0')                                      // LED off
    {
      // TURN LED OFF
    }
    if(data[0] == '1')                                      // LED on
    {
      // TURN LED ON
    }
  }
  
  // "IFF"
  if (strncmp(topic, inTopic1, strlen(inTopic1)) == 0)      // Check it's the right topic
  {
    if(data[0] == '0')                                      // LED off
    {
      // TURN LED OFF
    }
    if(data[0] == '1')                                      // LED on
    {
      // TURN LED ON
    }
  }
  
  // "DISPLAY_BRIGHTNESS"
  if (strncmp(topic, inTopic2, strlen(inTopic2)) == 0)      // Check it's the right topic
  {
    if(data[0] == '0')                                      // LED off
    {
      // TURN LED OFF
    }
    if(data[0] == '1')                                      // LED on
    {
      // TURN LED ON
    }
  }
}

This will only work if the details are at the start of the topic. If they are concatenated like "STATUS/WIFIDEVICEID/IFF" then you will need to either check in more stages or concatenate a suitable char array in memory to compare to.

Thanks, but I think I am still not getting something.

const char* idTopic = "STATUS/WIFIDEVICEID";
const char* inTopic1 = "IFF";
const char* inTopic2 = "DISPLAY_BRIGHTNESS";

Why is one idTopic, and the others are inTopic?
Is that just a naming thing?

That last example is better as originally I couldn't understand the line:

if (strncmp(topic, idTopic, strlen(idTopic)) == 0)

because I didn't get what idTopic was doing and if it was the same at both times in the line.
I guess I need to read what the command strncmp() is/does.

Trying to pull it apart:
strncmp( topic <- Who is this? idTopic (yeah, ok, I defined this), strlen (length? (idTopic)) == 0

So it compares topic to idTopic and somewhere it uses the length of idTopic and sees if it is zero.

Oh well. I'll study it and try to learn.

lost_and_confused:
Trying to pull it apart:
strncmp( topic <- Who is this? idTopic (yeah, ok, I defined this), strlen (length? (idTopic)) == 0

So it compares topic to idTopic and somewhere it uses the length of idTopic and sees if it is zero.

strncmp() compares char arrays. The arguments it needs are pointers to the two arrays to compare and a length to compare.
char* topic is supplied by the callback routine
char* idTopic is part of your code and the topic your comparing to
strlen(idTopic) is the length of the idTopic sting <- note the lower case s in string. This is not the same as String.
It returns a signed number that is zero if the strings match or <> zero depending on where then strings don't match.

Without knowing what the subscribed topics looks like I cannot be sure if what you have is correct.

Thanks for the reply.

Shall sit and study this for a while.

Alas other things are happening and alas I am limited with time allocation.

Just quickly - realised after initial posting - what is the difference between the topic and the idtopic when talking to MQTT?

Because, ok, I get that in the code:

if (strncmp(topic, idTopic, strlen(idTopic)) == 0)

I am comparing the "topic" (which I supplied) to the "idtopic" which is what MQTT gets, I think/thought I see/saw a topic also.

Somewhere in your code you will have subscribed to the idTopic

client.subscribe(idTopic);              // Subscribe to MQTT input

The callback code that is called when an MQTT message arrives

void callback(char* topic, byte * data, unsigned int length)// Callback for subscribed MQTT topics

supplies the 'topic' as a pointer to a char array of the received MQTT message. It also supplies a pointer to a byte array called 'data' that contains the MQTT message payload and a 'length' that says how large the 'data' array is.
The callback handles all subscribed messages so you need the strncmp() to determine what topic your dealing with and then extra code to deal with the payload data.