ESP8266: Parsing JSON

Introduction

In this post, we will create a simple program to parse a JSON string simulating data from a sensor and print it to the serial port. We assume that the ESP8266 libraries for the Arduino IDE were previously installed. You can check how to do it here.

In order to avoid having to manually decode the string into usable values, we will use the ArduinoJson library, which provides easy to use classes and methods to parse JSON. The GitHub page of the library can be consulted here.

This very useful library allows both encoding and decoding of JSON, is very efficient and works on the ESP8266. It can be obtained via library manager of the Arduino IDE, as shown in figure 1.

Installation of the ArduinoJSON library on the Arduino IDE library manager.
Figure 1 – Installation via Arduino IDE library manager.

Setup

First of all, we will include the library that implements the parsing functionality.

#include "ArduinoJson.h"

Since this library has some tricks to avoid problems while using it, this post will just show how to parse a locally created string, and thus we will not use WiFi functions. So, we will just start a Serial connection in the setup function.

void setup() {
 
  Serial.begin(115200);
  Serial.println();  //Clear some garbage that may be printed to the serial console
 
}

Main loop

On our main loop function, we will declare our JSON message, that will be parsed. The \ characters are used to escape the double quotes on the string, since JSON names require double quotes [1].

char JSONMessage[] ="{\"SensorType\":\"Temperature\", \"Value\": 10}";

This simple structure consists on 2 name/value pairs, corresponding to a sensor type and a value for that sensor. For the sake of readability, the structure is shown bellow without escaping characters.

{
"SensorType" : "Temperature",
"Value" : 10
}

Important: The JSON parser modifies the string [2] and thus its content can’t be reused. That’s the reason why we declare the string inside the main loop and not as a global variable, even though its content is always the same in this program. This way, the variable is local and when the main loop function returns, it is freed and a new variable is allocated again in the next call to the loop function. Check here some definitions about variable scopes.

Then, we need to declare an object of class StaticJsonBuffer. It will correspond to a pre-allocated memory pool to store the object tree and its size is specified in a template parameter (the value between <> bellow), in bytes [3].

StaticJsonBuffer<300> JSONBuffer;

In this case, we declared a size of 300 bytes, which is more than enough for the string we want to parse. The author of the library specifies here two approaches on how to determine the buffer size. Personally, I prefer to declare a buffer that has enough size for the expected message payload and check for errors in the parsing step.

The library also supports dynamic memory allocation but that approach is discouraged [4]. Here we can check the differences between static and dynamic JsonBuffer.

Next, we call the parseObject method on the StaticJsonBuffer object, passing the JSON string as argument. This method will return a reference to an object of class JsonObject [5]. You can check here the difference between a pointer and a reference.

JsonObject& parsed= JSONBuffer.parseObject(JSONMessage);

To check if the JSON was successfully parsed, we can call the success method on the JsonObject instance [6].

if (!parser.success()) {
 
  Serial.println("Parsing failed");
  return;
 
}

After that, we can use the subscript operator to obtain the parsed values by their names [7]. Check here some information about the subscript operator. In other words, this means that we use square brackets and the the names of the parameters to obtain their values, as shown bellow.

const char * sensorType = parsed["SensorType"];
int value = parsed["Value"];

The whole main function is shown bellow. We included some extra prints to separate each iteration of the loop function and to show how the original string is modified when parsed. We need to print it char by char because the parser introduces \0 characters and thus, if we used Serial.println(JSONMessage), we would just see the content until the first \0 character.

void loop() {
 
  Serial.println("——————");
 
  char JSONMessage[] = " {\"SensorType\": \"Temperature\", \"Value\": 10}"; //Original message
  Serial.print("Initial string value: ");
  Serial.println(JSONMessage);
 
  StaticJsonBuffer<300> JSONBuffer;   //Memory pool
  JsonObject& parsed = JSONBuffer.parseObject(JSONMessage); //Parse message
 
  if (!parsed.success()) {   //Check for errors in parsing
 
    Serial.println("Parsing failed");
    delay(5000);
    return;
 
  }
 
  const char * sensorType = parsed["SensorType"]; //Get sensor type value
  int value = parsed["Value"];                                         //Get value of sensor measurement
 
  Serial.println(sensorType);
  Serial.println(value);
 
  Serial.print("Final string value: ");
 
  for (int i = 0; i < 31; i++) { //Print the modified string, after parsing
 
    Serial.print(JSONMessage[i]);
 
  }
 
  Serial.println();
  delay(5000);
 
}

Testing the code

To test the code, simply compile it and upload it to your ESP8266. After that, open the Arduino IDE serial monitor. Figure 2 illustrates the result printed to the serial monitor.

Output of the JSON parse program in the Arduino IDE serial console.
Figure 2 – Output of the program in the Arduino IDE serial console.

As seen by the previous explanation, this library has some particularities that we need to take in consideration when using it, to avoid unexpected problems. Fortunately, the GitHub page of this library is very well documented, and thus here is a section describing how to avoid pitfalls.

Also, I strongly encourage you to check the example programs that come with the installation of the library, which are very good for understanding how it works.

Final notes

This post shows how easily is to parse JSON in the ESP8266. Naturally, this allows to change data in a well known structured format that can be easily interpreted by other applications, without the need for implementing a specific protocol.

Since microcontrollers and IoT devices have many resource constraints, JSON poses much less overhead than, for example, XML, and thus is a very good choice.

