¿Quieres aprender a decodificar y codificar datos en formato JSON utilizando Arduino o ESP8266? ¡Has llegado al lugar correcto! En este artículo, te explicaremos paso a paso cómo llevar a cabo este proceso de forma sencilla y efectiva. ¡No te lo pierdas!
En esta publicación de blog, aprenderá cómo decodificar (analizar una cadena JSON) y codificar (generar una cadena JSON) usando Arduino con Ethernet Shield usando la biblioteca ArduinoJson. Esta guía también funciona con los módulos Wi-Fi ESP8266 y ESP32 con pequeños cambios.
Importante: Este tutorial sólo es compatible con la biblioteca ArduinoJSON 5.13.5.
¿Qué es JSON?
JSON significa javaSguion ohobjeto norteRotación. JSON es un estándar abierto ligero basado en texto para el intercambio de datos.
JSON se utiliza principalmente para serializar y transmitir datos estructurados a través de conexiones de red, es decir, para transferir datos entre un servidor y un cliente. Se utiliza comúnmente en servicios como API (interfaces de programación de aplicaciones) y servicios web que exponen datos públicos.
Conceptos básicos de la sintaxis JSON
En JSON, los datos están estructurados de cierta manera. JSON usa símbolos como { } , : ” ” [ ] y tiene la siguiente sintaxis:
- Los datos se representan en pares clave/valor.
- Los dos puntos (:) asignan un valor a la clave
- Los pares clave/valor están separados por comas (,).
- Las llaves contienen objetos ({ })
- Los corchetes contienen matrices ([ ])
Por ejemplo, para representar datos en JSON, los pares clave-valor son los siguientes:
{"key1":"value1", "key2":"value2", "key3":"value3"}
Ejemplos JSON
En un ejemplo del mundo real, es posible que desees estructurar datos sobre un usuario:
{"name":"Rui", "country": "Portugal", "age":24}
O en un proyecto de IoT es posible que desees estructurar los datos de tus sensores:
{"temperature":27.23, "humidity":62.05, "pressure":1013.25}
En JSON, los valores pueden ser otro objeto JSON (deportes) o una matriz (mascotas). Ejemplo:
{ "name": "Rui", "sports": { "outdoor": "hiking", "indoor": "swimming" }, "pets": [ "Max", "Dique" ] }
Aquí estructuramos datos sobre un usuario y tenemos varias claves: “Apellido»“Deportes» Y «Mascotas».
Al nombre se le asigna el valor Rui. Rui puede practicar diferentes deportes dependiendo del lugar donde se practique. Por lo tanto, creamos otro objeto JSON para almacenar los deportes favoritos de Rui. Este objeto JSON es el valor de «Deportes» Llave.
El «mascotas» La clave tiene una matriz que contiene los nombres de las mascotas de Rui y los valores «máx.» Y «Diqué» Adentro.
La mayoría de las API devuelven datos en formato JSON y la mayoría de los valores son en sí mismos objetos JSON. El siguiente ejemplo muestra los datos proporcionados por una API meteorológica.
{ "coord":{ "lon":-8.61, "lat":41.15 }, "weather":[ { "id":803, "main":"Clouds", "description":"broken clouds", "icon":"04d" } ], "base":"stations", "main":{ "temp":288.15, "pressure":1020, "humidity":93, "temp_min":288.15, "temp_max":288.15 }, (...) }
Esta API proporciona mucha información. Por ejemplo, las coordenadas de longitud y latitud se almacenan en las primeras líneas.
Arduino con escudo Ethernet
Los ejemplos de esta publicación utilizan un Arduino con un escudo Ethernet. Simplemente monte el escudo en su placa Arduino y conéctelo a su red con un cable RJ45 para establecer una conexión a Internet (como se muestra en la imagen a continuación).
Nota: Los ejemplos proporcionados en este tutorial también funcionan con ESP8266 y ESP32 con pequeños cambios.
Preparando el IDE de Arduino
La forma más sencilla de decodificar y codificar cadenas JSON con Arduino IDE es utilizar la biblioteca ArduinoJson 5.13.5, diseñada para ser la biblioteca JSON de administración de memoria más intuitiva, más pequeña y más eficiente para Arduino.
Está escrito pensando en Arduino, pero no está vinculado a las bibliotecas de Arduino, por lo que puede usar esta biblioteca en cualquier otro proyecto de C++. También hay una documentación Sitio web de la biblioteca con ejemplos y referencia de API.
características
- Decodificación JSON (se admiten comentarios)
- Codificación JSON (con sangría opcional)
- API elegante, muy fácil de usar.
- Asignación de memoria fija (malloc nulo)
- Sin duplicación de datos (copia cero)
- Portátil (escrito en C++98)
- Independiente (sin dependencia externa)
- Pequeña huella de pie
- Biblioteca de solo encabezado
- licencia MIT
Compatible con
- Placas Arduino: Uno, Due, Mini, Micro, Yun…
- Placas ESP8266, ESP32 y WeMos
- Teensy, placas RedBearLab, Intel Edison y Galileo
- PlataformaIO, Partículas y Energia
Instalación de la biblioteca ArduinoJson
Para este proyecto necesitas instalar la biblioteca ArduinoJson en tu IDE de Arduino:
- Haga clic aquí para descargar ArduinoJson versión 5.13.5. Deberías tener una carpeta .zip en tu carpeta de Descargas.
- Extraiga la carpeta .zip y debería obtener la carpeta maestra ArduinoJson.
- Cambie el nombre de su carpeta de
Maestro ArduinoJsonA ArduinoJson - Mueva la carpeta ArduinoJson a la carpeta de bibliotecas de instalación de su IDE de Arduino.
- Finalmente, vuelva a abrir su IDE de Arduino
Decodificar JSON – Analizar cadena JSON
Comencemos decodificando/analizando la siguiente cadena JSON:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
Importe la biblioteca ArduinoJson:
#include <ArduinoJson.h>
Arduino JSON utiliza un grupo de memoria preasignado para almacenar el árbol JsonObject. Esto lo hace StaticJsonBuffer. Puedes usar Asistente ArduinoJson para calcular el tamaño exacto del buffer, pero para este ejemplo 200 es suficiente.
StaticJsonBuffer<200> jsonBuffer;
Crea una matriz de caracteres llamada json[] Para guardar una cadena JSON de muestra:
char json[] = "{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}";
Usa la función analizarObjeto() para convertir la cadena JSON en un JsonObject llamado raíz.
JsonObject& root = jsonBuffer.parseObject(json);
Para verificar si la decodificación/análisis fue exitosa, puede raíz.éxito():
if(!root.success()) { Serial.println("parseObject() failed"); return false; }
El resultado puede ser erróneo por tres motivos:
- la cadena JSON tiene una sintaxis no válida;
- la cadena JSON no representa un objeto;
- StaticJsonBuffer es demasiado pequeño: utilícelo Asistente ArduinoJson para calcular el tamaño del buffer.
Ahora que el objeto o matriz está en la memoria, puede extraer los datos fácilmente. La forma más sencilla de hacerlo es con JsonObject. raíz:
const char* sensor = root["sensor"]; long time = root["time"]; double latitude = root["data"][0]; double longitude = root["data"][1];
Puede utilizar las variables decodificadas sensor, tiempo, latitud o longitud en la lógica de su código.
API OpenWeatherMap
Para un ejemplo del mundo real usando un Arduino y un escudo Ethernet, usaremos una API gratuita de OpenWeatherMap para solicitar el pronóstico del tiempo para el día de su ubicación seleccionada.
Aprender a utilizar las API es una gran habilidad porque le permite acceder a una amplia variedad de información en constante cambio, como el último precio de las acciones, el tipo de cambio, las últimas noticias, actualizaciones de tráfico y mucho más.
Usando la API
El plan gratuito de OpenWeatherMap tiene todo lo que necesitas para este ejemplo. Para utilizar la API, necesita una clave API, llamada APIID. Cómo obtener un APIID:
- Abra un navegador y vaya a OpenWeatherMap
- presione el Acceso Haga clic y cree una cuenta gratuita
- Una vez creada su cuenta, se le presentará un panel de múltiples pestañas (vea la imagen a continuación).
- Elegir Clave API y copia tu único Llave
Esta es una clave única que necesita para recuperar información del sitio. Copie y pegue esta clave en algún lugar; la necesitará pronto.
Para obtener información sobre el clima en la ubicación seleccionada, ingrese la siguiente URL, reemplazando las secciones entre llaves con la información de la ubicación seleccionada y su clave API única:
http://api.openweathermap.org/data/2.5/weather?q={your city},{your country code}&APPID={your API Key}
Sustituto {tu ciudad} con la ciudad de la que quieres datos, {su código de país} con el código de país de esta ciudad y {Su clave API} con su clave API única que encontramos anteriormente. Por ejemplo, nuestra URL API para la ciudad de Oporto en Portugal después de reemplazarla con los detalles sería:
http://api.openweathermap.org/data/2.5/weather?q=Porto,PT&APPID=801d2603e9f2e1c70e042e4------
nota: Hay más información disponible sobre el uso de la API para recuperar información meteorológica. Aquí.
Copie su URL en su navegador y debería obtener un conjunto de información correspondiente a sus datos meteorológicos locales.
En nuestro caso, el tiempo en Oporto, Portugal, el día de escribir este artículo es:
{ "coord": { "lon": -8.61, "lat": 41.15 }, "weather": [ { "id": 701, "main": "Mist", "description": "mist", "icon": "50d" } ], "base": "stations", "main": { "temp": 290.86, "pressure": 1014, "humidity": 88, "temp_min": 290.15, "temp_max": 292.15 }, (...) }
Realizar una solicitud de API con Arduino
Ahora tiene una URL que devuelve sus datos meteorológicos locales. Puede automatizar esta tarea y acceder a estos datos en sus proyectos Arduino o ESP8266. Aquí está el script completo que necesitas cargar en tu Arduino usando Ethernet-Shield para devolver la temperatura en Kelvin y la humedad:
/*
* Rui Santos
* Complete Project Details https://randomnerdtutorials.com
* Based on the Arduino Ethernet Web Client Example
* and on the sketch "Sample Arduino Json Web Client" of the Arduino JSON library by Benoit Blanchon (bblanchon.github.io/ArduinoJson)
*/
#include <ArduinoJson.h>
#include <Ethernet.h>
#include <SPI.h>
EthernetClient client;
// Name address for Open Weather Map API
const char* server = "api.openweathermap.org";
// Replace with your unique URL resource
const char* resource = "REPLACE_WITH_YOUR_URL_RESOURCE";
// How your resource variable should look like, but with your own COUNTRY CODE, CITY and API KEY (that API KEY below is just an example):
//const char* resource = "/data/2.5/weather?q=Porto,pt&appid=bd939aa3d23ff33d3c8f5dd1";
const unsigned long HTTP_TIMEOUT = 10000; // max respone time from server
const size_t MAX_CONTENT_SIZE = 512; // max size of the HTTP response
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// The type of data that we want to extract from the page
struct clientData {
char temp[8];
char humidity[8];
};
// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to initialize
}
Serial.println("Serial ready");
if(!Ethernet.begin(mac)) {
Serial.println("Failed to configure Ethernet");
return;
}
Serial.println("Ethernet ready");
delay(1000);
}
// ARDUINO entry point #2: runs over and over again forever
void loop() {
if(connect(server)) {
if(sendRequest(server, resource) && skipResponseHeaders()) {
clientData clientData;
if(readReponseContent(&clientData)) {
printclientData(&clientData);
}
}
}
disconnect();
wait();
}
// Open connection to the HTTP server
bool connect(const char* hostName) {
Serial.print("Connect to ");
Serial.println(hostName);
bool ok = client.connect(hostName, 80);
Serial.println(ok ? "Connected" : "Connection Failed!");
return ok;
}
// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
Serial.print("GET ");
Serial.println(resource);
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("Connection: close");
client.println();
return true;
}
// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
// HTTP headers end with an empty line
char endOfHeaders[] = "rnrn";
client.setTimeout(HTTP_TIMEOUT);
bool ok = client.find(endOfHeaders);
if (!ok) {
Serial.println("No response or invalid response!");
}
return ok;
}
// Parse the JSON from the input string and extract the interesting values
// Here is the JSON we need to parse
/*{
"coord": {
"lon": -8.61,
"lat": 41.15
},
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
"base": "stations",
"main": {
"temp": 296.15,
"pressure": 1020,
"humidity": 69,
"temp_min": 296.15,
"temp_max": 296.15
},
"visibility": 10000,
"wind": {
"speed": 4.6,
"deg": 320
},
"clouds": {
"all": 0
},
"dt": 1499869800,
"sys": {
"type": 1,
"id": 5959,
"message": 0.0022,
"country": "PT",
"sunrise": 1499836380,
"sunset": 1499890019
},
"id": 2735943,
"name": "Porto",
"cod": 200
}*/
bool readReponseContent(struct clientData* clientData) {
// Compute optimal size of the JSON buffer according to what we need to parse.
// See https://bblanchon.github.io/ArduinoJson/assistant/
const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) +
2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) +
JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 390;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& root = jsonBuffer.parseObject(client);
if (!root.success()) {
Serial.println("JSON parsing failed!");
return false;
}
// Here were copy the strings we're interested in using to your struct data
strcpy(clientData->temp, root["main"]["temp"]);
strcpy(clientData->humidity, root["main"]["humidity"]);
// It's not mandatory to make a copy, you could just use the pointers
// Since, they are pointing inside the "content" buffer, so you need to make
// sure it's still in memory when you read the string
return true;
}
// Print the data extracted from the JSON
void printclientData(const struct clientData* clientData) {
Serial.print("Temp = ");
Serial.println(clientData->temp);
Serial.print("Humidity = ");
Serial.println(clientData->humidity);
}
// Close the connection with the HTTP server
void disconnect() {
Serial.println("Disconnect");
client.stop();
}
// Pause for a 1 minute
void wait() {
Serial.println("Wait 60 seconds");
delay(60000);
}
Nota: Asegúrese de reemplazar la variable de recurso con su recurso URL único de OpenWeatherMap:
const char* resource = "REPLACE_WITH_YOUR_URL_RESOURCE";
Modifica el código de tu proyecto.
En este ejemplo, Arduino realiza una solicitud HTTP GET a un servicio deseado (en este caso, la API OpenWeatherMap), pero puede cambiar esto para solicitar cualquier otro servicio web. No explicaremos el código Arduino línea por línea.
Para este proyecto, es importante que comprenda lo que necesita cambiar en el código Arduino para decodificar/analizar una respuesta JSON. Siga estos siguientes tres pasos.
PASO #1 – Estructura
Cree una estructura de datos que pueda almacenar la información que desea extraer de la API. En este caso queremos almacenar la temperatura y la humedad en matrices de caracteres:
struct clientData { char temp[8]; char humidity[8]; };
PASO #2 – Tamaño de JsonBuffer
Ir a Asistente ArduinoJson y copie la respuesta completa de la API OpenWeatherMap en el campo de entrada.
Entendido Expresión generado (ver figura anterior), en mi caso:
JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12)
Tienes que Leer el contenido de la respuesta() Funciona con tu generado JsonBuffer Tamaño del Asistente ArduinoJson para asignar la memoria adecuada para decodificar la respuesta JSON de una API:
bool readReponseContent(struct clientData* clientData) {
const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) +
2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) +
JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 390;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& root = jsonBuffer.parseObject(client);
Todavía en Leer el contenido de la respuesta() función, necesita copiar las variables que necesita para su proyecto en los datos de su estructura:
strcpy(clientData->temp, root["main"]["temp"]); strcpy(clientData->humidity, root["main"]["humidity"]);
PASO 3: acceda a los datos decodificados
Luego podrá acceder fácilmente y hacer algo con los datos JSON decodificados en su código Arduino. En este ejemplo, simplemente imprimimos la temperatura en Kelvin y la humedad en el monitor serie del IDE de Arduino:
void printclientData(const struct clientData* clientData) { Serial.print("Temp = "); Serial.println(clientData->temp); Serial.print("Humidity = "); Serial.println(clientData->humidity); }
demostración
Abra el monitor serial del Arduino IDE con una velocidad de 9600 baudios y verá la temperatura en Kelvin y la humedad en porcentaje impresa en el monitor serial cada 60 segundos.
Se puede acceder al resto de la información en la respuesta de la API de OpenWeatherMap, pero para fines de demostración solo hemos decodificado la temperatura y la humedad.
Codificar JSON: generar una cadena JSON
Aprendamos a codificar/generar la siguiente cadena JSON:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
Puedes leer la documentación sobre cifrado. Aquí.
Importe la biblioteca ArduinoJson:
#include <ArduinoJson.h>
Arduino JSON utiliza un grupo de memoria preasignado para almacenar el árbol de objetos. Esto lo hace StaticJsonBuffer. Puedes usar Asistente ArduinoJson para calcular el tamaño exacto del buffer, pero para este ejemplo 200 es suficiente.
StaticJsonBuffer<200> jsonBuffer;
Cree un JsonObject llamado root que contenga sus datos. Luego asigna los valores gps y 1351824120 a eso sensor Y Tiempo botones o
JsonObject& root = jsonBuffer.createObject(); root["sensor"] = "gps"; root["time"] = 1351824120;
Para luego crear una matriz en un Datos botón, haga lo siguiente:
JsonArray& data = root.createNestedArray("data"); data.add(48.756080); data.add(2.302038);
Es muy probable que necesite imprimir el JSON generado en su monitor serie para fines de depuración. Para ello proceda de la siguiente manera:
root.printTo(Serial);
Después de codificar su información en una cadena JSON, puede publicarla en otro dispositivo o servicio web, como se muestra en el siguiente ejemplo.
Ejemplo de codificación con Arduino y Node-RED
Para este ejemplo, necesitará Node-RED o un software similar que pueda recibir solicitudes HTTP POST. Puedes instalar Node-RED en tu computadora, pero recomiendo ejecutar Node-RED en una Raspberry Pi.
Creando el flujo
En este flujo, recibe una solicitud HTTP POST e imprime los datos recibidos en el Depurar Ventana. Siga estos siguientes 6 pasos para crear su flujo:
1) Abra el software Node-RED en su navegador
2) tira uno entrada HTTP nodo y un depurar nodo
3) Editar eso entrada HTTP añadiendo el CORREO método y el /json-post-ejemplo URL
4) Puede cambiar la configuración predeterminada para el depurar nodo
5) Conecta tus nodos
6) Para guardar su aplicación, debe hacer clic en el botón «Implementar» en la esquina superior derecha.
Su solicitud está guardada y lista.
Enviar datos JSON con Arduino
Después de preparar Node-RED para recibir solicitudes POST en la URL /json-post-example, puede usar el siguiente ejemplo de código en un Arduino con un escudo Ethernet para enviarle datos.
/*
* Rui Santos
* Complete Project Details https://randomnerdtutorials.com
* Based on the Arduino Ethernet Web Client Example
* and on the sketch "Sample Arduino Json Web Client" of the Arduino JSON library by Benoit Blanchon (bblanchon.github.io/ArduinoJson)
*/
#include <ArduinoJson.h>
#include <Ethernet.h>
#include <SPI.h>
EthernetClient client;
// Replace with your Raspberry Pi IP address
const char* server = "REPLACE_WITH_YOUR_RASPBERRY_PI_IP_ADDRESS";
// Replace with your server port number frequently port 80 - with Node-RED you need to use port 1880
int portNumber = 1880;
// Replace with your unique URL resource
const char* resource = "/json-post-example";
const unsigned long HTTP_TIMEOUT = 10000; // max respone time from server
const size_t MAX_CONTENT_SIZE = 512; // max size of the HTTP response
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
Serial.begin(9600);
while(!Serial) {
; // wait for serial port to initialize
}
Serial.println("Serial ready");
if(!Ethernet.begin(mac)) {
Serial.println("Failed to configure Ethernet");
return;
}
Serial.println("Ethernet ready");
delay(1000);
}
// ARDUINO entry point #2: runs over and over again forever
void loop() {
if(connect(server, portNumber)) {
if(sendRequest(server, resource) && skipResponseHeaders()) {
Serial.print("HTTP POST request finished.");
}
}
disconnect();
wait();
}
// Open connection to the HTTP server (Node-RED running on Raspberry Pi)
bool connect(const char* hostName, int portNumber) {
Serial.print("Connect to ");
Serial.println(hostName);
bool ok = client.connect(hostName, portNumber);
Serial.println(ok ? "Connected" : "Connection Failed!");
return ok;
}
// Send the HTTP POST request to the server
bool sendRequest(const char* host, const char* resource) {
// Reserve memory space for your JSON data
StaticJsonBuffer<200> jsonBuffer;
// Build your own object tree in memory to store the data you want to send in the request
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "dht11";
JsonObject& data = root.createNestedObject("data");
data.set("temperature", "30.1");
data.set("humidity", "70.1");
// Generate the JSON string
root.printTo(Serial);
Serial.print("POST ");
Serial.println(resource);
client.print("POST ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("Connection: closernContent-Type: application/json");
client.print("Content-Length: ");
client.print(root.measureLength());
client.print("rn");
client.println();
root.printTo(client);
return true;
}
// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
// HTTP headers end with an empty line
char endOfHeaders[] = "rnrn";
client.setTimeout(HTTP_TIMEOUT);
bool ok = client.find(endOfHeaders);
if(!ok) {
Serial.println("No response or invalid response!");
}
return ok;
}
// Close the connection with the HTTP server
void disconnect() {
Serial.println("Disconnect");
client.stop();
}
// Pause for a 1 minute
void wait() {
Serial.println("Wait 60 seconds");
delay(60000);
}
Nota: Asegúrate de reemplazar la variable del servidor con la dirección IP de tu Raspberry Pi:
const char* server = "REPLACE_WITH_YOUR_RASPBERRY_PI_IP_ADDRESS";
Modifica el código de tu proyecto.
En este ejemplo, Arduino realiza una solicitud HTTP POST a Node-RED, pero puede modificarla para enviar una solicitud a otro servicio web o servidor. No explicaremos el código Arduino línea por línea. Para este proyecto, es importante que comprenda lo que necesita cambiar en el código Arduino para codificar/generar una solicitud JSON.
función enviarSolicitud()
Para este proyecto puedes utilizar el Enviar petición() Funciona con tu propia estructura de datos JSON:
bool sendRequest(const char* host, const char* resource) {
Primero, reserve espacio de almacenamiento para sus datos JSON. Puede Asistente ArduinoJson para calcular el tamaño exacto del buffer, pero para este ejemplo 200 es suficiente.
StaticJsonBuffer<200> jsonBuffer;
Crea un JsonObject llamado root que contenga tus datos y asigne los valores a tus claves (en este ejemplo tenemos esto sensor Llave):
JsonObject& root = jsonBuffer.createObject(); root["sensor"] = "dht11";
Para almacenar datos en una matriz, haga lo siguiente:
JsonObject& data = root.createNestedObject("data"); data.set("temperature", "30.1"); data.set("humidity", "70.1");
Imprima la cadena JSON generada en el monitor serie Arduino IDE para fines de depuración:
root.printTo(Serial);
El resto de la función sendRequest() es la solicitud POST.
client.print("POST "); client.print(resource); client.println(" HTTP/1.1"); client.print("Host: "); client.println(host); client.println("Connection: closernContent-Type: application/json"); client.print("Content-Length: "); client.print(root.measureLength()); client.print("rn"); client.println(); root.printTo(client);
Tenga en cuenta que con el raíz.medidaLongitud() para determinar la longitud de su JSON generado. root.printTo(client) envía los datos JSON al cliente Ethernet.
demostración
Abra el monitor serie Arduino IDE con una velocidad de baudios de 9600 y verá el objeto JSON impreso en el monitor serie cada 60 segundos.
En el nodo ROJO depurar Puedes ver que se recibe el mismo objeto JSON cada 60 segundos:
Finalmente, creará funciones en Node-RED que harán algo útil con los datos recibidos, pero para fines de demostración simplemente imprimiremos los datos de muestra.
Envolver
En este tutorial, le hemos mostrado varios ejemplos sobre cómo decodificar y codificar datos JSON. Puede seguir estos pasos básicos para crear proyectos más avanzados que requieran compartir datos entre dispositivos.
Esperamos que este tutorial te haya resultado útil.
Si disfrutó de este proyecto y de la automatización del hogar, asegúrese de consultar nuestro curso: Construya un sistema de automatización del hogar por 0.
Decodificación y codificación JSON con Arduino o ESP8266
En esta publicación del blog aprenderás cómo decodificar (analizar una cadena JSON) y codificar (generar una cadena JSON) con la biblioteca ArduinoJson utilizando Arduino con el shield Ethernet. Esta guía también funciona con los módulos Wi-Fi ESP8266 y ESP32 con pequeños cambios.
¿Qué es JSON?
JSON significa JavaScript Object Notation. JSON es un estándar abierto basado en texto y ligero diseñado para intercambiar datos.
JSON se utiliza principalmente para serializar y transmitir datos estructurados a través de una conexión de red: transmitir datos entre un servidor y un cliente. A menudo se usa en servicios como APIs (Interfaces de Programación de Aplicaciones) y servicios web que proporcionan datos públicos.
Sintaxis básica de JSON
En JSON, los datos están estructurados de una manera específica. JSON utiliza símbolos como { }, : » «, [ ] y tiene la siguiente sintaxis:
- Los datos se representan en pares clave/valor
- Los dos puntos (:) asignan un valor a una clave
- Los pares clave/valor están separados por comas (,)
- Las llaves rizadas contienen objetos ({ })
- Los corchetes cuadrados contienen arreglos ([ ])
Por ejemplo, para representar datos en JSON, los pares clave/valor son los siguientes:
{«clave1″:»valor1», «clave2″:»valor2», «clave3″:»valor3»}
Ejemplos de JSON
En un ejemplo del mundo real, es posible que desees estructurar datos sobre un usuario:
{«nombre»:»Rui», «país»: «Portugal», «edad»:24}
En un proyecto de IoT, es posible que desees estructurar datos de tus sensores:
{«temperatura»:27.23, «humedad»:62.05, «presión»:1013.25}
En JSON, los valores pueden ser otro objeto JSON (deportes) o un arreglo (mascotas). Por ejemplo:
{
«nombre»: «Rui»,
«deportes»: {
«al aire libre»: «senderismo»,
«interior»: «natación»
},
«mascotas»: [
«Max»,
«Dique»
]
}
Aquí estamos estructurando datos sobre un usuario y tenemos varias claves: «nombre», «deportes» y «mascotas».
El nombre tiene el valor de Rui asignado. Rui puede practicar diferentes deportes relacionados con donde se practican. Por lo tanto, creamos otro objeto JSON para guardar los deportes favoritos de Rui. Este objeto JSON es el valor de la clave «deportes».
La clave de «mascotas» tiene un arreglo que contiene los nombres de las mascotas de Rui y tiene los valores «Max» y «Dique» dentro.
La mayoría de las APIs devuelven datos en JSON y la mayoría de los valores son objetos JSON mismos. El siguiente ejemplo muestra los datos proporcionados por una API meteorológica.
{
«coord»: {
«lon»: -8.61,
«lat»: 41.15
},
«weather»: [
{
«id»: 803,
«main»: «Clouds»,
«description»: «broken clouds»,
«icon»: «04d»
}
],
«base»: «stations»,
«main»: {
«temp»: 288.15,
«pressure»: 1020,
«humidity»: 93,
«temp_min»: 288.15,
«temp_max»: 288.15
},
(…)
}
Esta API proporciona mucha información. Por ejemplo, las primeras líneas almacenan las coordenadas con la longitud y la latitud.
Arduino con shield Ethernet
Los ejemplos en esta publicación utilizan un Arduino con un shield Ethernet. Simplemente monta el shield en tu placa Arduino y conéctalo a tu red con un cable RJ45 para establecer una conexión a Internet.
Nota: los ejemplos proporcionados en este tutorial también funcionan con el ESP8266 y ESP32 con pequeños cambios.
Preparando el Arduino IDE
La forma más sencilla de decodificar y codificar cadenas JSON con el Arduino IDE es utilizando la biblioteca ArduinoJson 5.13.5, que fue diseñada para ser la biblioteca JSON más intuitiva, con el menor tamaño y la gestión de memoria más eficiente para Arduino.
Ha sido escrita pensando en Arduino, pero no está vinculada a las bibliotecas de Arduino, por lo que puedes utilizar esta biblioteca en cualquier otro proyecto C++. También hay un sitio web de documentación para la biblioteca con ejemplos y con la referencia API.
Funciones
- Decodificación JSON (los comentarios son compatibles)
- Codificación JSON (con sangría opcional)
- API elegante, muy fácil de usar
- Asignación fija de memoria (cero malloc)
- Sin duplicación de datos (copia cero)
- Portátil (escrito en C++98)
- Autocontenido (sin dependencia externa)
- Pequeño tamaño
- Biblioteca solo para el encabezado
- Licencia MIT
Compatible con
- Placas Arduino: Uno, Due, Mini, Micro, Yun…
- Placas ESP8266, ESP32 y WeMos
- Teensy, placas RedBearLab, Intel Edison y Galileo
- PlatformIO, Particle y Energia
Instalando la biblioteca ArduinoJson
Para este proyecto, necesitas instalar la biblioteca ArduinoJson en tu Arduino IDE:
- Haz clic aquí para descargar la versión 5.13.5 de ArduinoJson. Deberías tener una carpeta .zip en tu carpeta de Descargas
- Descomprime la carpeta .zip y deberías obtener la carpeta ArduinoJson-master
- Renombra la carpeta de ArduinoJson-master a ArduinoJson
- Mueve la carpeta ArduinoJson a la carpeta de bibliotecas de instalación de tu Arduino IDE
- Finalmente, vuelve a abrir tu Arduino IDE
Decodificación JSON – Analizar cadena JSON
Comencemos decodificando/análizando la siguiente cadena JSON:
{«sensor»:»gps»,»time»:1351824120,»data»:[48.756080,2.302038]}
Importa la biblioteca ArduinoJson:
#include <ArduinoJson.h>
ArduinoJson utiliza un búfer de memoria preasignado para almacenar el árbol JsonObject, esto se hace mediante StaticJsonBuffer. Puedes utilizar ArduinoJson Assistant para calcular el tamaño exacto del búfer, pero para este ejemplo 200 es suficiente.
Crea un arreglo de caracteres llamado json[] para almacenar una muestra de cadena JSON:
char json[] = «{«sensor»:»gps»,»time»:1351824120,»data»:[48.756080,2.302038]}»
Utiliza la función parseObject() para decodificar/analizar la cadena JSON en un JsonObject llamado root:
JsonObject& root = jsonBuffer.parseObject(json);
Para verificar si la decodificación/análisis fue exitosa, puedes llamar a root.success():
if(!root.success()) {
Serial.println(«parseObject() failed»);
return false;
}
El resultado puede ser falso por tres razones:
- la cadena JSON tiene una sintaxis inválida;
- la cadena JSON no representa un objeto;
- el StaticJsonBuffer es demasiado pequeño, utiliza ArduinoJson Assistant para calcular el tamaño del búfer.
Ahora que el objeto o arreglo está en memoria, puedes extraer los datos fácilmente. La forma más sencilla es utilizar JsonObject root:
const char* sensor = root[«sensor»];
long time = root[«time»];
double latitude = root[«data»][0];
double longitude = root[«data»][1];
Puedes utilizar las variables decodificadas sensor, time, latitude o longitude en la lógica de tu código.
API de OpenWeatherMap
Para un ejemplo real utilizando un Arduino con shield Ethernet, vamos a utilizar una API gratuita de OpenWeatherMap para solicitar el pronóstico del tiempo del día para tu ubicación elegida.
Aprender a usar las APIs es una gran habilidad porque te permite acceder a una amplia variedad de información en constante cambio, como el precio de las acciones actual, el tipo de cambio de divisas, las últimas noticias, actualizaciones de tráfico y mucho más.
Usando la API
El plan gratuito de OpenWeatherMap proporciona todo lo que necesitas para este ejemplo. Para utilizar la API necesitas una clave de API, conocida como APIID. Para obtener un APIID:
- Abre un navegador y ve a OpenWeatherMap
- Presiona el botón de registro y crea una cuenta gratuita
- Una vez creada tu cuenta, se te presentará un panel que contiene varias pestañas
- Selecciona la pestaña API Keys y copia tu clave única
Esta es una clave única que necesitas para extraer información del sitio. Copia y pega esta clave en algún lugar, la necesitarás en un momento.
Para extraer información sobre el clima en tu ubicación elegida, ingresa la siguiente URL con las secciones entre llaves reemplazadas con tu información de ubicación y tu clave única de API:
http://api.openweathermap.org/data/2.5/weather?q={tu ciudad},{tu código de país}&APPID={tu clave de API}
Reemplaza {tu ciudad} con la ciudad de la que deseas obtener los datos, {tu código de país} con el código de país para esa ciudad y {tu clave de API} con tu clave única que encontramos anteriormente. Por ejemplo, nuestra URL de API para la ciudad de Porto en Portugal, después de reemplazar con los detalles, sería:
http://api.openweathermap.org/data/2.5/weather?q=Porto,PT&APPID=801d2603e9f2e1c70e042e4——
Nota: más información sobre cómo utilizar la API para obtener información meteorológica está disponible aquí.
Copia tu URL en tu navegador y debería darte una gran cantidad de información que corresponde a la información meteorológica local.
En nuestro caso, devuelve el clima en Porto, Portugal, en el día de la escritura:
{
«coord»: {
«lon»: -8.61,
«lat»: 41.15
},
«weather»: [
{
«id»: 701,
«main»: «Mist»,
«description»: «mist»,
«icon»: «50d»
}
],
«base»: «stations»,
«main»: {
«temp»: 290.86,
«pressure»: 1014,
«humidity»: 88,
«temp_min»: 290.15,
«temp_max»: 292.15
},
(…)
}
Haciendo una solicitud de API con Arduino
Ahora que tienes una URL que devuelve los datos meteorológicos locales, puedes automatizar esta tarea y acceder a esos datos en tus proyectos de Arduino o ESP8266. Aquí tienes el guión completo que necesitas cargar en tu Arduino con shield Ethernet para devolver la temperatura en Kelvin y la humedad:
/*
* Rui Santos
* Complete Project Details https://randomnerdtutorials.com
* Based on the Arduino Ethernet Web Client Example
* and on the sketch "Sample Arduino Json Web Client" of the Arduino JSON library by Benoit Blanchon (bblanchon.github.io/ArduinoJson)
*/
#include <ArduinoJson.h>
#include <Ethernet.h>
#include <SPI.h>;
EthernetClient client;
// Name address for Open Weather Map API
const char* server = "api.openweathermap.org";
// Replace with your unique URL resource
const char* resource = "REPLACE_WITH_YOUR_URL_RESOURCE";```
// How your resource variable should look like, but with your own COUNTRY CODE, CITY and API KEY (that API KEY below is just an example):
//const char* resource = "/data/2.5/weather?q=Porto,pt&appid=bd939aa3d23ff33d3c8f5dd1";```
const unsigned long HTTP_TIMEOUT = 10000; // max respone time from server
const size_t MAX_CONTENT_SIZE = 512; // max size of the HTTP response
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// The type of data that we want to extract from the page
struct clientData {
char temp[8];
char humidity[8];
};
// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to initialize
}
Serial.println("Serial ready");
if(!Ethernet.begin(mac)) {
Serial.println("Failed to configure Ethernet");
return;
}
Serial.println("Ethernet ready");
delay(1000);
}```
// ARDUINO entry point #2: runs over and over again forever
void loop() {
if(connect(server)) {
if(sendRequest(server, resource) && skipResponseHeaders()) {
clientData clientData;
if(readReponseContent(&clientData)) {
printclientData(&clientData);
}
}
}
disconnect();
wait();
}```
// Open connection to the HTTP server
bool connect(const char* hostName) {
Serial.print("Connect to ");
Serial.println(hostName);
bool ok = client.connect(hostName, 80);
Serial.println(ok ? "Connected" : "Connection Failed!");
return ok;
}```
// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
Serial.print("GET ");
Serial.println(resource);
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("Connection: close");
client.println();
return true;
}```
// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
// HTTP headers end with an empty line
char endOfHeaders[] = "rnrn";
client.setTimeout(HTTP_TIMEOUT);
bool ok = client.find(endOfHeaders);
if (!ok) {
Serial.println("No response or invalid response!");
}
return ok;
}```
// Parse the JSON from the input string and extract the interesting values
// Here is the JSON we need to parse
/*{
"coord": {
"lon": -8.61,
"lat": 41.15
},
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
"base": "stations",
"main": {
"temp": 296.15,
"pressure": 1020,
"humidity": 69,
"temp_min": 296.15,
"temp_max": 296.15
},
"visibility": 10000,
"wind": {
"speed": 4.6,
"deg": 320
},
"clouds": {
"all": 0
},
"dt": 1499869800,
"sys": {
"type": 1,
"id": 5959,
"message": 0.0022,
"country": "PT",
"sunrise": 1499836380,
"sunset": 1499890019
},
"id": 2735943,
"name": "Porto",
"cod": 200
}*/```
bool readReponseContent(struct clientData* clientData) {
// Compute optimal size of the JSON buffer according to what we need to parse.
// See https://bblanchon.github.io/ArduinoJson/assistant/
const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) +
2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) +
JSON_OBJECT_SIZE(6
¡Interesante contenido, definitivamente voy a probarlo en mi proyecto con ESP8266!
¡Súper útil! Me viene genial para entender mejor cómo trabajar con JSON en mis proyectos de Arduino. ¡Gracias por compartir la información! 🤓👍🏼