Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LittleFS with ArduinoJSON #1473

Closed
davidmariag opened this issue Jan 14, 2021 · 5 comments
Closed

LittleFS with ArduinoJSON #1473

davidmariag opened this issue Jan 14, 2021 · 5 comments
Labels
question v6 ArduinoJson 6

Comments

@davidmariag
Copy link

davidmariag commented Jan 14, 2021

I am using the ArduinoJSON library with LittlesFS and have used it on quite a few projects successfully. However never quite like this. I have int arrays, long arrays and a char array. Please see the code below. Can any one help me with the syntax for the char array? Please see the commented line in the code.

#include <ArduinoJson.h>
#include "FS.h"
#include <LittleFS.h>

long cardUIDlittleFS[3] = {123456789,989748741,326561145};
char* cardHolder[3] = {"David","Sam","Doug"};
int cardActive[3] = {1,0,1};

long cardUIDlittleFS1[3];
char* cardHolder1[3];
int cardActive1[3];

bool loadData() {
  File dataFile = LittleFS.open("/data.json", "r");
  if (!dataFile) {
    Serial.println("Failed to open data file");
    return false;
  }

  size_t size = dataFile.size();
  if (size > 1024) {
    Serial.println("Data file size is too large");
    return false;
  }

  std::unique_ptr<char[]> buf(new char[size]);

  dataFile.readBytes(buf.get(), size);

  StaticJsonDocument<300> doc;
  auto error = deserializeJson(doc, buf.get());
  if (error) {
    Serial.println("Failed to parse config file");
    return false;
  }
    for(int i=0; i<3; ++i)
    {
      cardUIDlittleFS1[i] = doc["CardUID"][i];
    }
    for(int i=0; i<3; ++i)
    {
      cardHolder1[i] = doc["CardHLDR"][i];
    }


  return true;
}

bool saveData() {
  StaticJsonDocument<300> doc;
  
  JsonArray CardUID = doc.createNestedArray("CardUID");
  JsonArray CardHLDR = doc.createNestedArray char*("CardHLDR");  /////want to put char array into JSON doc and loop it in and out
  
  for(int i=0; i<3; ++i)
  {
    CardUID.add(cardUIDlittleFS[i]);
    Serial.println(cardUIDlittleFS[i]);
  }
  
    for(int i=0; i<3; ++i)
    {
     CardHLDR[i]=cardHolder[i];
    Serial.println(cardHolder[i]);
    }
  
  
  File dataFile = LittleFS.open("/data.json", "w");
  if (!dataFile) {
    Serial.println("Failed to open config file for writing");
    return false;
  }

  serializeJson(doc, dataFile);
  return true;
}


void setup() {
  Serial.begin(74880);

  if (!LittleFS.begin()) {
        Serial.println("Failed to mount file system");                  
        return;
      }
  
  if (!loadData())                                                      
      {
        Serial.println("Failed to load Data");
      } 
      else 
      {
        Serial.println("Data loaded");
      }

   delay(5000);

  saveData();
   
   Serial.println("Print");
    for(int i=0; i<3; ++i)
      {
        Serial.println(cardUIDlittleFS1[i]);
      }
   Serial.println("name");
    for(int i=0; i<3; ++i)
      {
        Serial.println(cardHolder1[i]);
      }
}

void loop() {
}

PS not sure how to mark this as a question..

@bblanchon
Copy link
Owner

Hi @davidmariag,

I didn't understand your question, so here are a few remarks about the code above.

char* cardHolder[3] = {"David","Sam","Doug"};

I'm pretty sure there is a compiler warning on this line; it should be const char*.
You must eliminate all compiler warnings.

std::unique_ptr<char[]> buf(new char[size]);

This is a very common anti-pattern; I don't understand why so many users are doing this.
It's simpler and more efficient to pass the File directly to deserializeJson(), as shown in the example.

cardHolder1[i] = doc["CardHLDR"][i];

This line stores a pointer to the temporary buffer; the pointer dangles as soon as the function exits.
After that, anything can happen, so it's no need to read further.
You must copy the string instead, as shown in the example.

I hope this will help.

Best regards,
Benoit

@davidmariag
Copy link
Author

Ok I'll look at the examples and see if I can make heads or tails of em. I'll post here if I have more questions after.

@davidmariag
Copy link
Author

