Impossible de récupérer des données d'un fichier JSON

Bonjour à toutes et à tous,

Avant de vous posez ma question, je tiens à préciser que je suis nouveau sur le forum.
J’ai lu les règles du forum mais malheureusement il est peut être possible que j’oublie quelques règles n’ayant pas l’habitude de poster des questions.
Si c’est le cas, je vous remercie grandement de me le faire remarquer afin de pouvoir corriger mes erreurs.
Merci beaucoup.

Je travail actuellement sur un projet personnel. Le but de celui-ci est de récupérer des informations sur les transports en commun. Pour cela, j’utilise une API qui me génère un fichier JSON.

Le site de l’API que j’utilise est celui-ci: http://transport.opendata.ch

La requête HTTP que j’utilise est la suivante: http://transport.opendata.ch/v1/stationboard?station=Cugy%20VD,%20Le%20Moulin&id=8570164&limit=2&transportations=bus&type=departure

J’utilise donc une carte nodeMCU que je programme avec l’IDE d’arduino.

Le code que j’utilise est le suivant (les adresses MAC et tous les autres paramètres réseau présents ici ont été changés):

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

const char* ssid = "MyNetwork";  // Wifi SSID
const char* password = "MyPassword";  // Wifi Password
bool ssidFound = false; // Var that says if the wifi is found

void setup() {
  // Set the speed of the serial and delay 10
  Serial.begin(115200);
  delay(10);

  // Show the MAC address
  Serial.println();
  Serial.print("MAC Address: ");
  Serial.println(WiFi.macAddress());
  Serial.println();
  
  // Call ScanWifi to test if the wifi SSID is found
  ScanWifi();
  
  // If the ssid is found continue the init.
  if (ssidFound == true){
    
    // Connect to WiFi network
    // Print new line for "println" and no new line for "print"
    // Print informations which says the nodeMCU try to connect to the WiFi
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    // Start the connection to the SSID wich is specified above
    WiFi.begin(ssid, password);

    // Do while the nodeMCU card is not connected to the WIFI:
    //  - Wait 500ms
    //  - Print "."
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    } // end While

    //Check if the connection is init.
    if(WiFi.status() == WL_CONNECTED){
      //Display a message that say the connection is init.
      Serial.println();
      Serial.print("TEST 1: Connection ");
      Serial.print(ssid);
      Serial.println(" => Ok!");
    }//end if
  } //end if  
} // end setup

void loop() {
  // Display a message that say the function loop is started
  Serial.println("TEST 2: The function loop is open");

  //Start the HTTP Request
  HTTPClient http;
  http.begin("http://transport.opendata.ch/v1/stationboard?station=Cugy%20VD,%20Le%20Moulin&id=8570164&limit=2&transportations=bus&type=departure");

  // Display a message that say the http.begin is ok
  Serial.println("TEST 3: Request is ok");

  //Init the httpCode
  int httpCode = http.GET();

  //Check the returning code                                                                  
  if (httpCode > 0) {

    //Generated with https://arduinojson.org/v5/assistant/
    const size_t bufferSize = JSON_ARRAY_SIZE(2) + JSON_ARRAY_SIZE(8) + JSON_ARRAY_SIZE(26) + JSON_OBJECT_SIZE(2) + 73*JSON_OBJECT_SIZE(3) + 109*JSON_OBJECT_SIZE(5) + 36*JSON_OBJECT_SIZE(10) + 2*JSON_OBJECT_SIZE(11) + 20080;
    DynamicJsonBuffer jsonBuffer(bufferSize);
    JsonObject& root = jsonBuffer.parseObject(http.getString());

    //Set vars
    JsonObject& stationboard1 = root["stationboard"][1];
    JsonObject& stationboard1_stop = stationboard1["stop"];
    const char* departure = stationboard1_stop["departure"];
    Serial.println("TEST 4: departure==stationboard1_stop");
    Serial.println(departure);

    //Close the http object
    http.end();   //Close connection
    Serial.println("TEST 5: http.end => OK");
  }//end if (httpCode > 0)

  // Wait 10 min.
  delay(600000);
}// end loop

//  Name: ScanWifi
//  Goal: Test if the wifi ssid is founded
//  Param: none
//  Return: none
void ScanWifi() {

  // Get how many Wifi connection can be scaned
  int numberOfNetworks = WiFi.scanNetworks();
  
  // Display all scanned Wifi
  for(int i=0; i<numberOfNetworks; i++){

      // Print network name
      Serial.print("Network name: ");
      Serial.println(WiFi.SSID(i));

      // If the SSID scaned is eq. SSId to connect display a message and set var "ssidFound" true
      if (WiFi.SSID(i)==ssid){
        Serial.print(ssid);
        Serial.println(" NETWORK IS FOUND!!");
        ssidFound = true;
      }// end if
      Serial.println("-----------------------");
  }//end For
}//end ScanWifi

Le retour sur le moniteur serie est le suivant:

