Getting data from JSON MQTT Payload into variables

Hi All
I've got a Home Assistant automation which sends 2 values to a MQTT payload.
This is getting received by my ESP32 no problem... but I can't seem to use those variables...

This output is give:
{ state: off, lightlevel: 1500!�?
0
0

by the following code


void callback(char* topic, byte* payload, unsigned int length) {
  char messageBuffer[30];
  memcpy(messageBuffer, payload, length);
  messageBuffer[length] = '\0';

StaticJsonDocument <256> doc;
deserializeJson(doc,messageBuffer);
 
 Serial.println(messageBuffer);
 Serial.println(state);
 Serial.println(lightlevel);
}

What I want to be able to do is something like

if (state == true){

blah blah 

}

Any ideas how to get 2 simple varaibles to equal
state = off
lightlevel = 1500

so that they are useable?

Thanks - very new to this.

that might be too short...

why do you want to duplicate the payload, you already have the payload to play with.

you should also check the value returned by deserializeJson()

Do you mean messageBuffer[length-1] = '\0'; It may help avoid corrupting anything near messageBuffer. Anyway, from your print out, it looks like messageBuffer does not contain valid JSON.

EDIT
and, as already pointed out, 30 does seem a bit short if you also want the closing brace '}' possibly with a preceding space :

         1111111111222222222233333333334   
1234567890123456789012345678901234567890
{ state: off, lightlevel: 1500!�?

Thanks to you both...
I've upped the 30 to 40 and now get this output... so that's a step nearer!!

{ state: off, lightlevel: 1500 }
0
0

How do I output the value of deserializeJson() ??? I tried

Serial.println(doc);

but that just throws an error and won't compile...

Sorry for such silly questions - I've been a PHP / DB programmer for years, but this is my first dabble with this.

assuming your JSON is like this

{
  "state": "off",
  "lightlevel": 1500
}

then try

void callback(char* topic, byte* payload, unsigned int length) {
  StaticJsonDocument <256> doc;
  DeserializationError error = deserializeJson(doc, (char*) payload, length);

  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());
  } else {
    const char* state = doc["state"];
    int lightlevel = doc["lightlevel"];
    Serial.println(state);
    Serial.println(lightlevel);
  }
}

Note that 256 is probably way too much for the size of your Json doc.

first off you were absolutely right about the JSON not being properly formed.... The payload is actually being sent by a Home Assistant automation and there were " " missing... I've added them and the data is coming through now and I'm not getting the 0 results....

where the XXXXXXXX is below, what could I put that creates the type of string variable that I can use in my IF statement at the end??

void callback(char* topic, byte* payload, unsigned int length) {
  char messageBuffer[50];
  memcpy(messageBuffer, payload, length);
  messageBuffer[length] = '\0';

StaticJsonDocument <256> doc;
deserializeJson(doc,messageBuffer);

**XXXXXXXX** state = doc["state"];
int lightlevel = doc["lightlevel"];
 
 Serial.println(messageBuffer);
 Serial.println(state);
 Serial.println(lightlevel);

  if (state == "on"){

I've put

const char* state = doc["state"];

but the IF statement doesn't seem to run....

got it by using a String

String state = doc["state"];

All now working as expected.... Thanks very much for your time and effort with me!!!

This came too late but gives you another alternative:

**XXXXXXXX** state = doc["state"];
. . .
if (state == "on"){

you could try String state . . .

or keep it as const char * then use strcmp() to test if its value is on

if you go for c-strings, stick to c-strings functions, don't generate a String which will duplicate the value in memory... You'll eat up RAM for nothing

void callback(char* topic, byte* payload, unsigned int length) {
  StaticJsonDocument <256> doc;
  DeserializationError error = deserializeJson(doc, (char*) payload, length);

  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());
  } else {
    const char* state = doc["state"];
    int lightlevel = doc["lightlevel"];
    Serial.println(state);
    Serial.println(lightlevel);
    if (strcmp(state, "on") == 0) { // see https://cplusplus.com/reference/cstring/strcmp/
      // we got state "on"
      ....
    } else {
      // we (likely) got state "off"
      ....
    }
  }
}

really also drop the idea of making a copy of the buffer....

it's useless and costly and error prone as you don't know if length is >= 50 then you'll introduce a bug in your code.

The buffer is already available through the payload pointer, just use it.

1 Like