Mostrando las entradas con la etiqueta datos. Mostrar todas las entradas
Mostrando las entradas con la etiqueta datos. Mostrar todas las entradas

domingo, 6 de enero de 2019

Arduino con JSON

Hoy les traigo una librería capaz de integrar Json a arduino, es decir, la librería se encarga de decodificar texto en variables y viceversa. Con esta librería, por ejemplo, vamos a ser capaces de adquirir datos desde la red y utilizarlos fácilmente en nuestro arduino (sea cual sea). La idea de esta librería es facilitar la adquisición de datos de la red desde nuestro arduino.

Json tiene la siguiente sintaxis:

{"nombreDeLaVariable":"valor"}

Para más de un dato va a figurar de la siguiente forma:

{"nombre1":"valor1", "nombre2":"valor2", "nombre3":"valor3"}

Y un arreglo de datos se vería de la siguiente manera:

{"nombreGeneral":[{"nombre1":"valor1", "nombre2":"valor2"}, {"nombre1":"valor3", "nombre2":"valor4"}, {"nombre1":"valor5", "nombre2":"valor6"}]}

Aunque por lo general el Json de arriba se declara de la siguiente forma:

{
   "nombreGeneral":[
      {"nombre1":"valor1", "nombre2":"valor2"},
      {"nombre1":"valor3", "nombre2":"valor4"},
      {"nombre1":"valor5", "nombre2":"valor6"}
   ]
}

Esto es para que sea más legible dentro del programa. Por lo general le asignamos estas cadenas a alguna variable, quedando de la forma:

variable = {
   "nombreGeneral":[
      {"nombre1":"valor1", "nombre2":"valor2"},
      {"nombre1":"valor3", "nombre2":"valor4"},
      {"nombre1":"valor5", "nombre2":"valor6"}
   ]
}

Por lo tanto si queremos acceder a "valor6" utilizaríamos la siguiente cadena:

variable.nombreGeneral[2].nombre2

En donde vamos "accediendo" a los distintos niveles del objeto hasta llegar a la variable deseada. Esto puede parecer un poco confuso para el ejemplo que dí, por lo que acá les dejo otro, en donde vamos a englobar los vegetales y los vamos a separar entre frutas y verduras, y a cada vegetal le vamos a dar un nombre y un sabor:

vegetales = {
   "verduras":[
      {"nombre":"lechuga", "sabor":"semi amargo"},
      {"nombre":"zanahoria", "sabor":"semi dulce"},
      {"nombre":"radicheta", "sabor":"amargo"}
   ],
   "frutas":[
      {"nombre":"limón", "sabor":"ácido"},
      {"nombre":"mandarina", "sabor":"dulce"},
      {"nombre":"pomelo", "sabor":"amargo"}
   ]
}

Entonces si queremos obtener el sabor de la mandarina siempre vamos a comenzar escribiendo el nombre de nuestra variable, que en este caso es "vegetales", luego vamos por el siguiente identificador, que es una fruta, y sabemos que la mandarina se encuentra en la posición 1 (porque se empieza contando desde el 0), entonces nos dirigimos a esa posición, y por último vamos al sabor, entonces nos quedaría de la forma: "vegetales.frutas[1].sabor".
La estructura que yo definí no es única, por lo que no hay límites de identificadores que coloquemos, a las verduras podríamos agregarle el color o la textura, mientras que a las frutas podríamos ponerle la cantidad de azúcar en gramos o la forma.
El Json es muy versátil y tiene muchas aplicaciones más sobre todo en javaScript, dónde podemos poner hasta funciones como valor.

Yendo a arduino, acá les dejo un código que utiliza los vegetales de arriba y muestra todos los datos por puerto serie.


#include <ArduinoJson.h>

void setup() {
  // Inicialiazmos el puerto serie
  Serial.begin(9600);
  while(!Serial){}

  /*
   * Acá le asignamos una memoria para que la librería
   * trabaje.
   * 
   * Dentro de los símbolos de mayor y menos le vamos
   * a pasar la cantidad de bytes que le queremos asig-
   * nar, dependiendo de la longitud de los datos con
   * los que vamos a trabajar tendremos que asignar más
   * o menos memora
   */
  StaticJsonBuffer<600> jsonBuffer;

  char json[] = 
  
  "{" 
    "\"verduras\":["
      "{\"nombre\":\"lechuga\",\"sabor\":\"semi amargo\"},"
      "{\"nombre\":\"zanahoria\",\"sabor\":\"semi dulce\"},"
      "{\"nombre\":\"radicheta\",\"sabor\":\"amargo\"}"
    "],"
    "\"frutas\":["
      "{\"nombre\":\"limon\",\"sabor\":\"acido\"},"
      "{\"nombre\":\"mandarina\",\"sabor\":\"dulce\"},"
      "{\"nombre\":\"pomelo\",\"sabor\":\"amargo\"}"
    "]"
  "}";

  //Creamos el objeto bajo el nombre vegetales
  JsonObject& vegetales = jsonBuffer.parseObject(json);
  
  //Verificamos que todo se generó de forma correcta
  if (!vegetales.success()) {
    Serial.println("fallo: parseObject()");
    return;
  }


  /* Mostramos los valores.
   * 
   * Como dato, antes de trabajar con los datos hay
   * que pasarlos a una variable del tipo "const char*"
   * para que funcione correctamente.
   */

  Serial.println("");
  for(int i = 0; i < 3; i++)
  {
    const char* nombre = vegetales["verduras"][i]["nombre"];
    const char* sabor = vegetales["verduras"][i]["sabor"];
    Serial.print("verdura: ");
    Serial.print(nombre);
    Serial.print(", sabor: ");
    Serial.println(sabor);
  }
  for(int i = 0; i < 3; i++)
  {
    const char* nombre = vegetales["frutas"][i]["nombre"];
    const char* sabor = vegetales["frutas"][i]["sabor"];
    Serial.print("fruta: ");
    Serial.print(nombre);
    Serial.print(", sabor: ");
    Serial.println(sabor);
  }
}

