ESP8266 resp json api

It happens quite often that it is necessary to invoke Rest JSON API using ESP8266. This is the case where it is necessary to call some Rest JSON API to integrate services using ESP8266.

Problem: How to invoke Rest JSON API using ESP8266 to integrate external services. I have a Rest JSON API exposed by an external service that I want to integrate with my ESP8266, what do I have to do?

Scenario: the ESP8266 has to invoke Web API, Rest API to send and receive data. For example, the ESP8266 has to invoke a weather service (such as ClimaCell) to get weather information. Therefore, this is a common scenario and it is useful to understand how to invoke HTTPS Rest API using ESP8266

Basically, it is necessary to develop an ESP8266 HTTPS client that handles the Rest JSON API call. We will discover how to do it in the following parts of this tutorial. To better understand the steps to follow when invoking a Rest JSON API from an ESP8266, we will use an HTTPS API of ClimaCell that returns the air pollution. We will build a simple ESP8266 HTTPS client that invokes this ClimaCell’s API and parse the JSON result. Using this result, the ESP8266 manages a LEDs strip that uses colors to visualize the air quality.

How to call an HTTPS Rest JSON API from ESP8266

To invoke an HTTPS Rest JSON API from ESP8266, it is necessary to follow these steps:

  • Get the OAuth2 token to have access to the API
  • Develop an ESP8266 HTTPS client
  • Call the JSON API
  • Parse the JSON result

How to get OAuth2 token

Usually, a Rest JSON API uses OAuth2 protocol to manage the authorization process. Before going further in this tutorial, you need to get your token from ClimaCell. You can create an account on ClimaCell that is free for 14-days. When you have created your account, you will get the token to use in the API invocation from ESP8266.

This tutorial assumes you already know about OAuth2, but if you are new to this protocol, you can skip all the protocol’s details and focus your attention on the token. Normally, the Rest JSON client needs to send this token in the HTTP header. We will see later how to do it. You can referer to the provider API documentation to know more about the API.

How to develop an HTTS ESP8266 client

This is an important step. The ESP8266 Rest client will manage all the HTTPS connection details. Therefore, to accomplish this task, we will use the ESP8266 HTTP Library, so that we don’t need to implement all the ESP8266 HTTP client manually.

Connecting the ESP8266 to WiFi

Firstly, the ESP8266 has to connect to the Wifi. I just write down the code without any explanations because it is trivial:

boolean connectWifi() {

  // Let us connect to WiFi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(5000);
    Serial.print(".");
  }

  Serial.println(".......");
  Serial.println("WiFi Connected....IP Address:");
  Serial.println(WiFi.localIP());

  return true;
}

where ssid and password depend on your WiFi.

Connecting to an HTTPS JSON API from ESP8266

While invoking an HTTP API is very simple, invoking an HTTPS API could be quite complex. Unfortunately almost the API available uses the HTTPS protocol. So what do we have to do to implement an ESP8266 Rest Client to invoke and HTTPS API? The code below shows how to do it:

#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>

const char *server = "https://api.climacell.co/v3/weather/realtime";
HTTPClient http;

