📟 JSON library for Arduino and embedded C++. Simple and efficient.

Overview

ArduinoJson


arduino-library-badge Continuous Integration Continuous Integration Fuzzing Status Coverage Status GitHub stars

ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).

Features

Quickstart

Deserialization

Here is a program that parses a JSON document with ArduinoJson.

char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";

DynamicJsonDocument doc(1024);
deserializeJson(doc, json);

const char* sensor = doc["sensor"];
long time          = doc["time"];
double latitude    = doc["data"][0];
double longitude   = doc["data"][1];

See the tutorial on arduinojson.org

Serialization

Here is a program that generates a JSON document with ArduinoJson:

DynamicJsonDocument doc(1024);

doc["sensor"] = "gps";
doc["time"]   = 1351824120;
doc["data"][0] = 48.756080;
doc["data"][1] = 2.302038;

serializeJson(doc, Serial);
// This prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}

See the tutorial on arduinojson.org

Support the project

Do you like this library? Please star this project on GitHub!

What? You don't like it but you love it?
We don't take donations anymore, but we sell a book, so you can help and learn at the same time.

Comments
  • PlatformIO + ESP8266 + Debug mode = Stack overflow

    PlatformIO + ESP8266 + Debug mode = Stack overflow

    I am using the code right out of your book examples. Whenever I run it a second time (when it should have already created the /config.json) it tells me it "Failed to deserialize configuration." When the JSON prints it looks fine, and I have run it through a JSON Validator and it returns ok.

    The only changes I've made are as follows:

    • Renamed SpiffsConfig.ino to main.cpp as I am using PlatformIO
    • Added prototypes for the functions at the top of the main.cpp

    I'm not going to include that code - because I got it from you. :)

    So - problem statement: I am unable to use the example provided.

    It never seems to be able to deserialize the file. The file prints out fine when writing, but when the ESP restarts the file is unable to deserialize again. The file exists.

    Here's some demo code I made trying to make sense of it (using the same Config.h and Config.cpp):

    #include <FS.h>
    #include "Config.h"
    
    const char *filename = "/config.json";
    Config config;
    
    bool loadConfig(const char *filename, Config &config);
    bool saveConfig(const char *filename, const Config &config);
    void setDefaultConfig();
    bool printFile(const char *filename);
    bool listFiles();
    bool listFileSystemInfo();
    void printConfig();
    void setup();
    void loop();
    
    bool loadConfig(const char *filename, Config &config) {
        // Loads the configuration from a file on SPIFFS
        bool retVal;
        // Mount SPIFFS
        if (SPIFFS.begin()) {
            // Open file for reading
            File file = SPIFFS.open(filename, "r");
            // This may fail if the file is missing
            if (!file) {
                Serial.println(F("Failed to open config file."));
                retVal = false;
            } else {
                // Parse the JSON object in the file
                // This may fail if the JSON is invalid
                if (!deserializeConfig(file, config)) {
                    Serial.println(F("Failed to deserialize configuration, here's the file we attempted:"));
                    printFile(filename);
                    SPIFFS.remove(filename);
                    Serial.println(F("Deleted corrupt file."));
                    retVal = false;
                } else {
                    retVal = true;
                }
                file.close();
            }
            SPIFFS.end();
        } else {
            Serial.println(F("Unable to start SPIFFS in loadConfig()."));
            retVal = false;
        }
        return retVal;
    }
    
    bool saveConfig(const char *filename, const Config &config) {
        bool retVal;
        // Open file for writing
        if (SPIFFS.begin()) {
            File file = SPIFFS.open(filename, "w");
            if (!file) {
                Serial.println(F("Failed to create config file."));
                retVal = false;
            } else {
                // Serialize JSON to file
                bool success = serializeConfig(config, file);
                if (!success) {
                    Serial.println(F("Failed to serialize configuration."));
                    retVal = false;
                } else {
                    retVal = true;
                }
                file.close();
            }
            SPIFFS.end();
        } else {
            Serial.println(F("Unable to start SPIFFS in saveConfig()."));
            retVal = false;
        }
        return retVal;
    }
    
    void setDefaultConfig() {
        // Initialize configuration with defaults
        Serial.println(F("Setting default config."));
        strcpy(config.server.host, "example.com");
        strcpy(config.server.path, "/resource");
        strcpy(config.server.username, "admin");
        strcpy(config.server.password, "s3cr3t");
        strcpy(config.accessPoint[0].ssid, "SSID 1");
        strcpy(config.accessPoint[0].passphrase, "Passphrase 1");
        strcpy(config.accessPoint[1].ssid, "SSID 2");
        strcpy(config.accessPoint[1].passphrase, "Passphrase 2");
        config.accessPoints = 2;
    }
    
    bool printFile(const char *filename) {
        // Prints the content of a file to the Serial
        bool retVal;
        // Open file for reading
        if (SPIFFS.begin()) {
            File file = SPIFFS.open(filename, "r");
            if (!file) {
                Serial.println(F("Failed to open file for printing."));
                retVal = false;
            } else {
                // Extract each by one by one
                while (file.available()) {
                    Serial.print((char)file.read());
                }
                Serial.println();
                file.close();
                retVal = true;
            }
            SPIFFS.end();
        } else {
            Serial.println(F("Unable to start SPIFFS in printFile()."));
            retVal = false;
        }
        return retVal;
    }
    
    bool listFileSystemInfo() {
        bool retVal;
        if (SPIFFS.begin()) {
            retVal = true;
            // List filesystem information
            FSInfo fs_info;
            SPIFFS.info(fs_info);
            Serial.println(F("-------------------"));
            Serial.print(F("Total Bytes: "));
            Serial.println(fs_info.totalBytes);
            Serial.print(F("Used Bytes: "));
            Serial.println(fs_info.usedBytes);
            Serial.print(F("Block Size: "));
            Serial.println(fs_info.blockSize);
            Serial.print(F("Page Size: "));
            Serial.println(fs_info.pageSize);
            Serial.print(F("Max Open Files: "));
            Serial.println(fs_info.maxOpenFiles);
            Serial.print(F("Max Path Length: "));
            Serial.println(fs_info.maxPathLength);
            Serial.println(F("-------------------"));
            SPIFFS.end();
            return true;
        } else {
            Serial.println(F("Unable to start SPIFFS in listFileSystemInfo()."));
            retVal = false;
        }
        return retVal;
    }
    
    bool listFiles() {
        bool retVal;
        if (SPIFFS.begin()) {
            Dir dir = SPIFFS.openDir("");
            int files = 0;
            while (dir.next()) {
                if (files == 0)
                    Serial.println(F("-------------------"));
    
                Serial.print(dir.fileName());
                Serial.print(F(" - "));
                Serial.print(dir.fileSize());
                Serial.println(F("B"));
                files++;
            }
            if (files > 0)
                Serial.println(F("-------------------"));
            SPIFFS.end();
            retVal = true;
        } else {
            Serial.println(F("Unable to start SPIFFS in listFiles()."));
            retVal = false;
        }
        return retVal;
    }
    
    void printConfig() {
        // TODO:  Iterate through stuff
    }
    
    void setup() {
        delay(1000);
        Serial.begin(BAUD);
    
        if (!listFileSystemInfo()) {
            Serial.println(F("Error: Unable to list file system info."));
        } else {
            if (!listFiles()) {
                Serial.println(F("Error: Unable to list files."));
            } else {
                // Load configuration
                if (!loadConfig(filename, config)) {
                    Serial.println(F("Error: Unable to load configuration."));
                    // Set default configuration
                    setDefaultConfig();
                    // Save configuration
                    if (!saveConfig(filename, config)) {
                        Serial.println(F("Error: Unable to save configuration."));
                    } else {
                        // Dump config file
                        if (!printFile(filename)) {
                            Serial.println(F("Error: Unable to print configuration file."));
                        }
                    }
                } else {
                    Serial.println(F("Everything seems ok."));
                }
            }
        }
    }
    
    void loop() {}
    

    Currently, it all works as expected the first time. Subsequently, when it should be loading the configuration it fails:

    -------------------
    Total Bytes: 957314
    Used Bytes: 753
    Block Size: 8192
    Page Size: 256
    Max Open Files: 5
    Max Path Length: 32
    -------------------
    -------------------
    /config.json - 309B
    -------------------
    Failed to deserialize configuration, here's the file we attempted:
    {
      "server": {
        "username": "admin",
        "password": "s3cr3t",
        "host": "example.com",
        "path": "/resource"
      },
      "access_points": [
        {
          "ssid": "SSID 1",
          "passphrase": "Passphrase 1"
        },
        {
          "ssid": "SSID 2",
          "passphrase": "Passphrase 2"
        }
      ]
    }
    Deleted corrupt file.
    Error: Unable to load configuration.
    Setting default config.
    {
      "server": {
        "username": "admin",
        "password": "s3cr3t",
        "host": "example.com",
        "path": "/resource"
      },
      "access_points": [
        {
          "ssid": "SSID 1",
          "passphrase": "Passphrase 1"
        },
        {
          "ssid": "SSID 2",
          "passphrase": "Passphrase 2"
        }
      ]
    }
    

    So you can see that the file looks right, it is 309 bytes in length (which is correct) yet still does not deserialize.

    ETA: A debug line in deserializeConfig() tells me that it fails because of IncompleteInput.

    bug 
    opened by lbussy 55
  • Platformio compatibility?

    Platformio compatibility?

    Do you have any experience of getting this to work with platformio?

    I followed these instructions http://www.penninkhof.com/2015/12/1610-over-the-air-esp8266-programming-using-platformio/

    and it works flawlessly.. I copied all my libs to the /lib folder but when i try and compile them it is the arduinojson that stops it in its tracks. It is the #include "../include/ArduinoJson.h" that causes the problems. The one included for ardunio compatibility... commenting it out, stops it from working.. bit of a stab in the dark asking you, but my knowledge of compiling structures / directories, outside the arduino IDE is fairly minimal. any help appreciated

    opened by sticilface 47
  • Complex memory requirements

    Complex memory requirements

    me again....

    I'm working on adapting arduinojson to work with an asynchronous web server on the ESP8266. I have to overcome two problems.

    1. getting chuncked data - which you have provided...
    2. Extending the lifetime of the jsonbuffer, and objects PAST that of the scope of the initial function...

    This is because to send an async web request it is all done via callbacks.... triggered on the ACK of the previous packet... I'm writing a class that deals with the creation of the buffer and the sending of the data, which is fine.... but... my issue is what is the relationship and scope requirements of the jsonobjects themselves and the buffer...

    my class can return a reference to the jsonbuffer.

    but then the user can create an object or an array using JsonObject&.. and what I'm not sure about is how far all these objects, and arrays, and sub objects... etc need to be in scope for the integrity of the sending later... or... can you just pass a jsonVarient pointer and use pointer->printTo()?

    Or do all the objects (Object + arrays) need to be in scope for it to work?
    I hope this makes sense?

    having thought i cracked it last night, it is not working now... Can you correct me if I'm wrong. The buffer has to stay in scope for the object to be able to print. BUT... the reference to the original object can go out of scope... as long as you've stored it somewhere, say as a pointer it will work... Through a lot of trial and error this seems to work...

    However, I would like this to be flexible... so i've tried to write a function like before

    template <class T> void AsyncJsonResponse::SetTarget( T & root)
    {
      _root = &root;
      _contentLength = _root->measureLength();
    
    }
    

    where _root is a pointer to JsonObject... now this works... but if i change the pointer to JsonVarient (so it can store a pointer to object and Array) i get garbage...

    so at the moment...

      JsonObject* _root;
    

    but i would like

    JsonVarient* _root; 
    

    so it can be both array and an object...

    What is the best way for this class to take a Json item.. (object or Array) store it so that it can be used for the measurelength() and printTo()..

    Let me know if this makes sense?

    opened by sticilface 40
  • BIG array problem with version 5

    BIG array problem with version 5

    Tried your assistant for the following API https://api.binance.com/api/v3/ticker/price on an ESP8266.

    Assistant gives the size as 34962 bytes with:

    const size_t bufferSize = JSON_ARRAY_SIZE(419) + 419*JSON_OBJECT_SIZE(2) + 14630;

    But from the assistant the entries are coming back as empty for:

    const char* root_0_symbol = root_[0]["symbol"]; // "ETHBTC"

    When I try:

    Serial.println(root_0_symbol);

    The ESP8266 is not crashing and I get the same results if I just set the json manually rather than via an API call i.e.

    const char* json = "[{\"symbol\":\"ETHBTC\",..........................................\"}]";

    Any idea why it's not parsing the json array and not giving any errors?

    question 
    opened by pieman64 34
  • Parsing String values crashes ESP8266

    Parsing String values crashes ESP8266

    Also noticing on the ESP8266, that parsing anything but a statically defined const char*, kills the parser.

    #include <ArduinoJson.h>
    
    void setup() {
    
      Serial.begin( 115200 );
      delay( 10 );
      Serial.println( "" );
    
      StaticJsonBuffer<200> jsonBuffer;
    
      String json = "{\"mqtt.host\":\"mqtt.test.com\",\"mqtt.port\":1883}";
    
      Serial.println( "Parsing json string" );
      JsonObject& root = jsonBuffer.parseObject( json );
    
      if( root.success() ) {
        Serial.println( "parsed" );
      } else {
        Serial.println( "failed" );
      }
    }
    
    void loop() {
    }
    

    Results in

    Parsing json string
    
    Exception (9):
    epc1=0x402021cd epc2=0x00000000 epc3=0x00000000 excvaddr=0x3ffe9d67 depc=0x00000000
    
    ctx: cont 
    sp: 3ffe9b40 end: 3ffe9e30 offset: 01a0
    
    >>>stack>>>
    3ffe9ce0:  3fffdc20 00000013 3ffe8de4 402039a9  
    3ffe9cf0:  3ffe8968 00000000 3ffe8de4 3ffe9e5c  
    3ffe9d00:  3fffdc20 00000000 3ffe8de4 40202216  
    3ffe9d10:  3ffe9d30 3ffe9d34 3ffe9d34 4020450a  
    3ffe9d20:  3fffdc20 00000000 3ffe8de4 4020214e  
    3ffe9d30:  3ffe8878 716d227b 682e7474 2274736f  
    3ffe9d40:  716d223a 742e7474 2e747365 226d6f63  
    3ffe9d50:  716d222c 702e7474 2274726f 3838313a  
    3ffe9d60:  00007d33 00000000 00000000 00000000  
    3ffe9d70:  00000000 00000000 00000000 00000000  
    3ffe9d80:  00000000 00000000 00000000 00000000  
    3ffe9d90:  00000000 00000000 00000000 00000000  
    3ffe9da0:  00000000 00000000 00000000 00000000  
    3ffe9db0:  00000000 00000000 00000000 00000000  
    3ffe9dc0:  00000000 00000000 00000000 00000000  
    3ffe9dd0:  00000000 00000000 00000000 00000000  
    3ffe9de0:  00000000 00000000 00000000 00000000  
    3ffe9df0:  00000000 00000000 00000000 00000037  
    3ffe9e00:  3fff38a8 0000002e 0000002e 00000000  
    3ffe9e10:  00000000 00000000 3ffe9e54 40201a07  
    3ffe9e20:  00000000 00000000 3ffe8e10 40100378  
    <<<stack<<<
    
    bug 
    opened by JeffAshton 34
  • two way communication of nrf24l01 model using ArduinoJson

    two way communication of nrf24l01 model using ArduinoJson

    I want to transmit and receive a json file using arduinojson in nrf24l01 but i am not getting the output.. if anyone can help me giving a very simple code (i.e generator and parsar) will be very thnkful..

    question 
    opened by soumiksinha19 31
  • 🔥 JsonBuffer was not declared in this scope / does not name a type

    🔥 JsonBuffer was not declared in this scope / does not name a type

    After updating from 5.13.1 to 5.13.2 neither StaticJsonBuffer nor DynamicJsonBuffer work. Compiler gives error StaticJsonBuffer/DynamicJsonBuffer' was not declared in this scope. Downgrading back to 5.13.1 and using the same code compiles.

    question 
    opened by teemue 27
  • trouble with

    trouble with "parseObject() failed", convert const char to char

    Hi.

    Just star to implant arduinoJson to my sketch. But with the parser return "parseObject() failed".

    I read on the wiki that It could be cause by a read-only or pointer object. My char came from uHTTP library and is a pointer but I can't find the way to convert it to an non const var . here the code:

    void parseJSONInputs(const char json[])  {
      StaticJsonBuffer<5000> jsonBuffer;
    Serial.print(json);
    Serial.println();
      JsonObject& root = jsonBuffer.parseObject(json);
    
      if (!root.success()) {
        Serial.println("parseObject() failed");
        return;
      }
    
      for (int i = 0; i < 10 ; i++) {
    
        inChannelID[root["channels"][i]["canal"]].channelName = root["channels"][i]["name"];
        outChannelID[root["channels"][i]["canal"]].channelSwitch = stringToBool(root["channels"][i]["status"]);
        outChannelID[root["channels"][i]["canal"]].sp = root["channels"][i]["setPoint"];
    
      }
    }
    
    question 
    opened by NitrofMtl 24
  • No control on when float numbers are written with exponent

    No control on when float numbers are written with exponent

    When serialising JSON with float/double values, there is control on how many digits to write after the decimal point, with default of 2. However, if the number is bigger than 1000 or smaller than 0.001 it will always be serialized with exponent: 1234.5 to 1.23e7

    I can track this hard coded behaviour to: https://github.com/bblanchon/ArduinoJson/blob/master/include/ArduinoJson/Serialization/JsonWriter.hpp#L95

    This is not in line with Arduino Serial.print that does not add exponent.

    enhancement 
    opened by hagai-shatz 22
  • Add support for variable float precision when generating JSON strings

    Add support for variable float precision when generating JSON strings

    Float values can have a large number of decimal places that may or may not be necessary to convey in a JSON string.

    Being able to control the max precision of the output to a certain number of decimal places would be a nice feature.

    enhancement 
    opened by mill1000 21
  • How to copy a JsonObject ?

    How to copy a JsonObject ?

    I would like to do something like that :

    void loop() {
      StaticJsonBuffer<200> jsonBuffer;
      JsonObject& objectJSON = jsonBuffer.createObject();
    
      if (stringComplete) {
        // parse string to objectJSON 
      }
    
      doSomethingWith(objectJSON );
    
    }
    

    My problem is that for some reasons, I cannot put the function doSomethingWith(objectJSON ) in the scope of if (stringComplete) {}... It would be too easy... Do you have some suggestion ?

    Thanks a lot !

    question 
    opened by jm4r7in 21
  • Nested array and Arduino substring  function

    Nested array and Arduino substring function

    Describe the issue
    Hi, I'm working on a telegram bot and I can't compile my sketch - it always throws an error if I use the Arduino substring function. Also tried to convert string to C-string "menuStr.substring(0, indexTo).c_str()" - no luck. What I'm doing wrong? Thank you in advance.

    Environment
    Here is the environment that I'm using':

    • Microconroller: [e.g. ESP8266]
    • Core/runtime: [e.g. ESP8266 core for Arduino v3.0.2]
    • IDE: [e.g. Arduino IDE 1.8.16]
    String telegram_showMenu(const String& msgStr, String menuStr)
    {
      DynamicJsonDocument jsonDoc(1024);  //create JSON document in heap memory
    
      jsonDoc["chat_id"] = telegramConfig.chat;
      jsonDoc["text"] = msgStr;
      jsonDoc["parse_mode"] = "HTML"; 
    
      JsonObject markupDoc  = jsonDoc.createNestedObject("reply_markup"); //{"chat_id":"YYYY", ...,"reply_markup":{}}
      JsonArray  keyboardDocArray = markupDoc.createNestedArray("keyboard");    //{"chat_id":"YYYY", ...,"reply_markup":{"keyboard":[]}}
    
      while (menuStr.indexOf('\n') != -1)  //-1=not found
      {
        int16_t indexTo = menuStr.indexOf('\n');
    
        JsonArray buttonDocArray = keyboardDocArray.createNestedArray();  //{"chat_id":"YYYY", ...,"reply_markup":{"keyboard":[[]]}}
        
        buttonDocArray["text"] = menuStr.substring(0, indexTo);  //{"chat_id":"YYYY", ...,"reply_markup":{"keyboard":[["text":"/on"],["text":"/off"]]}}
    
        menuStr.remove(0, indexTo + 1);  //remove "....\n" from start, until empty
    
        yield(); //give SDK (ctx: sys) stack a chance to run
      }
    
      markupDoc["resize_keyboard"]   = true; //{"chat_id":"YYYY", ...,"reply_markup":{"keyboard":[[],...,[]],"resize_keyboard":true}}
      markupDoc["one_time_keyboard"] = true;  //{"chat_id":"YYYY", ...,"reply_markup":{"keyboard":[[],...,[]],"resize_keyboard":true,"one_time_keyboard"=true}}
    
      String minifiedJsonStr((char *)0);
      minifiedJsonStr.reserve(1024);  //set string size to minimize potential heap memory fragmentation, in bytes
    
      serializeJson(jsonDoc, minifiedJsonStr);  //generate minified JSON & send it to string, return number of bytes
    
      return minifiedJsonStr;
    }
    
    question 
    opened by enjoyneering 2
  • Incremental serialize

    Incremental serialize

    Hi for example i want send jpeg image from ESP32 camera (through for example MQTT) using Json, so i must encode jpeg data as base64. And its vaste of memory store jpeg in memory again even bigger because encoded as base64. So i patched ArduinoJson library to do it incrementaly i created Abstract class DynamicData

    class DynamicData {
     public:
      typedef std::function<void(const char* s, size_t n)> WriteJsonFunc;
      typedef std::function<void(const uint8_t* s, size_t n)> WriteRawFunc;
    
      virtual void writeJsonTo(WriteJsonFunc writeFunc) = 0;
      virtual void writeRawTo(WriteRawFunc writeFunc) {}
      virtual size_t sizeJson() {
        return 0;
      }
      virtual size_t sizeRaw() {
        return 0;
      }
    };
    

    writeJsonTo write data for Json serializer using pointer to write func writeRawTo write data for MessagePack serializer using pointer to write func

    and then i for example create Base64 encoder inherited from Dynamic data and i use it

    #include <ArduinoJson.h>
    #include <stdio.h>
    
    class Base64 : public DynamicData {
     public:
      Base64(const char* data, size_t size) : data(data), dataSize(size) {}
      Base64() : data(0), dataSize(0) {}
    
      void encodeTriplet(const char (&input)[3], char (&output)[4]) {
        output[0] = base64_chars[(input[0] & 0xfc) >> 2];
        output[1] =
            base64_chars[((input[0] & 0x03) << 4) + ((input[1] & 0xf0) >> 4)];
        output[2] =
            base64_chars[((input[1] & 0x0f) << 2) + ((input[2] & 0xc0) >> 6)];
        output[3] = base64_chars[input[2] & 0x3f];
      }
    
      virtual size_t sizeRaw() {
        return dataSize;
      }
    
      virtual size_t sizeJson() {
        return 4 * (1 + ((sizeRaw() - 1) / 3));
      }
    
      virtual void writeJsonTo(DynamicData::WriteJsonFunc writer) {
        uint j = 0;
        char input[3];
        char output[4];
    
        for (uint i = 0; i < sizeRaw(); ++i) {
          input[j++] = data[i];
          if (j == 3) {
            encodeTriplet(input, output);
            writer(output, 4);
            j = 0;
          }
        }
        if (j != 0) {
          for (uint i = j; i < 3; ++i) {
            input[i] = '\0';
          }
          encodeTriplet(input, output);
    
          for (uint i = j + 1; i < 4; ++i) {
            output[i] = '=';
          }
          writer(output, 4);
        }
      }
    
     private:
      const char* data;
      size_t dataSize;
      static const char* base64_chars;
    };
    const char* Base64::base64_chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    
    
    int main() {
      char output[1280];
      const char binaryData[] =
          "test big data in memory which cand be stored encoded as base64 again "
          "because we must save memory!!";
      size_t size =
          strlen(binaryData);  // only for example (i must know size of binary data)
    
      DynamicJsonDocument doc(1024);
      doc["sensor"] = "gps";
      doc["binary"] = Base64(binaryData, size);
    
      serializeJson(doc, output);
    
      printf("%s\n ", output);
      return 0;
    }
    

    and after compile and run i got

    {"sensor":"gps","binary":"dGVzdCBiaWcgZGF0YSBpbiBtZW1vcnkgd2hpY2ggY2FuZCBiZSBzdG9yZWQgZW5jb2RlZCBhcyBiYXNlNjQgYWdhaW4gYmVjYXVzZSB3ZSBtdXN0IHNhdmUgbWVtb3J5ISE="}
    

    so it works perfectelly.

    Do you want patch ? It is usefull for others ? it is in my fork ...

    enhancement 
    opened by mirecta 2
  • Corrupted values

    Corrupted values

    Describe the bug
    I am deserializing two json config files. For first one everything works perfectly. However when I deserialize second one it sometimes overwrite config object readed from first file. However when I removed two rows from second file I didn't saw this issue. I check for sollutions in ArduinoJson documentation, tried some things mentioned there like clear or garbageCollect json object, using separate JsonDocuments, passing them as argument so they live long enought etc but it still not work correctly and I am out of idea why.

    Troubleshooter report
    Here is the report generated by the ArduinoJson Troubleshooter:

    1. The issue happens at run time
    2. The issue concerns deserialization
    3. deserializeJson() returns InvalidInput
    4. Input comes from a file
    5. jsonlint says the document is valid
    6. Input's first byte doesn't suggest a BOM

    Environment
    Here is the environment that I used:

    Reproduction
    Here is a small snippet that reproduces the issue.

    void setup(){
      readSystemConfiguration(); //Read first file
      readDeviceConfiguration(); //Read second file
    }
    
    void readSystemConfiguration(){
      Log.verboseln(F("readSystemConfiguration call"));
    
      DynamicJsonDocument doc(5000);
      fileSystem.loadConfiguration("/systemConfig.json", doc);
      systemConfig.fromJson(doc.as<JsonObject>());
      doc.clear();
    }
    
    void readDeviceConfiguration(){
      Log.verboseln(F("readDeviceConfiguration call"));
    
      DynamicJsonDocument doc(8000); 
      fileSystem.loadConfiguration("/deviceConfig.json", doc);
    
      Log.verboseln(F("SystemConfig is correct here: %s"), systemConfig.wifiName); //Until here everything works 
      deviceConfig.fromJson(doc.as<JsonVariant>());
      Log.verboseln(F("At this point system config is incorrect: %s"), systemConfig.wifiName); //Here content is already broken 
      doc.clear();
    }
    
    //fileSystem.loadConfiguration
    void loadConfiguration(const char *filename, DynamicJsonDocument &doc) {
      File file = SPIFFS.open(filename, "r+");
    
      // Deserialize the JSON document
      DeserializationError error = deserializeJson(doc, file);
      if (error){
        Log.errorln(F("Failed to read file, using default configuration %s"), error.c_str());
      }
      file.close();
    }
    
    //deviceConfig.fromJson
    void fromJson(const JsonVariant& json){
            JsonArray array = json["devices"].as<JsonArray>();
            mpptType = json["mpptType"];
            int i=0;
            for(JsonObject item: array){
                device[i].fromJson(item); //This call fromJson from SingleDeviceConfig
                i++;
            }
        }
    
    class SingleDeviceConfig {
    
       public:
      
        char name[32];
        char mapping[20];
        int type2;
        int default2;
        bool connected;
    
        void fromJson(const JsonObject& json) {
            strlcpy(name, json["name"], sizeof(name));
            strlcpy(mapping, json["mapping"], sizeof(mapping));
            type2 = json["type"];
            default2 = json["default"];
            connected = json["connected"];
        }
    };
    

    systemConfig.json file:

    {
        "wifiName": "MyWifiName",
        "wifiPassword": "wifiPassword",
        "connectToExistingWifi": false,
        "dhcp": true,
        "ip": "192.168.4.1",
        "gateway": "192.168.4.1",
        "subnet": "255.255.255.0",
        "user": "",
        "password": "",
        "phone": "",
        "pin": ""
    }
    

    deviceConfig.json file:

    {"devices": [
        {"name": "Hotel battery", "mapping": "mainBattery", "type": 1, "connected": 1},
        {"name": "Running battery", "mapping": "additionalBattery",  "type": 2, "connected": 1},
        {"name": "Fresh water", "mapping": "waterSensor1", "type": 1, "connected": 1},
        {"name": "Grey water", "mapping": "waterSensor2", "type": 1, "connected": 1},
        {"name": "Light", "mapping": "device1", "type": 2, "connected": 1},
        {"name": "Fridge", "mapping": "device2",  "type": 8, "connected": 1},
        {"name": "Water pump", "mapping": "device3",  "type": 1, "connected": 1},
        {"name": "Water valve", "mapping": "device4",  "type": 7, "connected": 1},
        {"name": "Fan", "mapping": "device5",  "type": 4, "connected": 1},
        {"name": "Heating", "mapping": "device6", "type": 3, "connected": 1},
        {"name": "Power Inverter", "mapping": "device7",  "type": 9, "connected": 1},
        {"name": "Move sensor", "mapping": "sensor1",  "type": 4, "connected": 1},
        {"name": "Gas sensor", "mapping": "sensor2",  "type": 5, "connected": 1},
        {"name": "Flood sensor", "mapping": "sensor3",  "type": 6, "connected": 1},
        {"name": "Door sensor", "mapping": "sensor4",  "type": 7, "connected": 1},
        {"name": "Outside temp.", "mapping": "extTemp1",  "type": 1, "connected": 1},
        {"name": "Grey water temp.", "mapping": "extTemp2",  "type": 1, "connected": 1},
        {"name": "Custom temp. 1", "mapping": "extTemp3",  "type": 1, "connected": 0},
        {"name": "Custom temp. 2", "mapping": "extTemp4",  "type": 1, "connected": 0}
    ], 
        "mpptType": 1
    }
    

    Program output

    Expected output:

    V: SystemConfig is correct here: MyWifiName
    V: At this point system config is incorrec: MyWifiName
    

    When I remove some rows from deviceConfig.json I can get this output. Of course I tried to increase json document size but it didn't help.

    Actual output:

    V: SystemConfig is correct here: MyWifiName
    V: At this point system config is incorrec: MyWifiNaextTemp2
    

    Looks like somehow it joined wifiName (without two last chars) from first file with mapping value from second file.

    bug 
    opened by michaloles 2
  • Much easier fix for min vs std::min issue

    Much easier fix for min vs std::min issue

    (It's not obvious where the website docs live in github, or i'd just submit a pull request) The troubleshooter for the std::min vs arduino min macro (https://arduinojson.org/v6/troubleshooter/?utm_source=github&utm_medium=readme#compiletime/macro-min/success) says to disable std::string/std::stream support.

    Just to flag there is actually a much easier fix that does not require compiler flags and should work everywhere.

    Before including ArduinoJson.h, do this:

    #include <Arduino.h>
    #undef min
    

    min is guaranteed to be defined in C++ so we don't have to worry that we will remove the only definition (it's also supposed to be an inline function and not a macro, which is why it conflicts in the first place)

    Including the header ourselves guarantees that all the macros are defined and that the header won't be reincluded by someone else. #undef min then removes the conflicting macro definition. This will work:

    1. On all systems where someone uses ArduinoJSON
    2. whether the min macro exists or not.
    3. without removing support for std::*

    Figured i would flag this.

    enhancement 
    opened by dberlin 1
  • Memory savings

    Memory savings

    Hi Benoit,

    I noticed that ArduinoJson needs a pretty sizeable amount of memory for each object (16 bytes on ESP32); even by using zero-copy I find that I can need more memory for the JsonDocument than for the serialized Json. I see that a lot of work has been put into saving memory, but I was wondering if you would consider PRs for the following changes:

    make support for serialized() optional

    By removing support for serialized() via a preprocessor definition we could then remove asRaw from VariantContent and also remove _tail from CollectionData and reduce the size of VariantContent to the size of a pointer/float. Removing _tail would mean that to add a collection element we need to walk the linked list each time, but in certain situations it could be a reasonable tradeoff.

    add support for short strings

    In case of very short strings we could apply short-string optimization and store up to 3 characters for 32bit archs and 7 characters for 64bit archs (+1 for null termination) in place of the 'char *'. This is probably a marginal improvement, especially because 64bit archs where it can be applied more easily don't probably need it as much. Also it won't matter for zero-copy.

    enhancement 
    opened by lultimouomo 1
  • Feature request: ability to get the path of JsonVariant in a document

    Feature request: ability to get the path of JsonVariant in a document

    Hello! Thanks for the great library!

    I suggest adding ability to get the path of JsonVariant in a document, or at least to check that two JsonVariant point to the same location of the document. The latter can be used to implement the former by traversing the whole document. As I understand JsonVariant::operator==() compares content, not pointers.

    My usecase: I parse some JSON structures received from network and if parsing fails I would like to easily send back error messages with the exact path to json part that caused a parsing error.

    enhancement 
    opened by gwisp2 0