void loop() {
  //no utilizado
}


Si necesitamos saber cuánta memoria asignarle al buffer de los datos Json, está el  sitio arduinojson.org/v5/assistant en donde podremos ingresar el texto que se va a utilizar como Json y nos da el tamaño a asignar. Además, más abajo, nos va a dar una porción de código que ya nos genera una variable por cada elemento del texto Json.

Además esta librería tiene un generador de Json que con lo que expliqué arriba y el ejemplo de la librería debería bastar para que se entienda.



domingo, 2 de julio de 2017

Cómo mantener las gráficas en node-red

Hoy les voy a explicar, como indica el título, cómo mantener las gráficas en node-red incluso si éste se detiene o se corta la luz.

Si realizaron la estación meteorológica simple (la versión que les dejé en el link de mega) quizá les pasó que las gráficas históricas se perdieron si se desconectaba el servidor o si detenían los servicios (hay algunos casos más en los que se pueden perder los datos, pero no los voy a mencionar porque el resultado siempre es el mismo, la pérdida de los datos), sin lugar a dudas a mi me pasó varias veces y tenía que mantener el servidor funcionando 24/7 si no quería perder esos datos, lo que hacía que la raspberry pi se me tildase o funcionase erráticamente luego de estar encendida por un par de meses (no me ejecutaba las funciones correctamente por lo que no filtraba los datos que se mostraban). Luego del último corte de luz me puse a pensar en cómo corregir eso, y decidí guardar los datos en un archivo, simplemente conectando los nodos de la siguiente forma


Así no perdía los datos, pero seguía sin poder mostrarlos nuevamente, revisando los datos que se guardaban, quedaba un objeto como el siguiente:

[{"key":"Series 1","values":[[1492920133027,32],[1492920135027, 33]...]}]

Si analizamos este objeto nos quedan las propiedades "Key" que guarda el valor "Series 1" y "values" que es un array de arrays (o un array de dos dimensiones) que contiene los milisegundos desde el año 1970 y la temperatura (o la humedad, si analizamos el otro archivo) correspondiente a esa fecha exacta.
Mi primera prueba fue crear una función que devuelva un objeto similar y mandarlo directo al graficador, pero no sirvió (lo más probable es que haya echo algo mal dado que no tengo experiencia trabajando con objetos), por lo que probé mandar el mismo objeto que guardo de la siguiente forma


Cuando presionaba el botón que inyecta el "timestamp" debería mandar los datos del archivo, de más está decir que esto no funciona porque lo que se guarda dentro del archivo es procesado como texto plano y no como un objeto, pero esto se resuelve poniendo el nodo json de la siguiente forma

Este nodo lo que hace es tomar el  texto plano y lo transforma en lo que es (en este caso un objeto). Esto sí es tomado de forma correcta por el nodo "chart" y nos muestra los datos subidos, entonces ahora nos faltaría hacer que se guarde en ese mismo archivo y la solución que se me ocurrió es la siguiente (sé que el tamaño de la imágen es bastante chico)


Cada tres horas mando el promedio de la humedad (en este caso) al nodo "chart" el cual me devuelve todos los puntos graficados, en la función siguiente verifico si lo que me manda está vacío, si lo está no devuelve nada y si no lo está guarda en el archivo todos los datos. Cada vez que se enciende el servidor el nodo "inject" manda una señal que hace que se lea el archivo donde se guardan los datos, estos se convierten a objeto y se mandan al nodo "chart" que los grafica.
Esta solución sigue teniendo el problema de que se muestra el último año de datos, y luego se van a ir descartando los datos más antiguos al año, por lo que no podríamos almacenar más que eso (si modificamos cuántos días queremos mostrar en el pasado podríamos hacer que se muestre, pero como el espacio para graficar es reducido llegaría un punto en el cuál no se podría apreciar ningún detalle).
La solución a esto podría ser crear un archivo por año y que se muestren todos los datos del año actual (del primero de enero al 31 de diciembre), y esto se podría implementar en la última función (la que está a la salida de la gráfica). Vamos a obtener el año actual y lo vamos a usar como nombre del archivo (o al menos como parte del nombre del archivo) y luego le vamos a pasar el nombre del archivo al nodo que guarda los datos para que los guarde en dicho archivo o cree el archivo si el mismo no existe. Un ejemplo de esto sería lo siguiente, los nodos función obtienen el año, le agregan la ruta y pasan ese string como nombre de archivo, el nodo que maneja archivos crea el archivo y guarda el dato, si ya está creado solo guarda el dato, el otro nodo de manejo de archivos sólo lo abre y lo muestra por consola.

El resultado final nos quedaría algo similar a la imágen anterior, pero con un nodo de función extra, deberíamos crear los archivos iniciales por como está planteado el sistema.

Acá les dejo el código de la versión actualizada de la estación meteorológica para que puedan importar y ver el código, o la configuración, de cada nodo. Vale aclarar que el sistema de archivos que estoy usando es el de linux que es el sistema operativo recomendado para la raspberry pi 3, si tienen montado este servidor en windows hay que cambiar la ruta de los archivos.

https://mega.nz/#!W5g1UBII!Xwh1HVaIYwi6lRhlVImE--tZM8qVIy2kR73KcwNCgDM