Contact Sales & After-Sales Service

Contact & Quotation

  • Inquire: Call 0086-755-23203480, or reach out via the form below/your sales contact to discuss our design, manufacturing, and assembly capabilities.
  • Quote: Email your PCB files to Sales@pcbsync.com (Preferred for large files) or submit online. We will contact you promptly. Please ensure your email is correct.
Drag & Drop Files, Choose Files to Upload You can upload up to 3 files.

Notes:
For PCB fabrication, we require PCB design file in Gerber RS-274X format (most preferred), *.PCB/DDB (Protel, inform your program version) format or *.BRD (Eagle) format. For PCB assembly, we require PCB design file in above mentioned format, drilling file and BOM. Click to download BOM template To avoid file missing, please include all files into one folder and compress it into .zip or .rar format.

ArduinoJSON: Parsing & Creating JSON Data

After integrating JSON communication into dozens of production IoT devices, I’ve learned that the ArduinoJSON library isn’t just convenient—it’s essential for any serious embedded project that needs to talk to web services, APIs, or modern protocols. Whether you’re sending sensor data to the cloud or receiving configuration from a mobile app, mastering ArduinoJSON will save you from reinventing the wheel and help your Arduino devices speak the lingua franca of the modern internet.

Understanding ArduinoJSON and Why It Matters

ArduinoJSON is a C++ library that provides efficient JSON parsing (deserialization) and generation (serialization) for embedded systems. Created by Benoit Blanchon, it’s specifically optimized for the memory and performance constraints of microcontrollers.

JSON (JavaScript Object Notation) has become the de facto standard for data exchange in IoT applications. Every REST API, cloud service, and modern communication protocol uses JSON. Without a robust library, you’d need to write complex string manipulation code that’s error-prone and difficult to maintain.

Why ArduinoJSON Stands Out

In production environments, I’ve found ArduinoJSON superior to alternatives because:

  • Zero dependencies: Works standalone without requiring other libraries
  • Platform independent: Runs on Arduino, ESP8266, ESP32, STM32, and even desktop C++
  • Memory efficient: Uses a pool allocator optimized for microcontroller constraints
  • Header-only: Simple integration without complex build configuration
  • Type safe: Provides compile-time type checking
  • Thoroughly tested: Over 3600 assertions with 99% code coverage

Installation and Setup

Using Arduino Library Manager

The easiest installation method leverages the Arduino IDE’s built-in package management:

  1. Open Arduino IDE
  2. Navigate to Sketch → Include Library → Manage Libraries
  3. Search for “ArduinoJSON”
  4. Click Install on ArduinoJSON by Benoit Blanchon
  5. Restart Arduino IDE

Manual Installation

For development environments or specific versions:

  1. Download from GitHub Repository
  2. Extract to Arduino/libraries/ArduinoJson
  3. Restart Arduino IDE

Version Considerations

VersionRelease DateKey FeaturesCompatibility
Version 72024+Simplified API, better performanceLatest boards
Version 62019-2024Most stable, widely usedAll platforms
Version 5LegacyDeprecated, avoid for new projectsOld projects only

For new projects, use Version 7 or Version 6. This article focuses on Version 6/7 as they share most syntax.

Basic Include Statement

#include <ArduinoJson.h>

void setup() {

  Serial.begin(9600);

  // Your JSON code here

}

Parsing JSON Data (Deserialization)

Deserialization converts JSON strings into structured data that your code can access. This is critical when receiving data from APIs or configuration files.

Basic Deserialization Example

#include <ArduinoJson.h>

void setup() {

  Serial.begin(9600);

  // JSON string to parse

  const char* json = “{\”sensor\”:\”gps\”,\”time\”:1351824120,\”data\”:[48.756080,2.302038]}”;

  // Create document

  JsonDocument doc;

  // Parse JSON

  DeserializationError error = deserializeJson(doc, json);

  // Check for errors

  if (error) {

    Serial.print(“deserializeJson() failed: “);

    Serial.println(error.c_str());

    return;

  }

  // Extract values

  const char* sensor = doc[“sensor”];

  long time = doc[“time”];

  double latitude = doc[“data”][0];

  double longitude = doc[“data”][1];

  // Use the data

  Serial.println(sensor);     // “gps”

  Serial.println(time);        // 1351824120

  Serial.println(latitude, 6); // 48.756080

  Serial.println(longitude, 6);// 2.302038

}

void loop() {

  // Empty

}

Extracting Values with Type Safety

ArduinoJSON provides multiple ways to extract values:

// Implicit conversion (simple but less safe)

const char* sensor = doc[“sensor”];

int value = doc[“number”];

// Explicit conversion with as<T>() (recommended)

const char* sensor = doc[“sensor”].as<const char*>();

int value = doc[“number”].as<int>();

// With default values using pipe operator

const char* sensor = doc[“sensor”] | “unknown”;

int value = doc[“number”] | 0;

// Check if value exists before accessing

if (doc.containsKey(“sensor”)) {

  const char* sensor = doc[“sensor”];

}

Handling Nested JSON Structures

// Complex JSON with nested objects

const char* json = R”({

  “device”: {

    “id”: “ESP32-001”,

    “location”: {

      “lat”: 48.8566,

      “lon”: 2.3522

    }

  },

  “readings”: [

    {“temp”: 22.5},

    {“humidity”: 65}

  ]

})”;

JsonDocument doc;

deserializeJson(doc, json);

// Access nested objects

const char* deviceId = doc[“device”][“id”];

double latitude = doc[“device”][“location”][“lat”];

// Access array elements

double temp = doc[“readings”][0][“temp”];

double humidity = doc[“readings”][1][“humidity”];

Creating JSON Data (Serialization)

Serialization builds JSON strings from your data—essential when sending information to APIs or saving configuration.

Basic Serialization Example

#include <ArduinoJson.h>

void setup() {

  Serial.begin(9600);

  // Create document

  JsonDocument doc;

  // Add values

  doc[“sensor”] = “gps”;

  doc[“time”] = 1351824120;

  doc[“data”][0] = 48.756080;

  doc[“data”][1] = 2.302038;

  // Serialize to Serial

  serializeJson(doc, Serial);

  // Output: {“sensor”:”gps”,”time”:1351824120,”data”:[48.756080,2.302038]}

  Serial.println(); // New line

  // Serialize to String

  String output;

  serializeJson(doc, output);

  Serial.println(output);

  // Pretty print (formatted with indentation)

  serializeJsonPretty(doc, Serial);

}

void loop() {

  // Empty

}

Building Complex JSON Structures

JsonDocument doc;

// Create nested objects

JsonObject device = doc.createNestedObject(“device”);

device[“id”] = “ESP32-001”;

device[“type”] = “sensor”;

JsonObject location = device.createNestedObject(“location”);

location[“lat”] = 48.8566;

location[“lon”] = 2.3522;

// Create nested arrays

JsonArray readings = doc.createNestedArray(“readings”);

JsonObject reading1 = readings.createNestedObject();

reading1[“type”] = “temperature”;

reading1[“value”] = 22.5;

JsonObject reading2 = readings.createNestedObject();

reading2[“type”] = “humidity”;

reading2[“value”] = 65;

// Serialize

serializeJsonPretty(doc, Serial);

/* Output:

{

  “device”: {

    “id”: “ESP32-001”,

    “type”: “sensor”,

    “location”: {

      “lat”: 48.8566,

      “lon”: 2.3522

    }

  },

  “readings”: [

    {

      “type”: “temperature”,

      “value”: 22.5

    },

    {

      “type”: “humidity”,

      “value”: 65

    }

  ]

}

*/

Memory Management: Critical for Embedded Systems

Understanding memory allocation in ArduinoJSON is crucial for production stability. Improper sizing causes crashes, while oversizing wastes precious RAM.

JsonDocument Types Comparison

FeatureJsonDocument (v7)StaticJsonDocument (v6)DynamicJsonDocument (v6)
Memory LocationHeapStackHeap
SpeedFastFastestFast
FlexibilityAuto-growsFixed sizeFixed size
Use CaseMost projectsSmall JSON (<1KB)Large JSON (>1KB)
Stack SafetyYesCan overflowYes
Recommended ForVersion 7 projectsEmbedded with limited heapProjects with larger JSON

Version 6 Memory Management

// StaticJsonDocument – Stack allocation (faster, limited size)

StaticJsonDocument<200> doc; // 200 bytes on stack

// DynamicJsonDocument – Heap allocation (flexible, more memory)

DynamicJsonDocument doc(1024); // 1024 bytes on heap

Version 7 Simplified Approach

// Version 7 uses just JsonDocument (automatically manages memory)

JsonDocument doc;

// It dynamically allocates as needed

doc[“sensor”] = “gps”;

doc[“data”][0] = 48.7;

doc[“data”][1] = 2.3;

Calculating Required Capacity

The ArduinoJSON Assistant (arduinojson.org/v6/assistant) is your best friend for sizing:

Step 1: Paste your sample JSON Step 2: Select your board Step 3: Get exact memory requirements

Manual Calculation (Version 6):

// For objects

const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 100;

StaticJsonDocument<capacity> doc;

Memory Usage Best Practices

// GOOD – Short-lived local variable

void sendSensorData() {

  JsonDocument doc;

  doc[“temp”] = readTemperature();

  doc[“humidity”] = readHumidity();

  String output;

  serializeJson(doc, output);

  sendToServer(output);

  // doc destroyed when function exits, memory released

}

// BAD – Global document (wastes memory)

JsonDocument globalDoc; // Occupies memory entire program lifetime

void loop() {

  globalDoc.clear(); // Doesn’t actually free memory!

  globalDoc[“data”] = readSensor();

  // Memory stays allocated even when not needed

}

Checking Memory Usage

JsonDocument doc;

doc[“sensor”] = “gps”;

doc[“time”] = 1351824120;

// Check current memory usage

size_t memUsed = doc.memoryUsage();

Serial.print(“Memory used: “);

Serial.print(memUsed);

Serial.println(” bytes”);

// Version 6: Check capacity

size_t cap = doc.capacity();

Serial.print(“Capacity: “);

Serial.print(cap);

Serial.println(” bytes”);

Real-World Applications and Examples

REST API Client (ESP32/ESP8266)

#include <WiFi.h>

#include <HTTPClient.h>

#include <ArduinoJson.h>

const char* ssid = “YourWiFi”;

const char* password = “YourPassword”;

void setup() {

  Serial.begin(115200);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(1000);

    Serial.println(“Connecting to WiFi…”);

  }

  Serial.println(“Connected!”);

  // Make HTTP GET request

  HTTPClient http;

  http.begin(“http://api.example.com/data”);

  http.GET();

  // Parse response

  JsonDocument doc;

  DeserializationError error = deserializeJson(doc, http.getStream());

  if (!error) {

    const char* value = doc[“result”];

    Serial.println(value);

  }

  http.end();

}

void loop() {

  // Empty

}

Sending Sensor Data to Cloud

