Répondre à la discussion
Affichage des résultats 1 à 16 sur 16

ESP32 HTTPClient récupération JSON données MTO



  1. #1
    mweber

    ESP32 HTTPClient récupération JSON données MTO


    ------

    Bonjour à tous,

    j'espère que vous avez la forme !


    Cela fait des jours que je me casse la tête à vouloir récupérer avec un µ-Ctrl ESP-32 la météo (de Nantes) depuis le site https://www.prevision-meteo.ch/services/json/nantes pour ensuite parser le JSON
    (Vous pouvez tester librement l'url dans votre navigateur)

    Le code de base est de la forme :
    Code:
    #include <HTTPClient.h>               // Permet la connexion à un serveur HTTP
    
    ....
    
    WiFiClient client;  // or WiFiClientSecure for HTTPS
    HTTPClient http;
    
    // Send request
    http.begin(client, "http://arduinojson.org/example.json");
    http.GET();
    
    // Print the response
    Serial.print(http.getString());
    
    // Disconnect
    http.end();
    Au final, soit j'arrive à afficher (immédiatement après le retour "code 200") les données sur la liaison série, mais il en manque (le JSON fait en gros 52 ko or j'en affiche +/-40ko) => Cela viens du fait que mon objet string est trop gros pour l'espace RAM contigu.

    J'ai essayé de faire :

    String Donnes;
    Donnes.reserve(52500); => retourne -1 => Car pas assez de "RAM heap" de libre en continu (fragmentation)

    Par contre, en variable globale, en bon vieux C, j'arrive bien à allouer un tableau de char de 52500 octets, que je remplis avec :

    Code:
    strncpy(Toto, http.getString().c_str(), 54000);
    MAIS ! Dans ce cas, après (une pause de plusieurs secondes )le serveur me renvoie -1 (HTTPC_ERROR_CONNECTION_REFUSE D) ou -5 (HTTPC_ERROR_CONNECTION_LOST)


    Voici mon code :

    Code:
    const char* host = "https://www.prevision-meteo.ch/services/json/nantes";   // Web site web où se connecter
    if (!WiFi.isConnected())                                                                              // On est pas connecté à internet => Quitte la fonction
      {
      #ifdef DEBUG_RS232 
        Serial.print(F("\r\nImpossible de récupérer la meteo : "));
        Serial.print(host);
        Serial.print(F(". Aucune connexion internet n'est disponible..."));  
      #endif
      return;            // On a pas pu se connecter à internet => Quitte la fonction
      }
    
    HTTPClient http;  // Instance un client HTTP
    
    
    http.setTimeout(10000);             // timeout (avec ou sans c'est pareil)  :(
    http.setConnectTimeout(10000); // timeout connexion (avec ou sans c'est pareil)  :(
    
    http.useHTTP10(true);  // Pour éviter l'erreur:  deserializeJson() failed: InvalidInput  cf :
    http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);  // Permet les redirections
    
    http.begin(host);           // connexion  au site web
    
    int httpCode = http.GET();  // Envoi de la requête HTTP GET à l'API de prévision météo
    
    // Vérification du code de statut de la réponse (200 = > OK)  mais j'ai -1 ou -5
    if (httpCode > 0) 
      {
      #ifdef DEBUG_RS232  
        Serial.print("\n\nHTTP Code : ");  Serial.println(httpCode);
      #endif
    
    
    ////////
    
    Serial.println(http.getString());  // Test Affichage sur la liaison série (Ça marche mais il manque des données, on reçoit environ 40 ko)
    
    
    // OU
    
    strncpy(Toto, http.getString().c_str(), 54000);   //(Avec un char Toto[52000];  déclaré dans main.cpp => Erreur -1 ou -5 
    Serial.println(Toto);
    
    //  OU
    
    //WiFiClient* stream = http.getStreamPtr();
    int idx = 0;
    
      while (http.available()) 
              {
              char c = http.read();
             // Toto[idx++] = stream->read();   //(Avec un char Toto[52000];  déclaré dans main.cpp => Erreur -1 ou -5 
              Serial.print(c);
              }
    Serial.println("\n\n");
    Serial.println(Toto);
    
    
    /// OU
    
      // Analyse syntaxique du flux JSON recu du site web
      DeserializationError error = deserializeJson(doc, http.getStream(), DeserializationOption::Filter(filter));
    // ===> Fichier tronqué deserializeJson écoue 
    
    //////
    
    // ON PARSE ENSUITE LE JSON
    
    [...]
    
      }
    else 
      { 
      #ifdef DEBUG_RS232    
        Serial.print("Erreur lors de la requête: ");
        Serial.println(httpCode);
      #endif
      }
    
    http.end();  // Déconnection du site web
    }
    Si vous avez des idées ? (ca marchait sur ESp8266 avec moins de RAM mais en utilisant
    Code:
    std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);
    bool mfln = client->probeMaxFragmentLength(host, HTTPS_PORT, 1024);
    Version "chunked", mais j'arrive pas à le faire avec HTTPClient sur ESP32

    Avez vous une idée ?
    Merci

    -----
    Dernière modification par mweber ; 17/03/2023 à 17h36. Motif: orthographe....

  2. #2
    bobflux

    Re : ESP32 HTTPClient récupération JSON données MTO

    http.getString() va réserver la mémoire pour la string donc si le problème est qu'il y a pas assez de mémoire ça va pas marcher, quoi que tu mettes autour...

    La lecture caractère par caractère ou par chunk semble être la seule solution.

  3. #3
    mweber

    Re : ESP32 HTTPClient récupération JSON données MTO

    Merci !

    C'est pour cela que j'ai tenté
    Code:
     char c = http.read();
    ... sans plus de résultat.

    Je n'arrive pas à faire marcher un code en mode chunked (avec l'esp32), aurais tu vu un exemple qq. part ?

    Au plaisir,

    Matthieu

  4. #4
    Biname

    Re : ESP32 HTTPClient récupération JSON données MTO

    Salut,
    Je connais mal le sujet, mais j'aime chercher
    https://esp32.com/viewtopic.php?f=19&p=107187#p107149

    Lui aussi cale autour de 40k

    Biname

  5. A voir en vidéo sur Futura
  6. #5
    mweber

    Re : ESP32 HTTPClient récupération JSON données MTO

    Yep, j'avais vu....

    Sans doute le même pb d'allocation RAM.

    Étrange (les APIs foisonnent) de ne pas trouver d'exemple en utilisant le chunk (qui marchait bien sur ESP8266).
    Mais on ne retrouve pas les mêmes méthodes dans la classe HTTPClient de l'esp 32
    Dernière modification par mweber ; 19/03/2023 à 18h08.

  7. #6
    bobflux

    Re : ESP32 HTTPClient récupération JSON données MTO

    Si je vais voir là

    https://github.com/espressif/arduino...c/HTTPClient.h

    je ne trouve pas la méthode read() utilisée dans ton code

  8. #7
    umfred

    Re : ESP32 HTTPClient récupération JSON données MTO

    en parcourant le github on tombe sur cet exemple qui lit les données depuis un stream par paquets
    https://github.com/espressif/arduino...HttpClient.ino

  9. #8
    mweber

    Re : ESP32 HTTPClient récupération JSON données MTO

    Ok merci a tous, je vais tester ça demain vendredi...

    Dans le pire des cas je tenterais un passage par la carte SD (une écriture de 50 ko tout les 3 heures, ça va pas la tuer !)

    Les alertes de réponse au forum atterrissaient dans mes spams :!

    Matt

  10. #9
    bobflux

    Re : ESP32 HTTPClient récupération JSON données MTO

    Tu n'aurais pas un ordinateur constamment allumé, NAS, Pi de domotique, etc ? Si oui tu peux mettre un bout de python dessus qui interroge l'API, parse le gros JSON, et ne donne à l'ESP32 que les données intéressantes...

  11. #10
    Seb.26

    Re : ESP32 HTTPClient récupération JSON données MTO

    pourquoi vouloir stocker toute la réponse et la traiter ensuite ?!!

    -> lis la réponse char par char et analyse la pour la traiter au fur et à mesure ... de toute façon si demain tes data passent à 100ko tu sera de toute façon de nouveau KO ...
    << L'histoire nous apprend que l'on apprend rien de l'histoire. >>

  12. #11
    mweber

    Re : ESP32 HTTPClient récupération JSON données MTO

    Salut Seb,

    Justement c'est ce que je voudrais le faire, (et ai déjà fait avec l'ESP8266) mais le code
    Code:
     while (http.available()) 
              {
              char c = http.read();
             // Toto[idx++] = stream->read();   //(Avec un char Toto[52000];  déclaré dans main.cpp =>   int httpCode = http.GET();   httpCode  = Erreur -1 ou -5 
              Serial.print(c);
              }

    Merdoie...

    Attendez, je vais vous faire un exemple dans un fichier .ino autonome...

  13. #12
    mweber

    Re : ESP32 HTTPClient récupération JSON données MTO

    Ca progresse !

    J'ai un code qui arrive a afficher en mode chuked tout les caractères du JSON envoyé par le serveur

    Mais ca plante si j'essaye de les mettre dans un char Resultat[52000] avec un strncat() et puis c'est dommage de gaspiller 27 % de RAM...

    De ce que je lis dans la doc de la lib arduinojson => https://arduinojson.org/v6/how-to/de...arge-document/

    This technique only works for arrays; you cannot deserialize a large object in chunks.
    Donc vu le fichier json que je récupère, ais-je d'autre choix que de tout stoker en RAM ?

    Code:
    #include <Arduino.h>
    
    #include <WiFi.h>
    #include <WiFiMulti.h>
    
    #include <HTTPClient.h>
    
    // Décodages fichiers JSON
    #define ARDUINOJSON_DECODE_UNICODE 0  // Ne gère pas l'UTF-16 (permet un petit gain en place en flash)
    #include <ArduinoJson.h>           // Gestion des fichiers json
    
    WiFiMulti wifiMulti;
    
    char Resultat[52000] = {0,};
    
    /////////////////////////////
    void setup() 
    /////////////////////////////
    {
    Serial.begin(115200);
    
    Serial.println();
    Serial.println();
    Serial.println();
    
    
    
    wifiMulti.addAP("Matt et Mu", "jenecroispascombel000,");
    }
    
    
    /////////////////////////////
    void loop() 
    /////////////////////////////
    {
    // wait for WiFi connection
    if((wifiMulti.run() == WL_CONNECTED)) 
      {
      HTTPClient http;
    
    
      DynamicJsonDocument doc(50000);  // Document qui contiendra l'analyse syntaxique du flux JSON
      StaticJsonDocument<370> filter;
    
      filter["city_info"]          = true;
      filter["current_condition"]  = true;
      filter["fcst_day_0"]["tmin"] = true;
      filter["fcst_day_0"]["tmax"] = true; 
      filter["fcst_day_0"]["condition_key"] = true; 
      filter["fcst_day_1"]["tmin"] = true;
      filter["fcst_day_1"]["tmax"] = true;
      filter["fcst_day_1"]["condition_key"] = true; // Filtres ne retenant que certains items
      filter["fcst_day_2"]["tmin"] = true;          // pour alléger la fonction deserializeJson() => gain en RAM
      filter["fcst_day_2"]["tmax"] = true;
      filter["fcst_day_2"]["condition_key"] = true; 
      filter["fcst_day_3"]["tmin"] = true;
      filter["fcst_day_3"]["tmax"] = true;
      filter["fcst_day_3"]["condition_key"] = true; 
      filter["fcst_day_4"]["tmin"] = true;
      filter["fcst_day_4"]["tmax"] = true;
      filter["fcst_day_4"]["condition_key"] = true; 
    
      // serializeJsonPretty(filter, Serial);  // Pour tester au besoin validité du filtre
    
      Serial.print("[HTTP] begin...\n");
    
    
      // configure server and url
      http.begin("https://www.prevision-meteo.ch/services/json/nantes");
    
      Serial.print("[HTTP] GET...\n");
      
      // start connection and send HTTP header
      int httpCode = http.GET();
      if(httpCode > 0) 
        {
        Resultat[0] = '\0';
          
        // HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTP] GET... code: %d\n", httpCode);
    
        // file found at server
        if(httpCode == HTTP_CODE_OK) 
          {
    
          // get length of document (is -1 when Server sends no Content-Length header)
          int len = http.getSize();
    
          // create buffer for read
          char buff[128] = { 0 };
    
          // get tcp stream
          WiFiClient * stream = http.getStreamPtr();
    
          // read all data from server
          while(http.connected() && (len > 0 || len == -1)) 
            {
            // get available data size
            size_t size = stream->available();
    
            if(size) 
              {
              // read up to 128 byte
              int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
    
              // write it to Serial
              //Serial.write(buff, c);      //  <============== Ca marche j'ai bien tout le texte
              strncat(Resultat, buff, c);   //  <============== Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
              yield();                                 
              if(len > 0)  len -= c;
              }
    
            delay(1);
            }
    
          Serial.print("\n[HTTP] connection closed or file end.\n");
          }
        } 
      else   Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());   
      http.end();
      Serial.print("deserializeJson en cours: "); 
    
      DeserializationError error = deserializeJson(doc, Resultat, DeserializationOption::Filter(filter));
      if (error) // Problème l'analyse du json...
        {
        Serial.print("deserializeJson() failed: ");  
        Serial.println(error.c_str());
        }  
      }
    
    delay(15000);
    }

  14. #13
    bobflux

    Re : ESP32 HTTPClient récupération JSON données MTO

    La library ArduinoJSON fonctionne sur le modèle DOM, elle veut le fichier complet en mémoire avant de parser.

    À la place tu pourrais utiliser une library qui fonctionne sur le modèle du streaming qui permet d'analyser le fichier à la volée et de ne garder que les bouts qui t'intéressent.

    https://github.com/mrfaptastic/json-streaming-parser2

    https://github.com/mrfaptastic/json-...ecastHandler.h

  15. #14
    mweber

    Re : ESP32 HTTPClient récupération JSON données MTO

    Ok ça reviendrai à ce que j'ai fait avec l'ESP8266, à savoir, développer mon propre parseur JSON

    Hum, par curiosité, je voudrai quand même piger pourquoi le code que j'ai mis en exemple plante, sachant que j'ai alloué 52000 octets de RAM... normalement l’espace d'alloc contigu peut les contenir

    Merci

  16. #15
    bobflux

    Re : ESP32 HTTPClient récupération JSON données MTO

    Citation Envoyé par mweber Voir le message
    Hum, par curiosité, je voudrai quand même piger pourquoi le code que j'ai mis en exemple plante, sachant que j'ai alloué 52000 octets de RAM...
    Parce que le json fait 53751 octets et que tu vérifies pas que ça rentre dans le buffer de 52000 octets

    La longueur doit changer en fonction du jour et de l'heure, ça dépend de ce qu'il y a dedans...

  17. #16
    mweber

    Re : ESP32 HTTPClient récupération JSON données MTO

    Humm, le temps change trop souvent ces temps ci !

    Merci !

Discussions similaires

  1. Excel - intégration de données JSON via requête sur site WEB
    Par bemo47 dans le forum Programmation et langages, Algorithmique
    Réponses: 9
    Dernier message: 06/03/2020, 14h07
  2. récupération de données
    Par zenorph dans le forum Logiciel - Software - Open Source
    Réponses: 2
    Dernier message: 13/10/2015, 09h21
  3. Récupération de données, PL7
    Par Galgante dans le forum Logiciel - Software - Open Source
    Réponses: 0
    Dernier message: 13/10/2008, 10h59
  4. Recuperation De Donnees
    Par GDS35 dans le forum Logiciel - Software - Open Source
    Réponses: 6
    Dernier message: 05/04/2008, 07h40
  5. Recupération de données
    Par lordgodgiven dans le forum Matériel - Hardware
    Réponses: 2
    Dernier message: 17/09/2006, 10h17
Découvrez nos comparatifs produits sur l'informatique et les technologies.