Releases(v6.19.4)
Owner
Benoît Blanchon
🐂 Pathological Yak Shaver
Benoît Blanchon
📟 JSON library for Arduino and embedded C++. Simple and efficient.

ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things). Features JSON deserialization Optionally decodes UTF-16 escape sequences t

Benoît Blanchon 5.8k Sep 27, 2022
This is a JSON C++ library. It can write and read JSON files with ease and speed.

Json Box JSON (JavaScript Object Notation) is a lightweight data-interchange format. Json Box is a C++ library used to read and write JSON with ease a

Anhero inc. 108 Aug 26, 2022
json-cpp is a C++11 JSON serialization library.

JSON parser and generator for C++ Version 0.1 alpha json-cpp is a C++11 JSON serialization library. Example #include <json-cpp.hpp> struct Foo {

Anatoly Scheglov 4 Dec 31, 2019
A convenience C++ wrapper library for JSON-Glib providing friendly syntactic sugar for parsing JSON

This library is a wrapper for the json-glib library that aims to provide the user with a trivial alternative API to the API provided by the base json-

Rob J Meijer 16 May 10, 2022
JSON parser and generator for C/C++ with scanf/printf like interface. Targeting embedded systems.

JSON parser and emitter for C/C++ Features ISO C and ISO C++ compliant portable code Very small footprint No dependencies json_scanf() scans a string

