[Resolu] api openweathermap.org

Bonjour à toutes et à tous.

Je souhaiterais grâce à openweathermap.org savoir si il va pleuvoir dans la journée.

Le principe est d’envoyer une requête à openweathermap avec le nom de la ville et un API généré sur le site:

https://samples.openweathermap.org/data/2.5/forecast?zip=94040&appid=439d4b804bc8187953eb36d2a8c26a02

la page internet nous retourne les prévisions des 5 prochains jours échelonné de 3h:

Je donne le début :
(j’ai rajouter des retours à la ligne pour la visibilité)

{"cod":"200","message":0,"cnt":40,"list":[{"dt":1588928400,"main":{"temp":289.62,
"feels_like":288.03,"temp_min":289.62,"temp_max":291.62,
"pressure":1015,"sea_level":1015,"grnd_level":1012,"humidity":77,"temp_kf":-2},
"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],
"clouds":{"all":94},"wind":{"speed":3.35,"deg":109},
"sys":{"pod":"d"},"dt_txt":"2020-05-08 09:00:00"},

Dans le principe je pensais récupéré les 8 première “id” qui indique l’état des conditions météo et les stocker indépendamment.

Mais pour le moment j’essaye juste de retourner cette page dans le terminal avec ce code :

#include <ESP8266WiFi.h>

 
const char* ssid = "";
const char* password = "";
  
const char* host = "api.openweathermap.org";
String api = "";
String ville = "";


char reponseOpenW = 0;

void setup()
{
  
  Serial.begin(115200);
  Serial.println("Début Setup");
  
  Serial.printf("Connection à %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connecté");
  WiFiClient client;
  
  Serial.print("Connexion à openweathermap.org ");
  delay(100);
  if (client.connect(host, 80))
  {
    Serial.println("Connecté!");
    delay(500);
    
    
    client.print(String("GET /data/2.5/forecast?q=" + ville + "&APPID=" + api + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "Connection: close\r\n" +
                 "\r\n"
                ));
    Serial.println("requête envoyer");     


  if(client.available()) {
    reponseOpenW = client.read();
    Serial.print(reponseOpenW);
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("Deconnexion !");
    client.stop();
    while(1); 
  }

  }

  Serial.println("Fin Setup");  
}

void loop()
{
}

Déjà est ce la bonne méthode ou il y à mieux ?
Et où est l’erreur ?

Par avance merci

Bonjour,

Personellement j'utilise ArduinoJson Tu as un exemple ici

Bonjour

idem : La librairie de référence pour le format JSON ! (pour ne pas réinventer la roue !!)
ou, si la place disponible est très réduite : GitHub - squix78/json-streaming-parser: Arduino library for parsing potentially huge json streams on devices with scarce memory
le gestionaire de librairies propose ces librairies … et d’autres…pour parser le JSON

openweathermap comme les nombreux services concurrents envoie généralement des données formattées JSON par défaut

Bonsoir

Merci des réponses

j’ai avancer :

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
 
const char* ssid = "";
const char* password = "";
  
const char* servername = "api.openweathermap.org";
String api = "";
String ville = "";


String reponseOpenW;

void setup()
{
  
  Serial.begin(115200);
  Serial.println("Début Setup");
  connexionWifi();
    WiFiClient client;
  
  Serial.print("Connexion à openweathermap.org ");
  delay(100);
  if (client.connect(servername, 80))
  {
    Serial.println("Connecté!");
    delay(500);
 
    }

  
getWeatherData();

}

void loop()
{
}


void getWeatherData() 
{
  String result ="";
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(servername, httpPort)) {
        return;
    }
    String url = "/data/2.5/forecast?q="+ville+"&units=metric&cnt=1&APPID="+api;

    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + servername + "\r\n" +
                 "Connection: close\r\n\r\n");
    Serial.println(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + servername + "\r\n" +
                 "Connection: close\r\n\r\n");
    unsigned long timeout = millis();
    while (client.available() == 0) {
        if (millis() - timeout > 5000) {
            client.stop();
            return;
        }
    }
    while(client.available()) {
        result = client.readStringUntil('\r');
    }

result.replace('[', ' ');
result.replace(']', ' ');

char jsonArray [result.length()+1];
result.toCharArray(jsonArray,sizeof(jsonArray));
jsonArray[result.length() + 1] = '\0';

StaticJsonBuffer<1024> json_buf;

JsonObject &root = json_buf.parseObject(jsonArray);

if (!root.success())
{
  Serial.println("parseObject() failed");
}

String idString = root["list"]["weather"]["id"];

Serial.print("description :  ");
Serial.println(idString );
}