void loop() {
  Serial.println("Connecting to the HTTP server....");
  std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
  client->setInsecure();
  char apiURL[1024];

  Serial.println("Building URL...");
  sprintf(apiURL, "%s?lat=%f&amp;lon=%f&amp;fields=%s", server, lat,lon, fields );
  
  Serial.printf("API URL=%s\r\n",apiURL);

  if (http.begin(*client, apiURL)) {
    Serial.println("Connected");
    http.addHeader("Accept", "application/json");
    http.addHeader("apikey", API_KEY);

    int code = http.GET();
    Serial.printf("HTTP Code [%d]", code);
    if (code > 0) {
      if (code == HTTP_CODE_OK || code == HTTP_CODE_MOVED_PERMANENTLY) {
        Serial.println("GET OK");
        String payload = http.getString();
        Serial.println(payload);
        Serial.println("...JSON..");
      }
    }
    else {
      Serial.printf("[HTTP] GET... failed, error: %s", http.errorToString(code).c_str());
    }
  }

A few things to notice in the code above:

  • at lines 8 and 9 a simple trick to invoke a Rest JSON API over HTTPS without using the certificate.
  • At line 13, we build the URL to invoke passing the query parameters according to the PM10 API.
  • Line 19 and 20 the ESP8266 HTTPS client passes the OAuth2 token in the header using the key apikey
  • Finally, in line 22 the ESP8266 makes the HTTP request using GET
  • Line 24, we get the response. This response contains the JSON data as the result of the API invocation. We will parse this payload to get the value we are looking for that represents the air quality

How to parse JSON API payload using ESP8266

Generally, once we have invoked the JSON Rest API and we have the payload as the result, we can parse the JSON to extract the data we are looking for.

If the JSON is simple, we can think to parse it manually, but I suggest to use Arduino JSON Library. This library simplifies the process of serialization and deserialization. Let us add the following line at the beginning:

#include <ArduinoJson.h>

Then, it is necessary to define the size of the object that will deserialize the JSON. To do it, it is necessary to know the JSON API response. The JSON below is a payload example:

{
  "lat": 40.7127281,
  "lon": -74.0060152,
  "pm10": {
    "value": 18,
    "units": "µg/m3"
  },
  "observation_time": {
    "value": "2020-01-21T20:56:39.000Z"
  }
}

In the response, there are four objects and one this object has two inner values while the other one has only one value. The dimension we are looking for is:

const int jsonSize = JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(2) 
                     + JSON_OBJECT_SIZE(1);

To parse the JSON response returned by the Rest JSON API invocation using the ESP8266, we need the following code:

double parseJson(String jsonDoc) {
  Serial.println("Parsing JSON...");
  DynamicJsonDocument doc(jsonSize);
  deserializeJson(doc, jsonDoc);
  float value = doc["pm10"]["value"];
  return value;
}

Notice that in line 3, we define a DynamicJsonDocument having the size of the value we have calculated in the step before. This is the JSON parser that we use to deserialize the JSON document. Finally, in line 5, we retrieve the value representing the PM10 concentration. That’s all. We are ready to manage the LEDs color using the value extracted.

How to control LEDs using Rest JSON API

In this last step, we will use air pollution (PM10) to manage a LED strip. In this way, it is possible to visualize the air quality using colors. This step is quite easy and we have covered it several times. The schematic is shown below:

ESP8266 LEDs. How to invoke Rest JSON API using ESP866 to control LEDs

Add the following code to select the LEDs color:

#include <Adafruit_NeoPixel.h>
 
#define PIN D2
#define NUM_LEDS 12

// LEDs
Adafruit_NeoPixel pixelsRing(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

void setLedColor(int range) {
   switch (range) {
      case 0:
        pixelsRing.fill(pixelsRing.Color(0x50,0xF0,0xE6));
        break;
      case 1:
        pixelsRing.fill(pixelsRing.Color(0x50,0xCC,0xAA));
        break;
     case 2:
        pixelsRing.fill(pixelsRing.Color(0xF0,0xE6,0x41));
        break;
     case 3:
        pixelsRing.fill(pixelsRing.Color(0xFA,0x50,0x50));
        break;
      case 4:
        pixelsRing.fill(pixelsRing.Color(0x96,0x00,0x32));
        break;
   }
   pixelsRing.show();
}

void loop() {
 ......
 if (http.begin(*client, apiURL)) {
   Serial.println("Connected");
   http.addHeader("Accept", "application/json");
   http.addHeader("apikey", API_KEY);
 
   int code = http.GET();
   Serial.printf("HTTP Code [%d]", code);
   if (code > 0) {
     if (code == HTTP_CODE_OK || code == HTTP_CODE_MOVED_PERMANENTLY) {
       Serial.println("GET OK");
       String payload = http.getString();
       Serial.println(payload);
       Serial.println("...JSON..");
       double value = parseJson(payload);
       Serial.printf("PM10 Value [%f]\r\n", value);
       if (value < 20)
          setLedColor(0);
       else if (value >= 20 &amp;&amp; value < 35)
          setLedColor(1);
       else if (value >= 35 &amp;&amp; value < 50)
          setLedColor(2);
       else if (value >= 50 &amp;&amp; value < 100)
          setLedColor(3);
       else if (value >= 100)
          setLedColor(4);   
     }
   }
   else {
     Serial.printf("[HTTP] GET... failed, error: %s", http.errorToString(code).c_str());
   }
 }
 
 http.end();
 delay(60 * 1000);
}

Wrapping up….

Finally, at the end of this tutorial, you learned how to develop an ESP8266 Rest Client to invoke a Rest JSON API. This is very useful because it happens quite often we want to integrate an external service that provides a set of API. There are other ways we can use to integrate ESP8266 with external systems. Another interesting way is using MQTT protocol with ESP8266 to publish and subscribe to MQTT channels where data is sent and received.

Through this tutorial, we have explored all the steps we have to follow to call a JSON API.

2 COMMENTS

  1. Goodmorning Francesco:
    Quite a nice post. I am experimenting with the ESP8266. I faced the problem, this device is going to loose the connection to the WLAN. Have you faced this as well?
    Sincerely yours Andreas

LEAVE A REPLY

Please enter your comment!
Please enter your name here