ArduinoJSON and some "different" JSON formats

Edit: using a Xiao ESP32-C6 with Arduino code

Hi all, Clovis from FritzenLab blog here. I am trying to use ArduinoJSON in the Arduino IDE 2.3.3 nightly to parse currency conversion JSONs and show in an OLED display. The first one I was able to parse (and it worked beautifully) by removing parts of it is:

[{"code":"USD","codein":"EUR","name":"Dólar Americano/Euro","high":"0.9174","low":"0.9129","varBid":"0.0002","pctChange":"0.02","bid":"0.9142","ask":"0.9144","timestamp":"1728680370","create_date":"2024-10-11 17:59:30"}]

that comes from this URL: https://economia.awesomeapi.com.br/json/USD-EUR/1 . What I had to do is use

payload.replace("[", "");
payload.replace("]", "");

in order to remove the brackets so that ArduinoJSON could do its job. Now the second URL

(https://api.freecurrencyapi.com/v1/latest?apikey=fca_live_VY5LigvrlRZa8DDEjEmC6KKqZXVjn4krRXHLkoA3)

that produces this JSON

{"data":{"AUD":1.4812302414,"BGN":1.7857002284,"BRL":5.6023007216,"CAD":1.3760501974,"CHF":0.8568100864,"CNY":7.06607111,"CZK":23.1031928798,"DKK":6.8207610011,"EUR":0.913750181,"GBP":0.7652001405,"HKD":7.7681411973,"HRK":6.4777808725,"HUF":366.5991296416,"IDR":15560.395268402,"ILS":3.7586104659,"INR":84.0984135739,"ISK":136.2421360606,"JPY":149.12577678,"KRW":1346.7958727075,"MXN":19.2684727479,"MYR":4.2857108042,"NOK":10.693421149,"NZD":1.636070264,"PHP":57.2133870147,"PLN":3.9219305098,"RON":4.545630534,"RUB":95.8006011973,"SEK":10.3671417216,"SGD":1.3037801975,"THB":33.1420633372,"TRY":34.2741747093,"USD":1,"ZAR":17.3821821208}}

Had me trying to remove the parts below, but it will not compile because of the "" inside the string

{"data":

and the final "}" doing

payload.replace("{"data":", "");
    payload.replace("}}", "}");

So my question is how to get out of this situation, since these JSON are not the "standard" the ArduinoJSON library is expecting?

Full code is below:

// Inclusão da(s) biblioteca(s)
#include <WiFi.h>       // Biblioteca nativa do ESP32
#include <HTTPClient.h> // Biblioteca nativa do ESP32
#include <ArduinoJson.h>

// Configurações da rede WiFi à se conectar
const char* ssid = "";
const char* password = "";

String payload;

HTTPClient http; // o objeto da classe HTTPClient

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);

#define LOGO16_GLCD_HEIGHT 64 
#define LOGO16_GLCD_WIDTH  128

long currenttime;
long oldtime;

void setup() {

  // Inicia Serial
  Serial.begin(115200);
  Serial.println();
  delay(1000);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  delay(2000);
  // Clear the buffer.
  display.clearDisplay();

  WiFi.disconnect(); // Desconecta do WiFI se já houver alguma conexão
  WiFi.mode(WIFI_STA); // Configura o ESP32 para o modo de conexão WiFi Estação
  Serial.println("[SETUP] Tentando conexão com o WiFi...");
  WiFi.begin(ssid, password); // Conecta-se à rede
  if (WiFi.waitForConnectResult() == WL_CONNECTED) // aguarda até que o módulo se
    //                                                  conecte ao ponto de acesso
  {
    Serial.println("[SETUP] WiFi iniciado com sucesso!");
  } else
  {
    Serial.println("[SETUP] Houve falha na inicialização do WiFi. Reiniciando ESP.");
    ESP.restart();
  }

  http.begin("https://api.freecurrencyapi.com/v1/latest?apikey=fca_live_VY5LigvrlRZa8DDEjEmC6KKqZXVjn4krRXHLkoA3"); // configura o URL para fazer requisição no servidor
    // entra em um laço de repetição infinito
  //while (1);
}

void loop() {
  
  currenttime= millis();
  if(currenttime - oldtime > 30000){
    oldtime= millis();

    Serial.println("[HTTP] GET...");
    int httpCode = http.GET(); // inicia uma conexão e envia um cabeçalho HTTP para o
    //                              URL do servidor configurado
    Serial.print("[HTTP] GET... código: ");
    Serial.println(httpCode);
    if (httpCode == HTTP_CODE_OK) // se o cabeçalho HTTP foi enviado e o cabeçalho de
      //                               resposta do servidor foi tratado, ...
    {
      Serial.println("[HTTP] GET... OK! Resposta: ");

      payload = http.getString(); // armazena a resposta da requisição
      Serial.println(payload); // imprime a resposta da requisição
    } else // se não, ...
    {
      Serial.print("HTTP GET... Erro. Mensagem de Erro: ");
      Serial.println(http.errorToString(httpCode).c_str()); // Imprime a mensagem de erro da requisição
    }

    http.end();// Fecha a requisição HTTP

  
    JsonDocument remotedata;

    

    payload.replace("{"data":", "");
    payload.replace("}}", "}");

    DeserializationError error = deserializeJson(remotedata, (char*) payload.c_str());

    
    double conversion= remotedata["EUR"][0];
    Serial.println(conversion, 4);

    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,0);
    display.println("EUR to USD");
    display.setCursor(15,10);
    display.println("One USD buys ");
    display.setCursor(15,20);
    display.println(conversion, 4);
    display.setCursor(50,20);
    display.println(" Euros");
    display.display();
  }

}