void connexionWifi(){
  Serial.printf("Connection à %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connecté");
}

dans le code avec le “String url = “/data/2.5/forecast?q=”+ville+”&units=metric&cnt=1&APPID="+api;" j’arrive à recupéré l’id de la météo.

mais c’est juste à l’instant T.

si je modifie la demande pour la journée :
“String url = “/data/2.5/forecast?q=”+ville+”&APPID="+api;"
l’ESP plante…

je viens de comprendre que le 1 :

String url = "/data/2.5/forecast?q="+ville+"&units=metric&cnt=1&APPID="+api;

demande la meteo dans les 3heures et elle me retorune bien la météo

si je demande 2 soit l'instant T et +3h l'esp plante:

String url = "/data/2.5/forecast?q="+ville+"&units=metric&cnt=2&APPID="+api;

ce qui donne :

{"cod":"200","message":0,"cnt":2,"list":[{"dt":1588982400,"main":{"temp":288.54,"feels_like":288.04,"temp_min":287.3,"temp_max":288.54,"pressure":1012,"sea_level":1012,"grnd_level":1009,"humidity":94,"temp_kf":1.24},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"clouds":{"all":60},"wind":{"speed":2.73,"deg":79},"sys":{"pod":"n"},"dt_txt":"2020-05-09 00:00:00"},{"dt":1588993200,"main":{"temp":287.04,"feels_like":286.17,"temp_min":286.3,"temp_max":287.04,"pressure":1011,"sea_level":1011,"grnd_level":1007,"humidity":97,"temp_kf":0.74},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"clouds":{"all":28},"wind":{"speed":2.77,"deg":49},"sys":{"pod":"n"},"dt_txt":"2020-05-09 03:00:00"}],"city":{"id":2990331,"name":"","coord":{"lat":**,"lon":***},"country":"FR","population":128,"timezone":7200,"sunrise":1588912324,"sunset":1588966110}}

Donne des détails sur la façon dont l'esp8266 plante. Quel est le message d'erreur ?

Oui biensur :

parseObject() failed
description :  

 ets Jan  8 2013,rst cause:4, boot mode:(3,7)

wdt reset
load 0x4010f000, len 1392, room 16 
tail 0
chksum 0xd0
csum 0xd0
v3d128e5c
~ld
Début Setup
Connection à ****** ..... connecté
Connexion à openweathermap.org Connecté!
GET /data/2.5/forecast?q=***&units=metric&cnt+1&APPID=****HTTP/1.1
Host: api.openweathermap.org
Connection: close

Merci

Bonjour

La librairie est elle bien ArduinoJson de Benoit Blachon ? (version 6.15 en ce moment)

(Doute car dans le code testé on ne voit pas l’allocation du buffer statique ou dynamique.)

Elle est documentée ici : https://arduinojson.org/

L’exemple JsonParserExemple est documenté ici

parseObject() failed
description :  

 ets Jan  8 2013,rst cause:4, boot mode:(3,7)

wdt reset

(le message d’erreur , reset par le chien de garde, laisse penser qu’une opération a monoplisé trop longtemps l’ESP8266 et que la fonctionnalité WiFi n’a pu être servie à temps)

si je demande 2 soit l’instant T et +3h l’esp plante:

String url = “/data/2.5/forecast?q=”+ville+"&units=metric&cnt=2&APPID="+api;

En procédant en deux temps est-ce que ça passe ?

al1fch: (le message d'erreur , reset par le chien de garde, laisse penser qu'une opération a monoplisé trop longtemps l'ESP8266 et que la fonctionnalité WiFi n'a pu être servie à temps)En procédant en deux temps est-ce que ça passe ?

si je demande 2 soit l'instant T et +3h l'esp plante:
String url = "/data/2.5/forecast?q="+ville+"&units=metric&cnt=2&APPID="+api;

