[Aporte] Esp8266 y archivos Json con libreria ArduinoJson.

Buenas, espero q anden bien, les traigo aquí un ejercicio resuelto o casi resuelto, tiene algunas que otras cosas que pulir, pero en si el objetivo del codigo está más que logrado, porque les muestro este ejercicio? Por dos razones, una porque me parece un ejercicio con mucho potencial, el otro por que no encontré mucha información detallada al respecto (o yo no supe dar con los tags justos) y actualizada. El objetivos es leer datos de un JSON porporcionado por una API y hacer uso de ello, para eso necesitamos dos conceptos explicados a continuación, que es una API y q es JSON.

Una API es una interfaz de programación de aplicaciones (del inglés API: Application Programming Interface). Es un conjunto de rutinas que provee acceso a funciones de un determinado software.En la web, las API's son publicadas por sitios para brindar la posibilidad de realizar alguna acción o acceder a alguna característica o contenido que el sitio provee. En nuestro caso usaremos la API de www.openweathermap.org

JSON (acrónimo de JavaScript Object Notation, «notación de objeto de JavaScript») es un formato de texto sencillo para el intercambio de datos. Se trata de un subconjunto de la notación literal de objetos de JavaScript, aunque, debido a su amplia adopción como alternativa a XML, se considera (año 2019) un formato independiente del lenguaje.
Una de las supuestas ventajas de JSON sobre XML como formato de intercambio de datos es que resulta mucho más sencillo escribir un analizador sintáctico (parser) para él.

En la siguiente imagen podemos observar lo q es un archivo JSON que nos proporciona la API de openweathermap, en esta página se tienen q registrar y una vez hecho eso el sitio les proporcionara una api key que tendremos q usar, no voy a detenerme mucho en esto, como verán está perfectamente ordenada y prolija, pero la verdad es q así es como lo interpreta el navegador FireFox, realmente no es una información muy legible.

En esta imagen es como realmente se ve un archivo JSON y que es lo que vamos a recibir en nuestro código de C++ del IDE de Arduino, en mi caso me canse del IDE de Arduino y uso Platformio, una extensión de Arduino para Visual Studio Code. Perdon la calidad de la imagen, no se como hacer que se vea mas grande, igual si le dan click a la imagen los lleva al a web hosting para q puedan verla mejor.

Acá se puede ver el mismo archivo JSON pero ordenado para que se vea más legible.

Y la url de la API


Donde:
Buenos Aires, se refiere a la ciudad
AR, se refiere al pais
y lo tachado al final, se refiere a la API key que les va a generar el sitio una vez registrados.

Bien, ahora lo que sigue, el codigo, es bastante simple y está bastante comentado, cuenta con un portal AP donde se cargaran los datos por única vez de SSID y PASS conectándolo a un celular o a una pc, luego los datos quedan guardados en la EEPROM , luego el proceso de recepción del archivos JSON consta de 4 etapas:
• Conexión a la API.
• Recepción del archivo JSON.
• Deserializacion del String recibido.
• Almacenado de los datos con su correspondiente variable.
Y luego una pequeña tabla de valores que se mostrara por serial

/*--------------------------------------------------------------------------------------------------------------------------------------------------------
#Autor: Leandro Quinteros.           
#Año: Diciembre, 2019.        
#Lugar: Buenos Aires, Argentina.
#IDE: Platformio Ide.
#MCU: esp8266.
#Servidor de la API: www.openweathermap.org
 
#Descripcion:
El proposito de este ejemplo, es mostrar como obtener datos de un archivos JSON generado por la API de www.openweathermap.org, procesandolo y separandolo, 
haciendo uso de la libreria "ArduinoJson" para poder hacer luego, uso de estos, tambien tiene un prolijo portal AP donde ingresar el SSID y la PASS, que 
quedaran guardados en la EEPROM del ESP8266.
--------------------------------------------------------------------------------------------------------------------------------------------------------*/

//LIBRERIA DE ARDUINO.
#include <Arduino.h>

//LIBRERIA DE JSON.
#include <ArduinoJson.h>          //https://github.com/bblanchon/ArduinoJson (ver: 6.13)

//LIBRERIAD DEL WIFI.
#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <ESP8266HTTPClient.h>

WiFiClient client;