Nevertheless, we need to keep in mind that for some intensive applications, even JSON can pose an overhead that is not acceptable, and thus we may need to go to byte oriented protocols. But, for simple applications, such as reading data from a sensor and sending it to a remote server or receiving a set of configurations, JSON is a very good alternative.

References

[1] http://www.w3schools.com/json/json_syntax.asp

[2] https://arduinojson.org/v5/faq/why-is-the-input-modifed/

[3] https://arduinojson.org/v5/doc/memory/

[4] https://arduinojson.org/v5/faq/how-to-determine-the-buffer-size/

[5] https://arduinojson.org/v5/api/jsonbuffer/parseobject/

[6] https://arduinojson.org/v5/api/jsonobject/success/

[7] https://arduinojson.org/v5/doc/decoding/

Technical details

  • ESP8266 libraries: v2.3.0.
  • ArduinoJson library: v5.1.1.

18 thoughts on “ESP8266: Parsing JSON”

  1. First, thank you so much for this tutorial, but i got this problem..
    I’m using nodemcu v3 and connect to my sites, and i used this command :
    ———————————————————————
    client.print(String(“GET “) + url + ” HTTP/1.1\r\n” +
    “Host: ” + host + “\r\n” +
    “Connection: close\r\n\r\n”);
    ———————————————————————

    And got data from my serial like this :

    ———————————————————————
    HTTP/1.1 200 OK
    Date: Fri, 06 Oct 2017 08:18:41 GMT
    Content-Type: application/json
    Content-Length: 47
    Connection: close
    Last-Modified: Sun, 24 Sep 2017 05:35:32 GMT
    Accept-Ranges: bytes
    Server: awex
    X-Xss-Protection: 1; mode=block
    X-Content-Type-Options: nosniff
    X-Request-ID: 134dcf4b10038706b4dbc3ccdcfea12e

    {“value”:[“1″,”0″,”0″,”1″,”0″,”0″,”0″,”1″,”1”]}
    closing connection
    ———————————————————————
    how i just parsing my json only? i succeed parsing using subString, but those header always changes and i must changed subString every i don’t get any data…. how to parsing just JSON data for easier?

    1. Hi! Thanks 🙂 Well it seems like you are using sockets to build your HTTP request. If doing so, it will be difficult to parse the result because, as you mentioned, the header changes.

      My recommendation is that you use the ESP8266 HTTP Client API to make the GET requests:
      https://techtutorialsx.com/2016/07/17/esp8266-http-get-requests/

      It gives you access to the payload by calling a simple function, which you can then parse if it is JSON.

      Hope it helps.

      Best regards,
      Nuno Santos

  2. First, thank you so much for this tutorial, but i got this problem..
    I’m using nodemcu v3 and connect to my sites, and i used this command :
    ———————————————————————
    client.print(String(“GET “) + url + ” HTTP/1.1\r\n” +
    “Host: ” + host + “\r\n” +
    “Connection: close\r\n\r\n”);
    ———————————————————————
    And got data from my serial like this :
    ———————————————————————
    HTTP/1.1 200 OK
    Date: Fri, 06 Oct 2017 08:18:41 GMT
    Content-Type: application/json
    Content-Length: 47
    Connection: close
    Last-Modified: Sun, 24 Sep 2017 05:35:32 GMT
    Accept-Ranges: bytes
    Server: awex
    X-Xss-Protection: 1; mode=block
    X-Content-Type-Options: nosniff
    X-Request-ID: 134dcf4b10038706b4dbc3ccdcfea12e
    {“value”:[“1″,”0″,”0″,”1″,”0″,”0″,”0″,”1″,”1”]}
    closing connection
    ———————————————————————
    how i just parsing my json only? i succeed parsing using subString, but those header always changes and i must changed subString every i don’t get any data…. how to parsing just JSON data for easier?

    1. Hi! Thanks 🙂 Well it seems like you are using sockets to build your HTTP request. If doing so, it will be difficult to parse the result because, as you mentioned, the header changes.
      My recommendation is that you use the ESP8266 HTTP Client API to make the GET requests:
      https://techtutorialsx.com/2016/07/17/esp8266-http-get-requests/
      It gives you access to the payload by calling a simple function, which you can then parse if it is JSON.
      Hope it helps.
      Best regards,
      Nuno Santos

  3. Pingback: ESP32 Espruino: Deserializing JSON | techtutorialsx

  4. Pingback: ESP32 Espruino: Deserializing JSON | techtutorialsx

  5. Hi, First of all. Thanks for this very good description.

    One thing. Isn’t there a typo? pleas correct me if I understand something wrong.

    if (!parser.success()) { // <– should be parsed with d

    Serial.println("Parsing failed");
    return;

    }

    1. Hi!

      You’re welcome, thanks for the feedback 🙂

      Where did you find the typo? There it is just handling the case when the parsing procedure fails 🙂

      Best regards,
      Nuno Santos

  6. Hi, First of all. Thanks for this very good description.
    One thing. Isn’t there a typo? pleas correct me if I understand something wrong.
    if (!parser.success()) { // <– should be parsed with d
    Serial.println("Parsing failed");
    return;
    }

    1. Hi!
      You’re welcome, thanks for the feedback 🙂
      Where did you find the typo? There it is just handling the case when the parsing procedure fails 🙂
      Best regards,
      Nuno Santos

Leave a Reply to antepherCancel reply

Discover more from techtutorialsx

Subscribe now to keep reading and get access to the full archive.

Continue reading