MAC Address: XX:XX:XX:XX:XX:XX

Network name: otherNetwork
-----------------------
Network name: otherNetwork
-----------------------
Network name: otherNetwork
-----------------------
Network name: otherNetwork
-----------------------
Network name: otherNetwork
-----------------------
Network name: MyNetwork
MyNetwork NETWORK IS FOUND!!
-----------------------
Network name: otherNetwork
-----------------------
Network name: MyNetwork
MyNetwork NETWORK IS FOUND!!
-----------------------


Connecting to MyNetwork
.......
TEST 1: Connection MyNetwork => Ok!
TEST 2: The function loop is open
TEST 3: Request is ok
TEST 4: departure==stationboard1_stop

TEST 5: http.end => OK

Mon problème est que entre le test 4 et le test 5 je devrai obtenir une date de type 2018-07-09T16:38:00+0200

Mais rien ne s’affiche.

Pour créer ce code, je me suis inspiré du tutoriel présent sur ce site: http://www.instructables.com/id/ESP8266-Parsing-JSON/

Des librairies suivantes:

  • ArduinoJson.h
  • ESP8266WiFi.h
  • ESP8266HTTPClient.h

Et de l’assistant de ArduinoJson: Assistant | ArduinoJson 5

Je vous remercie d’avance pour votre aide. :smiley:

ça ne serait pas plutôt quelque chose du genre :

const char* departure = stationboard["stop"]["departure"];

lesept:
ça ne serait pas plutôt quelque chose du genre :

const char* departure = stationboard["stop"]["departure"];

Merci de ta réponse, mais malheureusement mon moniteur n'affiche toujours rien. :sob:

J'ai également testé ceci mais le résultat reste inchangé.

const char* departure = root["stationboard"][1]["stop"]["departure"];

et :

const char* departure = root["station"]["stationboard"][1]["stop"]["station"]["departure"];

lesept:
et :

const char* departure = root["station"]["stationboard"][1]["stop"]["station"]["departure"];

Si on observe la composition du fichier JSON (voir image ci-dessous) de manière logique ça ne fonctionne pas. Car à la racine, on a 2 éléments:

  • Station, qui contient des données.
  • Et Stationboard, qui en contient d'autres.

La valeur qui m'intéresse se trouve dans stationboard=>1=>stop=>departure.

Donc de manière logique ça ne peut pas être:

 const char* departure = root["station"]["stationboard"][1]["stop"]["station"]["departure"];

Mais ton message m'a mis le doute et j'ai quand même essayé le code ci-dessus et donc confirme ce que je dis car ça ne fonctionne pas.