//OPENWEATHER_API.
const String host = "http://api.openweathermap.org/data/2.5/weather?q=Buenos%20Aires,AR&APPID="; //Url
const String key = "xxxxxxxxxxxxxx"; //API key.

//VARIABLES.
String clima;
int humedad;
int presion;
int temp;
int sensacion_termica;
int temp_Min;
int temp_Max;
int nubosidad;
int vel_viento;

//PROTOTIPOS DE FUNCIONES.
void getWeatherData();
void imprimirTabla(int *temp, int *sensacion_termica, int *temp_Min, int *temp_Max, int *humedad, int *presion, int *vel_viento, int *nubosidad, String *clima);

void setup()
{
   //CONFIGURACION DEL SERIAL.
   Serial.begin(115200);

   //CONFIGURACION DEL ADMINISTRADOR DE REDES.
   WiFiManager wifiManager;  //Class WiFiManager lo guardo en "wifiManager".
   delay(10);
   //wifiManager.resetSettings(); //.:::::DESCOMENTAR PARA QUE SE BORRE LA CONTRASEÑA E SSID DE LA EEPROM CADA VEZ QUE SE REINICIE:::::. 
   wifiManager.autoConnect(".::Dispositivo IOT::."); //Nombre del portal.
   Serial.println("Dispotivo conectado a Internet");
   
}

void loop()
{
  getWeatherData(); //Llamo a la funcion para obtener los datos del clima.
  delay(60000);
}

//FUNCION PARA OBTENER DATOS DEL JSON PROPORCIONADO POR LA API.
void getWeatherData()
{
  String dataJson;

  if ((WiFi.status() == WL_CONNECTED))
  {
    HTTPClient http; //Class HTTPClient la guardo en "http".
    http.begin(host + key);    //Aca unimos la url de la API con la API key, NO SE POR QUE APARECE UNA ADVERTENCIA AQUI EN EL COMPILADOR.
    int httpCode = http.GET(); //Guardo en httpcode el codigo(200) obtenido de http.GET()
    if (httpCode > 0)
    {
      String data = http.getString(); //Guardo en data el contenido del archivo json.
      dataJson = data;
      /*Serial.println("Codigo y archivo JSON:");
      Serial.println(httpCode); //Muestro el codigo http obtenido (200).
      Serial.println(data);     //Muestro el contenido obtenido del archivo json.
      */
    }
    else
    {
      Serial.println("Error en la peticion HTTP");
    }
    http.end();
  }

  DynamicJsonDocument dataJsonDes(1024);  //Reservo una variable dinamica de 1024bytes para guardar el archivo JSON deserializado.
  deserializeJson(dataJsonDes, dataJson); //Deserializo el contenido de dataJson y lo guardo en dataJsonDes.

  //DATOS OBTENIDOS.
  
  temp = dataJsonDes["main"]["temp"]; //En "temp", voy a guardar el contenido de "main" > "temp".
  temp = temp - 273; //El archivo JSON me devuelve los grados en Kelvin, entonces lo paso a Celsius.
  sensacion_termica = dataJsonDes["main"]["feels_like"];
  sensacion_termica = sensacion_termica - 273;
  temp_Min = dataJsonDes["main"]["temp_min"];
  temp_Min = temp_Min - 273;
  temp_Max = dataJsonDes["main"]["temp_max"];
  temp_Max = temp_Max - 273;
  humedad = dataJsonDes["main"]["humidity"];
  presion = dataJsonDes["main"]["pressure"];
  vel_viento = dataJsonDes["wind"]["speed"];
  nubosidad = dataJsonDes["clouds"]["all"];
  clima = dataJsonDes["weather"]["main"].as<String>();

  imprimirTabla(&temp, &sensacion_termica, &temp_Min, &temp_Max, &humedad, &presion, &vel_viento, &nubosidad, &clima); //llamo a la funcion imprimirTabla.

}

