How to parse multiple payloads to another functions from mqtt callback()

Hello,
i’m working on my meteo station monitor project. It collects information from various sensors around my house like pool temp, room temp, solar panel, and etc., using mqtt and displays it on my e-ink display. I have subscribe to multiple mqtt topics, but i don’t know how to parse payloads which is strings like “open”, “close” or floats from callback() function. I know my arduino programing skills are poor, but i hope i will understand the solution if someone could explain where is my mistakes here.

Here is the code with callback() function and parse topic and payload to another mqtt_procesas() function to further pass it to e-ink display print function.

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


  Serial.print("Message arrived in topic: ");


  Serial.println(topic);


  Serial.print("Message:");


  for (int i = 0; i < length; i++) {


    Serial.print((char)payload[i]);


  }

  Serial.println();


  Serial.println("-----------------------");


 mqtt_procesas(topic, payload);
}


void mqtt_procesas(char* topic, byte* payload) {
String msg;
String strTopic;


  strTopic = String((char*)topic);
  if(strTopic == programos_testas)


    {


    msg = String((char*)payload);


    Serial.print("mqtt_proceso pranesimas yra: ");


        Serial.println(msg);
}
}

Here is Serial monitor output:

12:39:31.066 -> IP address: 
12:39:31.066 -> 192.168.2.213
12:39:31.166 -> Connecting to MQTT...
12:39:31.681 -> connected
12:39:31.681 -> Pradedame prenumeruoti topikus: 
12:39:31.681 -> programos/testas
12:39:31.958 -> Message arrived in topic: skaidiskes/meteo/siltnamis/temperatura
12:39:31.958 -> Message:-12.10
12:39:31.958 -> -----------------------
12:39:31.958 -> Message arrived in topic: skaidiskes/namai/spyna
12:39:31.958 -> Message:UZRAKINTA
12:39:31.958 -> -----------------------
12:39:31.995 -> Message arrived in topic: programos/testas
12:39:31.995 -> Message:pranesimas
12:39:31.995 -> -----------------------
12:39:31.995 -> mqtt_proceso pranesimas yra: pranesimasKINTAratura

See the last line in the payload is “pranesimasKINTAratura” instead of “pranesimas”. I don’t know how to solve this problem. I need to receive exact payload phrase to pass it to e-ink display print function.

well you pass 'payload' as an argument here :void callback(char* topic, byte* payload, unsigned int length) { and you print every character in the buffer (of which i don't know the size) but somehow, the way the buffer gets filled up it doesn't get null-terminated, so all text that was longer than the new message is still in there. Of course when it is declared the buffer is full of null terminators. So, addpayload[length] = '\0';before you start processing, actually just after you fill the buffer with a new message. Shows us the function that does that if it is not clear what i mean.

Thank you!!! Two days i could not find a solution for my problem, which was so stupid simple :frowning: Now code work like intended.

Correct code:

void callback(char* topic, byte* payload, unsigned int length) {
 payload[length] = '\0';
  Serial.print("Message arrived in topic: ");
  Serial.println(topic);
 
  Serial.print("Message:");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }

  Serial.println();
  Serial.println("-----------------------");
 
 mqtt_procesas(topic, payload);
 
}

void mqtt_procesas(char* topic, byte* payload) {

String msg;
String strTopic;

  strTopic = String((char*)topic);
  if(strTopic == programos_testas)
    {
      
    msg = String((char*)payload);
    Serial.print("mqtt_proceso pranesimas yra: ");
        Serial.println(msg);
}
}

Serial monitor output:

13:17:54.873 -> Message arrived in topic: skaidiskes/meteo/siltnamis/temperatura
13:17:54.873 -> Message:-8.80
13:17:54.873 -> -----------------------
13:17:54.873 -> Message arrived in topic: skaidiskes/namai/spyna
13:17:54.873 -> Message:ATRAKINTA
13:17:54.873 -> -----------------------
13:17:54.873 -> Message arrived in topic: programos/testas
13:17:54.873 -> Message:MESSAGE
13:17:54.873 -> -----------------------
13:17:54.873 -> mqtt_proceso pranesimas yra: MESSAGE

payload arrive and parsed to other function succcesfuly :slight_smile:

Great to be of help. Still i maintain that the issue is in the function that fills the buffer initially, that is where the null-terminator should be added. This is important once you start using that function to receive data, and pass the results to a different function.

I’m not quite sure what you want to say, but i expect that my payload parse issue is related to it. I have added “return msg;” to the end of the code:

void callback(char* topic, byte* payload, unsigned int length) {
 payload[length] = '\0';
  Serial.print("Message arrived in topic: ");
  Serial.println(topic);
 
  Serial.print("Message:");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }

  Serial.println();
  Serial.println("-----------------------");
  
mqtt_procesas(topic, payload);
}


String mqtt_procesas(char* topic, byte* payload) {

String msg;
String strTopic;

  strTopic = String((char*)topic);
  if(strTopic == programos_testas)
    {
      
    msg = String((char*)payload);
    Serial.print("mqtt_proceso pranesimas yra: ");
        Serial.println(msg);
        return msg;
        
}
}

But then i’m trying to catch this value into void paveiksliukas() function, arduino return me an error “too few arguments to function ‘String mqtt_procesas(char*, byte*)’”