Cesanta Software 622 Sep 24, 2022
Json For Embedded Systems (JFES)

JFES Based on the jsmn project. Json For Embedded Systems (JFES) is a minimalistic json engine written in plain C. It can be easily integrated into th

Eremin Dmitrii 65 Jul 4, 2022
json-build is a zero-allocation JSON serializer compatible with C89

json-build is a zero-allocation JSON serializer compatible with C89. It is inspired by jsmn, a minimalistic JSON tokenizer.

Lucas Müller 28 Sep 14, 2022
A simple class for parsing JSON data into a QVariant hierarchy and vice versa.

The qt-json project is a simple collection of functions for parsing and serializing JSON data to and from QVariant hierarchies. NOTE: Qt5 introduced a

null 301 Sep 22, 2022
A simple class for parsing JSON data into a QVariant hierarchy and vice versa.

The qt-json project is a simple collection of functions for parsing and serializing JSON data to and from QVariant hierarchies. NOTE: Qt5 introduced a

null 301 Sep 22, 2022
Very simple C++ JSON Parser

Very simple JSON parser for c++ data.json: { "examples": [ { "tag_name": "a", "attr": [ { "key":

Amir Saboury 65 Sep 28, 2022
A Simple Nastran to JSON mesh reader which makes it easy to exchange data

Nastran to Json Converter A simple code that helps convert Nastran meshes to a JSON file format that is more suitable for the current day and age. Cur

Vijai Kumar S 5 Sep 23, 2021
Simple json reader

JsonReader JsonReader is a library designed to make reading from any json file easy. It is based on jsmn. JsonReader is perfect for working with singl

null 2 Dec 3, 2021
An easy-to-use and competitively fast JSON parsing library for C++17, forked from Bitcoin Cash Node's own UniValue library.

UniValue JSON Library for C++17 (and above) An easy-to-use and competitively fast JSON parsing library for C++17, forked from Bitcoin Cash Node's own

Calin Culianu 24 Sep 21, 2022
A Haskell library for fast decoding of JSON documents using the simdjson C++ library

hermes A Haskell interface over the simdjson C++ library for decoding JSON documents. Hermes, messenger of the gods, was the maternal great-grandfathe

Josh Miller 36 Jun 29, 2022
C library for encoding, decoding and manipulating JSON data

Jansson README Jansson is a C library for encoding, decoding and manipulating JSON data. Its main features and design principles are: Simple and intui

Petri Lehtinen 2.7k Sep 26, 2022
a JSON parser and printer library in C. easy to integrate with any model.

libjson - simple and efficient json parser and printer in C Introduction libjson is a simple library without any dependancies to parse and pretty prin

Vincent Hanquez 262 Sep 29, 2022
json_struct is a single header only C++ library for parsing JSON directly to C++ structs and vice versa

Structurize your JSON json_struct is a single header only library that parses JSON to C++ structs/classes and serializing structs/classes to JSON. It

Jørgen Lind 246 Sep 27, 2022
A small header-only library for converting data between json representation and c++ structs

Table of Contents Table of Contents What Is json_dto? What's new? v.0.3.0 v.0.2.14 v.0.2.13 v.0.2.12 v.0.2.11 v.0.2.10 v.0.2.9 v.0.2.8 v.0.2.7 v.0.2.6

Stiffstream 99 Sep 22, 2022
A very sane (header only) C++14 JSON library

JeayeSON - a very sane C++14 JSON library JeayeSON was designed out of frustration that there aren't many template-based approaches to handling JSON i

Jeaye Wilkerson 128 Jun 7, 2022