Unit H - ESP32 Wireless

43. HTTP Client, JSON and Cloud APIs

Parse JSON as a client, then build an outdoor condition lamp driven by a live temperature field.

Estimated time 4 hours

Learning outcomes

  • Contrast HTTP client vs server roles
  • Read JSON types, nesting and arrays
  • Parse httpbin for discovery, then a live temperature field
  • Drive an LED from a numeric JSON value
  • Check HTTP status and DeserializationError before acting

Parts and preparation

ESP32 DevKit, USB, LED on GPIO 2, ArduinoJson by Benoit Blanchon, internet-capable 2.4 GHz WiFi.

Before power: inspect wiring, confirm supply voltage and ensure all connected circuits share GND.

Libraries for this lesson

In Arduino IDE 2 open Tools → Manage Libraries…. Search by the Library Manager name and install the package by the exact author below. Similar names from other authors can use different APIs and will break the example.

IncludeLibrary Manager nameAuthorInstall note
WiFi.hWiFiEspressifBuilt into the esp32 Arduino core.
HTTPClient.hHTTPClientEspressifBuilt into the esp32 Arduino core.
ArduinoJson.hArduinoJsonBenoit BlanchonInstall ArduinoJson by Benoit Blanchon via Library Manager.
HTTP Client, JSON and Cloud APIs instructional connection diagram

Project: Outdoor condition lamp

Build a lamp that reflects outdoor temperature from a free weather API (Open-Meteo over plain HTTP). LED on means milder than your threshold; off means cooler - a simple outdoor condition indicator.

Sketch 1 discovers nested JSON on httpbin (no API key). Sketch 2 fetches current.temperature_2m and drives the lamp.

ESP32 HTTP GET JSON parse to control an LED
Client GET, parse a number, act on GPIO.

Client versus server

Lesson 42 was server (browsers call you). Here the ESP32 is the client calling a remote host.

GET, POST and status codes

GET reads a resource. Always require status 200 before parsing - error pages are often HTML, not JSON.

CodeLab meaning
200OK - parse the body
404Wrong URL
-1Transport fail (DNS/WiFi/blocked)

What JSON is

JSON uses objects { }, arrays [ ], double-quoted strings, numbers, true/false/null. Nested paths: doc["slideshow"]["author"]. Arrays: doc["slides"][0]["title"].

TypeExample
string"Yours Truly"
number21.5
object{ "temp": 21.5 }
array[1, 2, 3]

ArduinoJson workflow

HTTP 200 -> getString -> deserializeJson -> check error -> read fields with | defaults -> act. ArduinoJson 7 uses JsonDocument.

HTTPS note

Many APIs are HTTPS-only. This course stays on plain HTTP (httpbin + Open-Meteo HTTP) so certificates do not hide the JSON lesson.

Wiring and safe build sequence

  1. GPIO 2 -> resistor -> LED; cathode -> GND
  2. USB power; WiFi credentials in sketch
Power rule: switch off before moving wires. Arduino I/O pins are control signals; high-current loads require a driver and suitable external supply.

Worked sketch 1: Learn JSON paths on httpbin

Download .ino sketch

What this sketch is for: Discovery: GET httpbin.org/json, parse nested author and slides[0].title, LED on means parse OK.

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* url = "http://httpbin.org/json";
const int ledPin = 2;

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    digitalWrite(ledPin, LOW);
    delay(2000);
    return;
  }

  HTTPClient http;
  http.begin(url);
  int code = http.GET();
  Serial.printf("HTTP %d\n", code);

  bool ok = false;
  if (code == 200) {
    String body = http.getString();
    JsonDocument doc;
    DeserializationError err = deserializeJson(doc, body);
    if (!err) {
      const char* author = doc["slideshow"]["author"] | "unknown";
      const char* slide0 = doc["slideshow"]["slides"][0]["title"] | "?";
      Serial.print("author: ");
      Serial.println(author);
      Serial.print("slide[0]: ");
      Serial.println(slide0);
      ok = true;
    } else {
      Serial.println(err.c_str());
    }
  }

  digitalWrite(ledPin, ok ? HIGH : LOW);
  http.end();
  delay(15000);
}

How the code works

  1. httpbin needs no API key - good for path practice.
  2. LED HIGH means parse success, not weather yet.

Worked sketch 2: Outdoor condition lamp

Download .ino sketch

What this sketch is for: Fetch Open-Meteo current temperature over HTTP, print it, and light the lamp when temperature_2m is at or above 15 C. Change lat/lon for your site. If the URL is blocked, keep sketch 1 skills and swap host when your network allows. Match the breadboard layout below before upload.

Breadboard layout for ESP32 condition lamp: LED with series resistor on GPIO 2
Breadboard for sketch 2: LED with series resistor on GPIO 2 to GND. Click to enlarge.
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// Plain HTTP Open-Meteo sample (London). Edit latitude/longitude for your location.
const char* url =
  "http://api.open-meteo.com/v1/forecast?latitude=51.5&longitude=-0.12&current=temperature_2m";

const int ledPin = 2;
const float mildC = 15.0;

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    digitalWrite(ledPin, LOW);
    delay(2000);
    return;
  }

  HTTPClient http;
  http.begin(url);
  int code = http.GET();
  Serial.printf("HTTP %d\n", code);

  bool lamp = false;
  if (code == 200) {
    String body = http.getString();
    JsonDocument doc;
    if (!deserializeJson(doc, body)) {
      float t = doc["current"]["temperature_2m"] | -100.0;
      Serial.print("Outdoor C: ");
      Serial.println(t);
      lamp = (t >= mildC);
    } else {
      Serial.println("JSON parse failed");
    }
  }

  digitalWrite(ledPin, lamp ? HIGH : LOW);
  Serial.println(lamp ? "Condition lamp ON (mild+)" : "Condition lamp OFF");
  http.end();
  delay(20000);
}

How the code works

  1. Path current.temperature_2m is a nested number field.
  2. mildC threshold is a teaching default - adjust for your climate demo.
  3. Prefer HTTP for this lab; many other weather APIs need HTTPS + keys.
  4. Build from the breadboard photo: condition lamp LED on GPIO 2.

Test and record evidence

Expected result: Sketch 1: HTTP 200, author/slide lines, LED on when parse works. Sketch 2: prints Outdoor C and the condition lamp tracks the mild threshold.

Practical evidence checklist

Common faults and checks
  • HTTP -1: DNS, captive portal, or blocked outbound HTTP.
  • JsonDocument errors: install current ArduinoJson by Benoit Blanchon.
  • Open-Meteo blocked: try another network or fall back to sketch 1 paths.
Extension challenge: Map temperature bands to NeoPixel colours (lesson 39) instead of a single LED.

Check your understanding

Q1. What product is sketch 2?

Show answer

An outdoor condition lamp driven by live temperature JSON.

Q2. Client or server here?

Show answer

Client - ESP32 calls a remote host.

Q3. Name three JSON types

Show answer

string, number, object (or array/bool/null).

Q4. How to read nested temperature_2m?

Show answer

doc["current"]["temperature_2m"].

Q5. Why check HTTP status first?

Show answer

Error pages may not be JSON.

Q6. What library parses JSON?

Show answer

ArduinoJson by Benoit Blanchon.

Q7. Why stay on HTTP in this lab?

Show answer

Avoid certificate setup while learning JSON.

Q8. What does LED mean in sketch 2?

Show answer

Temperature at or above the mild threshold.