En 2 temps ? par rapport au cnt=2 ?

si je met 1 j'ai la prevision à l'instant T si je met 2 j'ai la prevision à l'instant T, +celle de 3H si je met 3 j'ai la prevision à l'instant T, +celle de 3H, +celle de 6H etc..

On peut demander que celle dans 9H indépendamment des autres ?

al1fch: Bonjour

La librairie est elle bien ArduinoJson de Benoit Blachon ? |500x58 (Doute car dans le code testé on ne voit pas l'allocation du buffer statique ou dynamique.)

Elle est documentée ici : https://arduinojson.org/ L'exemple JsonParserExemple est documenté ici

Je vais vérifier

Merci

On peut demander que celle dans 9H indépendamment des autres ?

je ne connais pas en détail l’API d’OpenWeatherMap et ne sais quel niveau de detail peut être demandé
https://openweathermap.org/api

la suggestion de fractionnement de la demande vient juste du constat du reset, elle n’est peut être pas réalisable

Je vois

parseObject() failed
description :

avant le reboot de l’ESP32.

Voyant le code, il s’agit bien de cette bibliothèque. Les deux lignes importantes sont elles-ci:

StaticJsonBuffer<1024> json_buf;

JsonObject &root = json_buf.parseObject(jsonArray);

La première alloue la mémoire pour le stockage de la réponse du site, la seconde lance la parsing.

Il est possible que la première soit erronée. Ce qui est bien avec cette bibliothèque c’est qu’il existe un “wizard” qui va te proposer les deux meilleurs lignes pour parser ton texte. Il donne même un exemple pour openweathermap !

Pour l’utiliser, tu copies la réponse de ton site (que l’on peut en général obtenir en ligne) dans la fenêtre Input, et il te donne le code qui va bien dans l’autre fenêtre. Tu n’as plus qu’à l’utiliser tel quel, et prendre les lignes qui t’intéressent.

Remarque: il faut avoir installé la version 6.15.1.

je n’étais pas descendu suffisement dans le code pour voir a déclaration du buffer !!

Sa taille (1024) parait insuffisante vu le volume des données renvoyées par OpenWeatherMap pour un ensemble de prévisions météo.

L’assistant indiqué par lesept permet de calculer la taille du buffer pour un document JSON donné
et l’exemple (très court) pour OpenWeatherMap atteint déjà 1ko

Une requete plus riche (prévisions météo) demandera un buffer nettement plus grand
La requête de prévisions météo (forecast) , exemple du message #1, nécessite un buffer de plus de 25ko :
http://samples.openweathermap.org/data/2.5/forecast?zip=94040&appid=439d4b804bc8187953eb36d2a8c26a02

sachant que je fait une requête que pour la journée donc de cnt=8, ce qui donne :

{"cod":"200","message":0,"cnt":8,"list":[{"dt":1589025600,"main":{"temp":287.23,"feels_like":286.34,"temp_min":287.23,"temp_max":288.42,"pressure":1012,"sea_level":1011,"grnd_level":1008,"humidity":72,"temp_kf":-1.19},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"clouds":{"all":29},"wind":{"speed":1,"deg":258},"sys":{"pod":"n"},"dt_txt":"2020-05-09 12:00:00"},{"dt":1589036400,"main":{"temp":290.06,"feels_like":289.5,"temp_min":290.06,"temp_max":291.15,"pressure":1013,"sea_level":1013,"grnd_level":1009,"humidity":58,"temp_kf":-1.09},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"clouds":{"all":62},"wind":{"speed":0.34,"deg":262},"sys":{"pod":"d"},"dt_txt":"2020-05-09 15:00:00"},{"dt":1589047200,"main":{"temp":297.69,"feels_like":296.35,"temp_min":297.69,"temp_max":298.48,"pressure":1013,"sea_level":1013,"grnd_level":1010,"humidity":35,"temp_kf":-0.79},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"clouds":{"all":68},"wind":{"speed":1.27,"deg":297},"sys":{"pod":"d"},"dt_txt":"2020-05-09 18:00:00"},{"dt":1589058000,"main":{"temp":300.35,"feels_like":298.01,"temp_min":300.35,"temp_max":300.47,"pressure":1012,"sea_level":1012,"grnd_level":1009,"humidity":30,"temp_kf":-0.12},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"clouds":{"all":95},"wind":{"speed":2.71,"deg":304},"sys":{"pod":"d"},"dt_txt":"2020-05-09 21:00:00"},{"dt":1589068800,"main":{"temp":299.14,"feels_like":296.71,"temp_min":299.14,"temp_max":299.14,"pressure":1011,"sea_level":1011,"grnd_level":1008,"humidity":30,"temp_kf":0},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"clouds":{"all":83},"wind":{"speed":2.49,"deg":295},"sys":{"pod":"d"},"dt_txt":"2020-05-10 00:00:00"},{"dt":1589079600,"main":{"temp":291.15,"feels_like":289.5,"temp_min":291.15,"temp_max":291.15,"pressure":1012,"sea_level":1012,"grnd_level":1008,"humidity":54,"temp_kf":0},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"clouds":{"all":96},"wind":{"speed":1.89,"deg":290},"sys":{"pod":"d"},"dt_txt":"2020-05-10 03:00:00"},{"dt":1589090400,"main":{"temp":288.6,"feels_like":287.4,"temp_min":288.6,"temp_max":288.6,"pressure":1012,"sea_level":1012,"grnd_level":1009,"humidity":60,"temp_kf":0},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"clouds":{"all":98},"wind":{"speed":0.95,"deg":250},"sys":{"pod":"n"},"dt_txt":"2020-05-10 06:00:00"},{"dt":1589101200,"main":{"temp":287.44,"feels_like":286.17,"temp_min":287.44,"temp_max":287.44,"pressure":1011,"sea_level":1011,"grnd_level":1008,"humidity":64,"temp_kf":0},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"clouds":{"all":100},"wind":{"speed":1,"deg":260},"sys":{"pod":"n"},"dt_txt":"2020-05-10 09:00:00"}],"city":{"name":"Mountain View","coord":{"lat":37.3855,"lon":-122.088},"country":"US","timezone":-25200,"sunrise":1589029455,"sunset":1589079920}}

Cette page semble faire 2,99 Ko (3 059 octets) selon Mozilla

Peut modifier la taille du buffer de cette ligne :

StaticJsonBuffer<1024> json_buf;

Merci

le buffer doit être plus grand que la taille indiquée par Mozilla
l’assistant donne 5325 octets

Oui la taille du buffer est à mettre entre les < >

Quelle est la taille maximun que l'ont peut lui donner sur cette ESP ?

ESP

Ne cherche pas à lui donner la taille maximum, l'assistant te donne la bonne taille. Si tu as peur de dépasser, tu peux ajouter un peu, mais fais des essais d'abord avec ce que dit l'assistant.

Quelle est la taille maximum que l'ont peut lui donner sur cette ESP ?

Il faut que tu prennes en compte la mémoire libre après compilation :

Les variables globales utilisent XXXXX octets (XX%) de mémoire dynamique, ce qui laisse XXXXX octets pour les variables locales.

Le lien que tu donnes : http://samples.openweathermap.org/data/2.5/forecast?zip=94040&appid=439d4b804bc8187953eb36d2a8c26a02

L'assistant conseille 30871 bytes.

const size_t capacity = 26*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(26) + JSON_OBJECT_SIZE(7) + 26*JSON_OBJECT_SIZE(45) + 20600; DynamicJsonBuffer jsonBuffer(capacity);

Il faut essayer d'allouer le buffer comme conseillé.

Un exemple : avec le résultat d'une requête particulière JSON vers mon serveur DOMOTICZ, l'assistant donne 38421 bytes. Mon appli n'ayant que 38408 bytes libres, donc j'explose, forcément.

Qand la mémoire devient un problème il est possible de se rabattre sur une librairie moins 'pointue' mais qui gère le JSON 'au fil de l'eau' et n'a pas besoin d'avoir en mémoire tout le JSON : https://github.com/squix78/json-streaming-parser

alors il m’indique pour mon lien de 8 relevé :

Platform Size
AVR 1816+1801 = 3617

ESP32 }
ESP8266} 3632+1801 = 5433
SAMD 21}
STM32 }

J’ai donc mis le buffer avec un peu plus que 5433

StaticJsonBuffer<5600> json_buf;

et il plante pareil