//FUNCION PARA MOSTRAR LOS VALORES POR SERIAL.
void imprimirTabla(int *temp, int *sensacion_termica, int *temp_Min, int *temp_Max, int *humedad, int *presion, int *vel_viento, int *nubosidad, String *clima)
{
  Serial.print("");
  Serial.println("==================================================.::TABLA DE VALORES::.=====================================================");
  Serial.println(String(" TEMP \t") + String("SENS_TERMICA \t") + String("TEMP_MIN \t") + String("TEMP_MAX \t") + String("HUMEDAD \t") + String("PRESION \t") + String("VEL_VIENTO \t") + String("NUBOSIDAD \t") + String("CLIMA"));
  Serial.println(String(" ") + *temp + String("C \t    ") + *sensacion_termica + String("C \t   ") + *temp_Min + String("C\t\t   ") + *temp_Max + String("C\t\t   ") + *humedad + String("%\t\t") + *presion + String("hPc\t\t    ") + *vel_viento + String("M/s\t    ") + *nubosidad + String("%\t\t ") + *clima);
  Serial.println("");
}

No voy a detenerme en explicar la aplicacion de la libreria del wifi manager, ya esta altura muchos la conocen y quien que no, youtube tiene centenares de videos al respecto, asi q vamos al grano q es la implementacion de la API y el archivos JSON.
Primero, la url y la api key, por obvias razones mi api key no la iba a poner.

//OPENWEATHER_API.
const String host = "http://api.openweathermap.org/data/2.5/weather?q=Buenos%20Aires,AR&APPID="; //Url
const String key = "xxxxxxxxxxxxxx"; //API key.

Segundo, en este bloque lo que hacemos, es realizar la coneccion al servidor q nos brindara del contenido del archivos JSON. Que lo guardaremos en un String en la variable "data"

HTTPClient http; //Class HTTPClient la guardo en "http".
    http.begin(host + key);    //Aca unimos la url de la API con la API key, NO SE POR QUE APARECE UNA ADVERTENCIA AQUI EN EL COMPILADOR.
    int httpCode = http.GET(); //Guardo en httpcode el codigo(200) obtenido de http.GET()
    if (httpCode > 0)
    {
      String data = http.getString(); //Guardo en data el contenido del archivo json.
      dataJson = data;
     }

Tercero y ultimo tenemos la aplicacion de la libreria ArduinoJson en su version 6.13, esta es la parte mas importante, aqui creamos una "variable dinamica" donde le asignamos el tamaño en bytes, en esta variale lo que vamos a hacer es guardar el contenido del JSON de manera deserializada. En el codigo completo deje los links de github de las librerias, recomiendo leer la documentacion de la libreria de AruinoJson, ya es muy completa y brinda de diversos ejemplos, para aquellos que tienen buen dominio de C++ pueden encontrar ejemplos muy divertidos y utiles para emplear.

DynamicJsonDocument dataJsonDes(1024);  //Reservo una variable dinamica de 1024bytes para guardar el archivo JSON deserializado.
  deserializeJson(dataJsonDes, dataJson); //Deserializo el contenido de dataJson y lo guardo en dataJsonDes.

Y esta es una parte del codigo que no pude resolver, en teoria deberia mostrar la leyenda de "nublado" o "soleado" o "lluvioso" dependiendo del estado del clima claramente, pero lo unico q consigo es q diga "null" o directamente no aparezca nada.

clima = dataJsonDes["weather"]["main"].as<String>();

bueno y aca unas imagenes de comparacion entre la terminal serial y el Json en el mismo minuto, como veran clima deberia decir "clear" pero me aparece un null, lo q me da a pensar que estaria entrando a "weather" pero luego no puede proceder hacia "main" que tiene proximo, le habia corregido agregandole

"clima = dataJsonDes["weather"]["0"]["main"].as();"
pero no tuve exito.

Bueno no se si me super hacer entender, si entendieron buenisimo, sino, me preguntan por aca, y si hay algo que corregir que no me haya dado cuenta, que algun moderador me lo haga saber, saludos. Perdon que me salio en 3 post, pero el editor del foro me reestringia los caracteres.

Hola Karma, no se usar el foro este, se que son re ortivas los moderadores, tienen como un ritual de iniciacion al que no me pienso someter asi que si me echan ya se porque.

Solamente queria comentar que encontre tu laburo, lo segui al pie de la letra y anda de 10!!.

Con respecto a ese error que tenias y que no pidas ver la nubosidad queria decirte que a mi si me aparece pero en porcentaje.

TEMP-SENS_TERMICA-TEMP_MIN-TEMP_MAX-HUMEDAD-PRESION-VEL_VIENTO-NUBOSIDAD-CLIMA
21C 19C 20C 22C 73% 1015hPc 5M/s 72% null

Muchas Gracias