This is my display print function:

void paveiksliukas() 
{
  
  display.setFullWindow();  // Set full window mode, meaning is going to update the entire screen
  display.firstPage();  // Tell the graphics class to use paged drawing mode
  do
  { 
    // Put everything you want to print in this screen:
    
    // Print image:
    display.fillScreen(GxEPD_WHITE);  // Clear previous graphics to start over to print new things.
    // Format: (POSITION_X, POSITION_Y, IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT, COLOR)
    // Color options are GxEPD_BLACK, GxEPD_WHITE, GxEPD_RED
    display.drawBitmap(0,0, gImage_EPD_mano_800x600h, 800,600, GxEPD_BLACK);  // Print YouTube logo - Black part (POSITION_X, POSITION_Y, IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT, COLOR)
    //display.drawBitmap(0,0, yt2, 200,45, GxEPD_BLACK);  // Print YouTube logo - Red part (POSITION_X, POSITION_Y, IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT, COLOR)
    
                                          // In the color part we put that if the display supports red color then use it. If not, use black.
    
    // Print Subscribers image:
    float calculated;
    float Body_Data_Site_E_Day;
    String dayStamp;
    String timeStamp;
    String msg;

//    siltnamisMsg=mqtt_siltnamis_temp();
    Body_Data_Site_E_Day=solar_http();
    dayStamp=ntp();
    timeStamp=ntp_time();
    msg=mqtt_procesas();
    
    calculated=Body_Data_Site_E_Day/1000;
    
    // Print text - "3,456" (example number of subscribers):
    display.setTextColor(GxEPD_BLACK);  // Set color for text
    display.setFont(&Dialog_plain_112);  // Set font
    display.setCursor(450, 370);  // saules kwh pozicija (x,y)
    display.print(calculated);  // Print some text

    display.setCursor(240, 370);  // svetaines temp pozicija (x,y)
    display.print("30");  // Print some text

    display.setCursor(215, 180);  // lauko temp pozicija (x,y)
    display.print("-24");  // Print some text

    display.setCursor(435, 180);  // siltnamio temp pozicija (x,y)
    display.print(msg);  // Print some text

    display.setCursor(625, 180);  // baseino temp pozicija (x,y)
    display.print("20");  // Print some text

    display.setFont(&FreeMono9pt7b);
    display.setCursor(80, 587);  // atnaujinta (x,y)
    display.print(dayStamp);  // Print some text

    display.setCursor(192, 587);  // atnaujinta (x,y)
    display.print("--");  // Print some text
    
    display.setCursor(220, 587);  // atnaujinta (x,y)
    display.print(timeStamp);  // Print some text


    display.setCursor(380, 587);  // baterija (x,y)
    display.print("60 %");  // Print some text

    display.setFont(&FreeMonoBold12pt7b);
    display.setCursor(650, 587);  // lauko durys (x,y)
    display.print("ATRAKINTA");  // Print some text

  }
  while (display.nextPage());  // Print everything we set previously
  // End of screen 2
}

paveiksliukas()

this probably means something in your language…
Anyway before we go into other issues, we need to see the function that is ‘calling’ callback(),
and the function that fills up ‘payload’.
The error msg doesn’t make sense, are you sure that is the only error you are getting ? and why are you using a byte* for payload ?

An MQTT callback that just extracts the published topic/payload and passes topic/payload on to a parser.

void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
  xSemaphoreTake( sema_MQTT_Parser, portMAX_DELAY);
  str_eTopic = topic;
  int i = 0;
  for ( i; i < length; i++)
  {
    strPayload[i] = ((char)payload[i]);
  }
  strPayload[i] = NULL;
  //log_i( "topic %s payload %s" ,str_eTopicPtr, strPayloadPtr );
  xSemaphoreGive ( sema_MQTT_Parser );
  xEventGroupSetBits( eg, evtParseMQTT ); // trigger tasks
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////

This code is the parser

void fparseMQTT( void *pvParameters )
{
  xSemaphoreGive ( sema_MQTT_Parser );
  for (;;)
  {
    xEventGroupWaitBits (eg, evtParseMQTT, pdTRUE, pdTRUE, portMAX_DELAY ); //
    xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
    mqttOK = 0;
    xSemaphoreGive( sema_mqttOK );
    xSemaphoreTake( sema_MQTT_Parser, portMAX_DELAY );
    if ( str_eTopic == topicOutsideTemperature )
    {
      oTemperature = String(strPayload).toFloat();
    }
    if ( (String)str_eTopic == topicOutsideHumidity )
    {
      oHumidity = String(strPayload).toFloat();
    }
    if ( (String)str_eTopic == topicAQIndex )
    {
      oIAQ = String(strPayload).toFloat();
    }
    if ( String(str_eTopic) == topicOutsidePressure )
    {
      oPressure = String(strPayload).toFloat();
    }
    // clear pointer locations
    memset( strPayload, '\0', 300 );
    str_eTopic = ""; //clear string buffer
    xSemaphoreGive( sema_MQTT_Parser );
  }
} // void fparseMQTT( void *pvParameters )

Hello,
here is my complete code (see atachment), maybe it will help to see big picture. I realy don’t know why use byte*, but it was as standard expression.

MyCode.txt (9.16 KB)

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.