Hi @clovisf

There is no need to do that. Just use [0] to get the first element in the array.

For example:

#include <ArduinoJson.h>

void setup() {
  Serial.begin(115200);
  Serial.println();
  delay(1000);

  String payload = "[{\"code\":\"USD\",\"codein\":\"EUR\",\"name\":\"Dólar Americano/Euro\",\"high\":\"0.9174\",\"low\":\"0.9129\",\"varBid\":\"0.0002\",\"pctChange\":\"0.02\",\"bid\":\"0.9142\",\"ask\":\"0.9144\",\"timestamp\":\"1728680370\",\"create_date\":\"2024-10-11 17:59:30\"}]";
  JsonDocument remotedata;
  deserializeJson(remotedata, (char*)payload.c_str());
  double high = remotedata[0]["high"];
  Serial.println(high);
}

void loop() {}

Don't try to remove parts. You can simply use ["data"] to get the data object.

For example:

#include <ArduinoJson.h>

void setup() {
  Serial.begin(115200);
  Serial.println();
  delay(1000);

  String payload = "{\"data\":{\"AUD\":1.4812302414,\"BGN\":1.7857002284,\"BRL\":5.6023007216,\"CAD\":1.3760501974,\"CHF\":0.8568100864,\"CNY\":7.06607111,\"CZK\":23.1031928798,\"DKK\":6.8207610011,\"EUR\":0.913750181,\"GBP\":0.7652001405,\"HKD\":7.7681411973,\"HRK\":6.4777808725,\"HUF\":366.5991296416,\"IDR\":15560.395268402,\"ILS\":3.7586104659,\"INR\":84.0984135739,\"ISK\":136.2421360606,\"JPY\":149.12577678,\"KRW\":1346.7958727075,\"MXN\":19.2684727479,\"MYR\":4.2857108042,\"NOK\":10.693421149,\"NZD\":1.636070264,\"PHP\":57.2133870147,\"PLN\":3.9219305098,\"RON\":4.545630534,\"RUB\":95.8006011973,\"SEK\":10.3671417216,\"SGD\":1.3037801975,\"THB\":33.1420633372,\"TRY\":34.2741747093,\"USD\":1,\"ZAR\":17.3821821208}}";
  JsonDocument remotedata;
  deserializeJson(remotedata, (char*)payload.c_str());
  double conversion = remotedata["data"]["EUR"];
  Serial.println(conversion, 4);
}

void loop() {}

This is a faulty premise. This is absolutely standard JSON and the library can handle any standard JSON. So use the library as intended instead of trying to do hacky string manipulations on the JSON.

the JSON you posted looks like this when you indent

[
    {
        "code": "USD",
        "codein": "EUR",
        "name": "Dólar Americano/Euro",
        "high": "0.9174",
        "low": "0.9129",
        "varBid": "0.0002",
        "pctChange": "0.02",
        "bid": "0.9142",
        "ask": "0.9144",
        "timestamp": "1728680370",
        "create_date": "2024-10-11 17:59:30"
    }
]

it's totally legit.

it's an array with only one entry.

Each entry in the array provides information about a specific exchange rate, in this case, between the US Dollar and the Euro.

so as @ptillisch said, get the first entry of the array by using [0] and then parse it.

the ArduinoJSON library offers an assistant you can use. You paste in the JSON you want to parse and a few other information and it spits out code you can use.

// const char* input;
// size_t inputLength; (optional)

JsonDocument doc;

DeserializationError error = deserializeJson(doc, input, inputLength);

if (error) {
  Serial.print("deserializeJson() failed: ");
  Serial.println(error.c_str());
  return;
}

JsonObject root_0 = doc[0];
const char* root_0_code = root_0["code"]; // "USD"
const char* root_0_codein = root_0["codein"]; // "EUR"
const char* root_0_name = root_0["name"]; // "Dólar Americano/Euro"
const char* root_0_high = root_0["high"]; // "0.9174"
const char* root_0_low = root_0["low"]; // "0.9129"
const char* root_0_varBid = root_0["varBid"]; // "0.0002"
const char* root_0_pctChange = root_0["pctChange"]; // "0.02"
const char* root_0_bid = root_0["bid"]; // "0.9142"
const char* root_0_ask = root_0["ask"]; // "0.9144"
const char* root_0_timestamp = root_0["timestamp"]; // "1728680370"
const char* root_0_create_date = root_0["create_date"]; // "2024-10-11 17:59:30"

(you can also extract then data as another type than const char *)