How to copy all members of a json object to a 2d array given that the object name matches (ArduinoJson)

883 Views Asked by At

I am working on an Arduino project that will mix cocktails for me. I've decided to save a list of cocktails in a JSON file named cocktails.json, which is saved on an SD card, and upon cocktail selection, I would like the Arduino to find its recipe in the JSON file. A small snippet of the JSON looks like this:

{
  "Cocktails": {
        "Americano": {
            "campari": 1
            "red vermouth": 2
            "soda": 3
        },
        "Aviation": {
            "gin": 1,
            "cherry liqueur": 2,
            "creme de violette": 3,
            "lemon juice": 4
        },
        "B52 Cocktail": {
            "kahlua": 1,
            "baileys": 2,
            "trand marnier": 3
        }
    }
}

Say I tell the Arduino I want the cocktail "Americano". I would like the Arduino to copy all the data under object "Americano" and save it to a 2D array I created in the following struct:


struct cocktailData
{
  char name[25];
  char portions[7][1];
} data;

The array is initialized as [7][1] because there are up to 8 potential ingredients and they're all paired with an amount multiplier. I can't figure out how to copy the entire string into the array so that it saves the recipe in memory. Im using the ArduinoJson library to parse the JSON file. The end goal is that the array would look something like this:


portions[0-7][0]=

"campari", "red vermouth", "soda", (the rest is null)

portions[0-7][1]=
1, 2, 3, (the rest is null)
1

There are 1 best solutions below

2
On BEST ANSWER

As I mentioned in comment, if you are saving data in SD (and writing C++), there is no need to add extra layer of encoding/decoding of JSON, you can read and write data with C++ struct.

Before showing how to to do read/write of struct into file, the struct you shown won't hold the data you want to represent, each cocktail recipe consists of name (a string), and an array of ingredients, each ingredient consists a string, and byte that represent the type of liquor and portion. So we are dealing with a struct within a struct.

typedef struct {
  char liquor[20];
  uint8_t portion;
} Ingridient;

typedef struct {
  char name[20];
  Ingridient ingridients[7];
} Cocktail;

Cocktail cocktails[] = {
    {"Americano", { {"campari", 1}, {"red vermouth", 2}, {"soda", 3} } },
    {"Aviation", { {"gin", 1}, {"cherry liqueur", 2}, {"creme de violette", 3}, {"lemon juice", 4} } },
    {"B52 Cocktail", { {"kahlua", 1}, {"baileys", 2}, {"trand marnier", 3} } }
};

Writing a struct into a file or reading struct from the file is just like writing a series of bytes into a file, all you need to do is to tell where is your struct located in memory (i.e. a pointer to the struct), and what is the size of the struct.

As I don't have an Arduino with SD card with me, so I show it using SPIFFS on ESP32, it should be quite similar to SD, and you should have no problem to convert the code to be used with SD card.

Here is the complete example.

#include <SPIFFS.h>

typedef struct {
  char liquor[20];
  uint8_t portion;
} Ingridient;

typedef struct {
  char name[20];
  Ingridient ingridients[7];
} Cocktail;

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

  Cocktail cocktails[] = {
    {"Americano", { {"campari", 1}, {"red vermouth", 2}, {"soda", 3} } },
    {"Aviation", { {"gin", 1}, {"cherry liqueur", 2}, {"creme de violette", 3}, {"lemon juice", 4} } },
    {"B52 Cocktail", { {"kahlua", 1}, {"baileys", 2}, {"trand marnier", 3} } }
  };
 
  if(!SPIFFS.begin()){
      Serial.println("Error while mounting SPIFFS");
      return;
  }
 
  //--------- Write a struct to file
  File fileToWrite = SPIFFS.open("/cocktails.txt", FILE_WRITE);
  
  if(fileToWrite) {
    for (int i=0; i<3; i++) {
      fileToWrite.write( (uint8_t *) &cocktails[i], sizeof(cocktails[i]) );
    }
  }
  
  fileToWrite.close();
  
  
  //---------- Read a struct from file
  Cocktail c[3];  //struct for holding the content from the file
  
  File fileToRead = SPIFFS.open("/cocktails.txt");
  
  if(fileToRead) {
    Serial.println("Data from file...");
    for (int i=0; i<3; i++) {
      fileToRead.read( (byte *) &c[i], sizeof(c[i]) );
      Serial.println(c[i].name);
      int n = 0;
      while (strlen(c[i].ingridients[n].liquor)) {
        Serial.print(c[i].ingridients[n].liquor);
        Serial.print(" - ");
        Serial.print(c[i].ingridients[n].portion);
        n++;
      }
      Serial.println();
    }
  }

  fileToRead.close();
}
 
void loop() {}