En écrivant ce message j'ai aussi trouvé bizarre que le [1] ne soit pas balisé avec des "" j'ai donc également essayé mais ça ne fonctionne pas (peut-être normal au final car il n'est pas considéré comme du texte ici mais comme une valeur numérique?).

Mais merci quand même pour ton message.

Si tu regardes le json brut (bien que ton image soit plus explicite, mais je ne pouvais pas le voir comme ça) tu verras des [ et ], c'est une sorte de tableau avec des lignes ou colonnes identiques. Ces ensembles sont numérotés à partir de 0.

Essaye de te familiariser avec la syntaxe : essaye de trouver le code or afficher la première valeur du json au complet, puis la seconde, puis saute un niveau et ainsi de suite

Genre :

const char* departure = root["station"]["id"];
const char* departure = root["station"]["name"];
const char* departure = root["station"]["coordinate"]["type"];

Comment fais-tu pour avoir cette visu ordonnée ?

Normalement, cette expression devrait être la bonne

root["stationboard"][1]["stop"]["departure"];

Tu devrais peut-être la faire par partie comme dans le code de l'assistant
Cela te permettrait d'afficher des états intermédiaires pour comprendre le problème.

JsonObject& stationboard1 = root["stationboard"][1];
JsonObject& stationboard1_stop = stationboard1["stop"];
const char* stationboard1_stop_departure = stationboard1_stop["departure"]; // "2018-07-09T23:13:00+0200"

lesept:
Si tu regardes le json brut (bien que ton image soit plus explicite, mais je ne pouvais pas le voir comme ça) tu verras des [ et ], c'est une sorte de tableau avec des lignes ou colonnes identiques. Ces ensembles sont numérotés à partir de 0.

Essaye de te familiariser avec la syntaxe : essaye de trouver le code or afficher la première valeur du json au complet, puis la seconde, puis saute un niveau et ainsi de suite

Genre :

const char* departure = root["station"]["id"];

const char* departure = root["station"]["name"];
const char* departure = root["station"]["coordinate"]["type"];




Comment fais-tu pour avoir cette visu ordonnée ?

Malheureusement, rien que la première ligne ne fonctionne pas, je pense que l'erreur vient d'ailleurs ou d'une mauvaise utilisation de la librairie mais si je me réfère au tuto.: http://www.instructables.com/id/ESP8266-Parsing-JSON/ mon code devrait être fonctionnel ^^

Quant à la visu ordonnée, de base j'utilise comme navigateur WEB opera, j'exécute ma requête, sauvegarde le fichier JSON et l'ouvre avec Mozilla Firefox

fdufnews:
Normalement, cette expression devrait être la bonne

root["stationboard"][1]["stop"]["departure"];

Tu devrais peut-être la faire par partie comme dans le code de l'assistant
Cela te permettrait d'afficher des états intermédiaires pour comprendre le problème.

JsonObject& stationboard1 = root["stationboard"][1];

JsonObject& stationboard1_stop = stationboard1["stop"];
const char* stationboard1_stop_departure = stationboard1_stop["departure"]; // "2018-07-09T23:13:00+0200"

Si on se fie au code initial que j'ai présenté au début de ce topic, malheureusement, c'est ce que j'avais déjà entré :sob: la seule différence est le nom de ma constante car je trouve plus pertinent ce nom pour mon code mais cette modification n'affecte pas mon code.

//Set vars
    JsonObject& stationboard1 = root["stationboard"][1];
    JsonObject& stationboard1_stop = stationboard1["stop"];
    const char* departure = stationboard1_stop["departure"];
    Serial.println("TEST 4: departure==stationboard1_stop");
    Serial.println(departure);

J’ai utilisé la bibli Arduinojson il y a quelques temps, voici le code s’il peut t’aider

Test_Json.ino (5.84 KB)

lesept:
J'ai utilisé la bibli Arduinojson il y a quelques temps, voici le code s'il peut t'aider

Merci je vais y jeter un oeil le plus vite possible, j'informe quand j'ai des nouvelles, en attendant si quelqu'un comprend pourquoi je n'ai rien en output je le remercie d'avance de me l'indiquer.

lesept:
J'ai utilisé la bibli Arduinojson il y a quelques temps, voici le code s'il peut t'aider

Malheureusement après plusieurs essais, toujours rien.

Je me demande si le problème ne viendrait pas de là.

 JsonObject& root = jsonBuffer.parseObject(http.getString());

http.getString() retourne un objet String alors que parseObject semble attendre un char*

fdufnews:
Je me demande si le problème ne viendrait pas de là.

 JsonObject& root = jsonBuffer.parseObject(http.getString());

http.getString() retourne un objet String alors que parseObject semble attendre un char*

Une réponse de Benoit Blanchon, l’auteur de la bibli ArduinoJSON himself :

parseObject() can take a String as input; but in that case, it will have to make a copy of it in the JsonBuffer, so you need to increase the size of the buffer.

As an alternative, you can ignore the const-ness of the string so as to avoid the duplication.

JsonObject& root = jsonBuffer.parseObject(static_const<char*>(myString.c_str()));
This will modify the string in place.
It is safe, as long as the String stays in memory.

Dans ton code, je suppose que cette ligne est fournie par le calculateur de BBlanchon sur son site, avec des données qui correspondent à ton cas d’utilisation ?

const size_t bufferSize = JSON_ARRAY_SIZE(2) + JSON_ARRAY_SIZE(8) + JSON_ARRAY_SIZE(26) + JSON_OBJECT_SIZE(2) + 73*JSON_OBJECT_SIZE(3) + 109*JSON_OBJECT_SIZE(5) + 36*JSON_OBJECT_SIZE(10) + 2*JSON_OBJECT_SIZE(11) + 20080;

EDIT : Essaye l’assistant. Tu copies : colles l’ensemble de ton contenu dans la case Input et il donne :

  • Les paramètres de buffer size :
    JSON_ARRAY_SIZE(2) + JSON_ARRAY_SIZE(8) + JSON_ARRAY_SIZE(26) + JSON_OBJECT_SIZE(2) + 73*JSON_OBJECT_SIZE(3) + 109*JSON_OBJECT_SIZE(5) + 36*JSON_OBJECT_SIZE(10) + 2*JSON_OBJECT_SIZE(11)
    Ça a l’air pareil sauf le 20080.

  • Le code pour parser les données

JsonObject& root = jsonBuffer.parseObject(json);

JsonObject& station = root["station"];
const char* station_id = station["id"]; // "8570164"
const char* station_name = station["name"]; // "Cugy VD, Le Moulin"

JsonObject& station_coordinate = station["coordinate"];
const char* station_coordinate_type = station_coordinate["type"]; // "WGS84"
float station_coordinate_x = station_coordinate["x"]; // 46.588931
float station_coordinate_y = station_coordinate["y"]; // 6.642583

JsonObject& stationboard0 = root["stationboard"][0];
const char* stationboard0_stop_departure = stationboard0_stop["departure"]; // "2018-07-11T10:28:00+0200"

J’attire votre attention sur ce point dans la réponse de Benoit Blanchon que tu cites:
JsonObject& root = jsonBuffer.parseObject(static_const<char*>(myString**.c_str()**));
Le .c_str assure la conversion de type!!