This is a very common anti-pattern; I don't understand why so many users are doing this.
It's simpler and more efficient to pass the File directly to deserializeJson(), as shown in the example.

I think it is because beginners like me see it as a SD card code and give up with converting it. Maybe if you have time you could do a video on LittleFS specifically.

@davidmariag
Copy link
Author

Ok I got an example to work with LittleFS to increment the variable, see below.

#include <ArduinoJson.h>
#include "FS.h"
#include <LittleFS.h>

// Our configuration structure.

struct Config {
  char cardHolder[64];
  int cardNumber;
};

const char *filename = "/config.txt";  // <- SD library uses 8.3 filenames
Config config;                         // <- global configuration object

// Loads the configuration from a file
void loadConfiguration(const char *filename, Config &config) {

  File file = LittleFS.open(filename, "r");
  if (!file) {
    Serial.println("Failed to open data file");
    return;
  }

  // Allocate a temporary JsonDocument
  // Don't forget to change the capacity to match your requirements.
  // Use arduinojson.org/v6/assistant to compute the capacity.
  StaticJsonDocument<512> doc;

  // Deserialize the JSON document
  DeserializationError error = deserializeJson(doc, file);
  if (error)
    Serial.println(F("Failed to read file, using default configuration"));

  // Copy values from the JsonDocument to the Config
  config.cardNumber = doc["cardNumber"];
  strlcpy(config.cardHolder,                  // <- destination
          doc["cardHolder"] | "example.com",  // <- source
          sizeof(config.cardHolder));         // <- destination's capacity

  // Close the file (Curiously, File's destructor doesn't close the file)
  file.close();
}

// Saves the configuration to a file
void saveConfiguration(const char *filename, const Config &config) {
  // Delete existing file, otherwise the configuration is appended to the file
  //SD.remove(filename);

  // Open file for writing
  File file = LittleFS.open(filename, "w");
  if (!file) {
    Serial.println("Failed to open config file for writing");
    return;
  }
  // Allocate a temporary JsonDocument
  // Don't forget to change the capacity to match your requirements.
  // Use arduinojson.org/assistant to compute the capacity.
  StaticJsonDocument<256> doc;

  // Set the values in the document
  doc["cardHolder"] = config.cardHolder;
  doc["cardNumber"] = config.cardNumber;

  // Serialize JSON to file
  if (serializeJson(doc, file) == 0) {
    Serial.println(F("Failed to write to file"));
  }

  // Close the file
  file.close();
}

// Prints the content of a file to the Serial
void printFile(const char *filename) {
  // Open file for reading

  File file = LittleFS.open(filename, "r");
  if (!file) {
    Serial.println("Failed to open data file");
    return;
  }
  // Extract each characters by one by one
  while (file.available()) {
    Serial.print((char)file.read());
  }
  Serial.println();

  // Close the file
  file.close();
}

void setup() {
  // Initialize serial port
  Serial.begin(9600);
  while (!Serial) continue;

  // Initialize SD library
  while (!LittleFS.begin()) {
    Serial.println(F("Failed to initialize SD library"));
    delay(1000);
  }

  // Should load default config if run for the first time
  Serial.println(F("Loading configuration..."));
  loadConfiguration(filename, config);

  // Create configuration file
  Serial.println(F("Saving configuration..."));
  saveConfiguration(filename, config);

  // Dump config file
  Serial.println(F("Print config file..."));
  printFile(filename);
}

void loop() {
  // not used in this example
  config.cardNumber = config.cardNumber + 1;
  Serial.println(config.cardNumber);
  saveConfiguration(filename, config);
  delay(1000);
}

So I am trying to store [10] RFID tags and the name associated to them, what is the correct way to edit this code to make that work? I will need and int Array to bring the card number in to the program to edit and compare them. What about the names?

@bblanchon
Copy link
Owner

Hi @davidmariag,

To store up to 10 RFID tags, you need an array of 10 structures.
If you need to see an example, the case study "Configuration in SPIFFS" shows how to store a list of SSID/Password in a configuration file; you'll find it in the last chapter of Mastering ArduinoJson.

Best regards,
Benoit

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 28, 2021
@bblanchon bblanchon added the v6 ArduinoJson 6 label Feb 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
question v6 ArduinoJson 6
Projects
None yet
Development

No branches or pull requests

2 participants