void sendToCloud(float temperature, float humidity) {

  HTTPClient http;

  // Create JSON payload

  JsonDocument doc;

  doc[“device_id”] = “ESP32-001”;

  doc[“timestamp”] = millis();

  doc[“temperature”] = temperature;

  doc[“humidity”] = humidity;

  // Serialize to string

  String payload;

  serializeJson(doc, payload);

  // Send POST request

  http.begin(“https://api.example.com/readings”);

  http.addHeader(“Content-Type”, “application/json”);

  int httpCode = http.POST(payload);

  if (httpCode == 200) {

    Serial.println(“Data sent successfully”);

  } else {

    Serial.print(“Error: “);

    Serial.println(httpCode);

  }

  http.end();

}

Configuration File Management

#include <SPIFFS.h>

#include <ArduinoJson.h>

// Save configuration to file

void saveConfig(const char* ssid, const char* password) {

  JsonDocument doc;

  doc[“ssid”] = ssid;

  doc[“password”] = password;

  doc[“mqtt_server”] = “mqtt.example.com”;

  doc[“mqtt_port”] = 1883;

  File configFile = SPIFFS.open(“/config.json”, “w”);

  if (!configFile) {

    Serial.println(“Failed to open config file for writing”);

    return;

  }

  serializeJson(doc, configFile);

  configFile.close();

}

// Load configuration from file

void loadConfig() {

  File configFile = SPIFFS.open(“/config.json”, “r”);

  if (!configFile) {

    Serial.println(“Failed to open config file”);

    return;

  }

  JsonDocument doc;

  DeserializationError error = deserializeJson(doc, configFile);

  configFile.close();

  if (error) {

    Serial.println(“Failed to parse config file”);

    return;

  }

  const char* ssid = doc[“ssid”];

  const char* password = doc[“password”];

  const char* mqtt_server = doc[“mqtt_server”];

  int mqtt_port = doc[“mqtt_port”];

  // Use configuration

  Serial.println(ssid);

}

Common Mistakes and Troubleshooting

Mistake 1: Insufficient Memory Allocation

Symptom: Program crashes or garbage data

Problem:

StaticJsonDocument<50> doc; // Too small!

deserializeJson(doc, largeJsonString); // Will fail

Solution:

// Use ArduinoJSON Assistant to calculate size

StaticJsonDocument<512> doc; // Properly sized

DeserializationError error = deserializeJson(doc, largeJsonString);

if (error) {

  Serial.print(“Error: “);

  Serial.println(error.c_str());

}

Mistake 2: Using Temporary Strings

Problem:

String getJsonString() {

  String json = “{\”temp\”:22.5}”;

  return json;

}

void parseData() {

  JsonDocument doc;

  deserializeJson(doc, getJsonString().c_str()); // DANGER!

  // String destroyed, doc contains dangling pointers

  const char* temp = doc[“temp”]; // CRASH!

}

Solution:

void parseData() {

  String json = getJsonString(); // Keep string alive

  JsonDocument doc;

  deserializeJson(doc, json);

  const char* temp = doc[“temp”]; // Safe

}

Mistake 3: Not Checking for Errors

Problem:

deserializeJson(doc, json); // No error checking

const char* value = doc[“missing”]; // nullptr!

Solution:

DeserializationError error = deserializeJson(doc, json);

if (error) {

  Serial.print(“deserializeJson() failed: “);

  Serial.println(error.c_str());

  return;

}

// Check if key exists

if (doc.containsKey(“value”)) {

  const char* value = doc[“value”];

} else {

  // Handle missing key

  Serial.println(“Key not found”);

}

Mistake 4: Reusing JsonDocument Without Clearing

Problem:

JsonDocument doc;

// First use

doc[“temp”] = 22.5;

serializeJson(doc, Serial);

// Second use – old data still present!

doc[“humidity”] = 65;

serializeJson(doc, Serial);

// Output includes both temp AND humidity

Solution:

JsonDocument doc;

// First use

doc[“temp”] = 22.5;

serializeJson(doc, Serial);

doc.clear(); // Clear before reuse

// Second use

doc[“humidity”] = 65;

serializeJson(doc, Serial); // Only humidity

Performance Optimization Techniques

Use Streams Instead of Strings

// INEFFICIENT – Copies entire JSON to RAM

HTTPClient http;

http.begin(“http://api.example.com/data”);

int httpCode = http.GET();

String payload = http.getString(); // Copies to String

JsonDocument doc;

deserializeJson(doc, payload); // Parses from String

// EFFICIENT – Parses directly from stream

HTTPClient http;

http.begin(“http://api.example.com/data”);

int httpCode = http.GET();

JsonDocument doc;

deserializeJson(doc, http.getStream()); // Direct parsing, no copy

Minimize Memory Footprint

// Choose smallest type that works

StaticJsonDocument<200> doc; // For small JSON

// vs

DynamicJsonDocument doc(4096); // Wastes memory if not needed

// Use filtering for large responses (Version 6+)

StaticJsonDocument<200> filter;

filter[“sensor”] = true;

filter[“data”][0] = true;

JsonDocument doc;

deserializeJson(doc, input, DeserializationOption::Filter(filter));

// Only extracts specified fields, saves memory

Precompute Capacity at Compile Time

// Calculate once, use everywhere

constexpr size_t JSON_CAPACITY =

  JSON_OBJECT_SIZE(3) +

  JSON_ARRAY_SIZE(2) +

  100; // String storage

StaticJsonDocument<JSON_CAPACITY> doc;

ArduinoJSON Version Differences

Key Changes in Version 7

FeatureVersion 6Version 7
Document TypesStatic/DynamicUnified JsonDocument
Memory ManagementManual capacityAutomatic growth
API ComplexityMore optionsSimplified
PerformanceFastFaster
MigrationBreaking changes

Migrating from Version 6 to 7

// Version 6

StaticJsonDocument<200> doc;

deserializeJson(doc, input);

// Version 7 (simpler)

JsonDocument doc;

deserializeJson(doc, input);

Resource Library for ArduinoJSON Development

Official Documentation and Tools

Learning Resources

  • Mastering ArduinoJSON: Official book by Benoit Blanchon
  • Example Projects: 10+ official examples in library
  • Video Tutorials: Arduino Project Hub tutorials
  • Community Forum: Questions at GitHub Issues

Testing and Validation Tools

Compatible Libraries

  • HTTPClient: For ESP32/ESP8266 HTTP requests
  • WiFiClientSecure: HTTPS support
  • ESP8266HTTPClient: ESP8266-specific HTTP
  • ESPAsyncWebServer: Async web server with JSON
  • SPIFFS: File system for config storage
  • SD: SD card storage

Development Environments

  • Arduino IDE: Standard development platform
  • PlatformIO: Advanced IDE with better library management
  • Visual Studio Code: With Arduino/PlatformIO extensions
  • Arduino CLI: Command-line development

Frequently Asked Questions

Q1: How do I decide between StaticJsonDocument and DynamicJsonDocument in Version 6?

Use StaticJsonDocument for JSON under 1KB that fits comfortably in stack memory—this is faster and safer for small payloads like sensor readings or simple configuration. Use DynamicJsonDocument when your JSON exceeds 1KB or when the size varies significantly at runtime. Stack overflow is a real concern on Arduino boards with limited RAM (2KB on Uno), so if your StaticJsonDocument needs more than 400-500 bytes, switch to Dynamic. The rule of thumb: StaticJsonDocument for embedded applications with predictable small JSON, DynamicJsonDocument for web applications with variable large JSON. In Version 7, this decision is handled automatically by JsonDocument.

Q2: Why does my program crash after deserializing JSON?

The most common cause is insufficient memory allocation. Use the ArduinoJSON Assistant to calculate the exact capacity needed for your JSON structure—people routinely underestimate by 50% or more. Another frequent issue is accessing the JsonDocument after the source string goes out of scope, particularly with temporary String objects. The JsonDocument doesn’t copy strings by default; it stores pointers. If the original string is destroyed, those pointers become invalid. To fix this, either keep the source string alive or use StaticJsonDocument which copies strings. Finally, check for DeserializationError—it returns specific error codes that pinpoint the exact problem.

Q3: Can I use ArduinoJSON with HTTPS/TLS connections?

Yes, ArduinoJSON works perfectly with secure connections. For HTTPS on ESP32/ESP8266, use WiFiClientSecure instead of WiFiClient, then pass the secure stream to deserializeJson(). You’ll need to handle certificate validation—either set a root CA certificate or call setInsecure() for testing (not recommended for production). The JSON parsing itself is identical; only the transport layer changes. When using HTTPClient with HTTPS, call http.begin() with the secure client and HTTPS URL. The library abstracts away the TLS complexity, so your JSON code remains unchanged. Just remember that TLS increases memory usage, so budget an extra 5-10KB for the TLS stack on top of your JSON document size.

Q4: How do I handle very large JSON responses that don’t fit in memory?

Use JSON filtering (deserializeJson with DeserializationOption::Filter) to extract only the fields you need—this dramatically reduces memory requirements. Create a filter document that specifies which fields to keep, then pass it as the third parameter to deserializeJson(). For example, if an API returns 100 fields but you only need 3, the filter can reduce memory usage by 97%. If even filtered JSON is too large, consider requesting data in smaller chunks using pagination parameters in the API call. Some APIs support field selection via query parameters. As a last resort, parse the JSON in streaming mode using a JSON streaming parser library, though this requires more complex code. For most IoT applications, filtering solves the problem elegantly.

Q5: What’s the performance impact of using ArduinoJSON compared to manual string parsing?

ArduinoJSON is typically faster than manual parsing for anything beyond trivial JSON structures. Manual parsing requires extensive string searching, copying, and type conversion code that’s both slow and error-prone. ArduinoJSON uses optimized algorithms and zero-copy techniques where possible. In benchmarks, ArduinoJSON parses typical IoT JSON payloads in microseconds on ESP32 and milliseconds on Arduino Uno. The real performance advantage is maintainability—manual parsing code becomes exponentially complex with nested structures, while ArduinoJSON maintains constant development time regardless of JSON complexity. Memory usage is also competitive; the library uses a memory pool that’s more efficient than repeated String allocations. Unless you’re parsing thousands of JSON documents per second (unlikely on microcontrollers), ArduinoJSON’s performance is excellent and its code clarity is invaluable.

Leave a Reply

Your email address will not be published. Required fields are marked *

Contact Sales & After-Sales Service

Contact & Quotation

  • Inquire: Call 0086-755-23203480, or reach out via the form below/your sales contact to discuss our design, manufacturing, and assembly capabilities.

  • Quote: Email your PCB files to Sales@pcbsync.com (Preferred for large files) or submit online. We will contact you promptly. Please ensure your email is correct.

Drag & Drop Files, Choose Files to Upload You can upload up to 3 files.

Notes:
For PCB fabrication, we require PCB design file in Gerber RS-274X format (most preferred), *.PCB/DDB (Protel, inform your program version) format or *.BRD (Eagle) format. For PCB assembly, we require PCB design file in above mentioned format, drilling file and BOM. Click to download BOM template To avoid file missing, please include all files into one folder and compress it into .zip or .rar format.