IoT de estar por casa; conectando un sensor con la Onesait Platform (parte 3)
Pues llegamos a la tercera y última entrada -de momento- sobre nuestra aventura de conectar un sensor en casa y mandar las mediciones a la Onesait Platform.
En la primera entrada vimos cómo elegir el entorno de trabajo y montar tanto la ontología como el servicio API para ingestar los datos. Ya en la segunda parte os conté cómo enganchar los cables entre las placas, a configurar el IDE de Arduino para trabajar, a picar el código que recoja y mande las medidas a la Plataforma, y ver que efectivamente se recibía bien.
Bien, pues hoy vamos a hablar de cómo representar los datos de una manera medianamente atractiva, ya que visualizar una ristra de datos está bien, pero quizás no es lo más óptimo para cuando quiero ver qué temperatura hace ahora mismo o durante la última hora. Esta entrada no deja de ser una muestra de lo que se puede llegar a hacer, por lo que si dominas SQL, HTML/CSS y/o JavaScript, puedes montarte algo muy interesante.
A lo que vamos. El objetivo es crear un Dashboard en la Plataforma que nos muestre la información de los sensores. Así por dar variedad, podremos mostrar la información de los dos sensores en tiempo real en cajetines (opción A) o en un plano de la casa (opción B), y mostrar la información acumulada de la última hora en una gráfica. O dicho de otra forma, hacer esto:
Podéis navegar entre las pestañas para ver las distintas representaciones de los datos. Para ver bien la opción de «Home Map» os recomiendo ver el Dashboard en grande.
Para conseguir esto, en primer lugar vamos a generar unos Datasources en los que procesar los datos existentes en las ontologías y formatear la salida para lo que vamos a necesitar. Seguidamente vamos a generar los Gadgets donde representar los datos de los Datasources creados. Cuando los tengamos, sólo tendremos que añadirlos al Dashboard y listo.
Creación de los Datasources
Empezaremos por la parte «árida» del tema, que incluye consultas SQL de por medio. Lo primero es preguntarse: «¿qué es lo que vamos a necesitar?».
Queremos representar en un Gadget los valores en tiempo real (o últimos registros, según se vea) de temperatura y humedad por habitación de casa. Por tanto, habrá que obtener el último valor de temperatura y el último valor de humedad (ordenado por fecha, claro) de cada tipo de sensor. Dicho y hecho, vamos a ello.
Navegaremos al menú de Visualización y GIS > Mis Datasources, y una vez allí crearemos un nuevo Datasource, rellando los campos como se indica a acontinuación:
- Identification: el primer Datasource que voy a crear corresponde al sensor del salón, por lo que le pondré un nombre para relacionarlo: «arduinoDHT22_diningRoom_last» (recordad que si estáis siguiendo los pasos de este tutorial, no podéis duplicar los nombres, por lo que os recomiendo añadir vuestras iniciales o algo similar al nombre que le deis al Datasource).
- Seleccione ontología: aquí seleccionaremos la ontología en la que estamos almacenando los datos, que en mi caso es la de «arduinoDHT22».
- Registros máximos: aquí lo dejamos en «1», ya que sólo vamos a recuperar un objeto.
- Tiempo de refresco: este punto es importante. El valor indicado será el tiempo en segundos que usará el Datasource para actualizar sus datos; es decir, que si le indicamos 60 segundos, como es mi caso, actualizará sus datos leyendo la ontología cada 60 segundos. Gracias a esta opción cada minuto obtenemos automáticamente el último valor.
- Descripción: en este pequeño campo podemos introducir un tostón descriptivo de lo que hace nuestro Datasource.
- Consulta del Datasource: aquí es donde hacemos magia usando SQL para obtener lo que queremos de la ontología. Como esto creo que es mejor explicarlo poco a poco, lo vamos a ver detenidamente a continuación.
Generar la consulta del Datasource
Si sois dichos en eso del SQL con Quasar (por aquí se habla al respecto), seguro que haréis una consulta mucho mejor que la que os voy a proponer, pero sino, acompañadme en este pedregal hasta la consulta prometida.
Supongamos que partimos de la siguiente consulta:
SELECT * FROM arduinoDHT22 AS table
Esto nos devolverá todo lo que hay en la ontología.
[{"arduinoDHT22":{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":29.9,"humidity":46},"contextData":{"deviceTemplate":"","device":null,"clientConnection":null,"clientSession":null,"user":"fjla.dev","timezoneId":"UTC","timestamp":"2020-08-26T21:45:06Z","timestampMillis":1598478306186,"source":"APIMANAGER"}},{"arduinoDHT22":{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":29.9,"humidity":45.5},"contextData":{"deviceTemplate":"","device":null,"clientConnection":null,"clientSession":null,"user":"fjla.dev","timezoneId":"UTC","timestamp":"2020-08-26T21:46:13Z","timestampMillis":1598478373455,"source":"APIMANAGER"}},{"arduinoDHT22":{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":29.9,"humidity":45.8},"contextData":{"deviceTemplate":"","device":null,"clientConnection":null,"clientSession":null,"user":"fjla.dev","timezoneId":"UTC","timestamp":"2020-08-26T21:47:15Z","timestampMillis":1598478435439,"source":"APIMANAGER"}}... ]
Sin embargo, no nos interesa tener todos los campos existentes, sino únicamente los de identificación del sensor, su localización, la temperatura, la humedad y la fecha. Considerando esto, vamos a generar una consulta que nos devuelva únicamente esa información, ordenada como tal:
SELECT
table.arduinoDHT22.deviceId,
table.arduinoDHT22.location,
table.arduinoDHT22.temperature
FROM arduinoDHT22 AS table
Con esta consulta, obtenemos algo más próximo a lo que buscamos:
[{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":29.9},{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":29.9},{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":29.9}... ]
Seguidamente vamos a filtrar la localización del sensor, para poder diferenciar entre el salón y el despacho. Esto lo haremos añadiendo una condición «WHERE» diferenciando entre ‘Dining Room’ y ‘Office’. Si habéis usado otros nombres, pues aquí es donde los tendréis que filtrar:
SELECT
table.arduinoDHT22.deviceId,
table.arduinoDHT22.location,
table.arduinoDHT22.temperature
FROM arduinoDHT22 AS table
WHERE table.arduinoDHT22.location = 'Dining Room'
En este caso la salida será igual que la que os he mostrado antes, pero cambiando a ‘Office’, sale algo como esto:
[{"deviceId":"esp32-wroom-32D_02","location":"Office","temperature":28.2},{"deviceId":"esp32-wroom-32D_02","location":"Office","temperature":28.1},{"deviceId":"esp32-wroom-32D_02","location":"Office","temperature":28.1}... ]
Ahora bien, los datos que estamos recuperando son de principio a fin; es decir, que el primer dato es el más antiguo, y el último el más moderno. A nosotros nos interesa ese último valor, así que vamos a ordenar la consulta de manera descendente (lo más moderno primero), usando para ello el campo de «timestamp».
Sí, ya lo sé, no tenemos campo timestamp porque he sido un vago y no lo mando desde el sensor cuando hago la medición. Seguro que alguno lo ha pensado y ha sido menos vago que yo y lo ha añadido. Bien. En mi caso voy a utilizar el timestamp de la ingesta del dato en la ontología. Ideal, ¿eh?
Este timestamp no se encuentra en el objeto «arduinoDHT22», sino en otro objeto a su mismo nivel llamado «contextData».
Para filtrar la consulta a partir de dicho campo y de manera que lo más actual salga primero, actualizaremos la consulta usando el «ORDER BY» en modo «DESC». Además, incluiremos el timestamp también como uno de los valores a recopilar.
SELECT
table.arduinoDHT22.deviceId,
table.arduinoDHT22.location,
table.arduinoDHT22.temperature,
table.arduinoDHT22.humidity,
table.contextData.timestamp
FROM arduinoDHT22 AS table
WHERE table.arduinoDHT22.location = 'Dining Room'
ORDER BY table.contextData.timestamp DESC
Ahora los datos salen correctamente ordenados. Echad un ojo a las horas de medición para que veáis que no os trato de timar:
{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":25.5,"humidity":62.5,"timestamp":"2020-09-23T14:52:12Z"},{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":25.5,"humidity":62.5,"timestamp":"2020-09-23T14:51:09Z"},{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":25.4,"humidity":62.3,"timestamp":"2020-09-23T14:50:07Z"}
El primer dato es de las 14:52 (ojo que está en UTC+0, no +2), el segundo a las 14:51, el tercero a las 14:50… vamos, que es tal como queríamos. Sin embargo, tenemos muuuuchos datos, cuando sólo nos interesa el último. Bueno, esto es fácil, es añadir un «LIMIT» y listo:
SELECT
table.arduinoDHT22.deviceId,
table.arduinoDHT22.location,
table.arduinoDHT22.temperature,
table.arduinoDHT22.humidity,
table.contextData.timestamp
FROM arduinoDHT22 AS table
WHERE table.arduinoDHT22.location = 'Dining Room'
ORDER BY table.contextData.timestamp DESC
LIMIT 1
Y con esto ya lo tenemos, el último registro obtenido desde el sensor:
[{"deviceId":"esp32-wroom-32D_01","location":"Dining Room","temperature":25.4,"humidity":62.3,"timestamp":"2020-09-23T14:53:14Z"}]
Esto lo repetiríamos con otro Datasource similar, pero para el despacho en vez del salón. Sólo hay que cambiar ‘Dining Room’ por ‘Office’ (nuevamente, en mi caso), por lo que os lo dejo a vosotros.
El otro tipo de Datasource que vamos a crear corresponde al que vamos a usar para generar la gráfica de evolución de temperatura de la última hora. Aquí la idea es recuperar los últimos sesenta registros de temperatura correspondientes al salón. La consulta es muy similar a lo que hemos generado previamente:
SELECT
table.arduinoDHT22.temperature,
table.contextData.timestamp
FROM arduinoDHT22 AS table
WHERE table.arduinoDHT22.location = 'Dining Room'
ORDER BY table.contextData.timestamp DESC
LIMIT 60
El resultado es un listado de los últimos 60 registros de temperatura del salón.
[{"temperature":25.5,"timestamp":"2020-09-23T15:02:34Z"},{"temperature":25.4,"timestamp":"2020-09-23T15:01:32Z"},{"temperature":25.4,"timestamp":"2020-09-23T15:00:30Z"},{"temperature":25.4,"timestamp":"2020-09-23T14:59:27Z"},{"temperature":25.4,"timestamp":"2020-09-23T14:58:25Z"},{"temperature":25.4,"timestamp":"2020-09-23T14:57:23Z"}... ]
Parece sencillo, ¿verdad? Pues dejadme deciros que hemos terminado el pedregal, y ahora pasamos a la parte del pinta y colorea.
Generar el Dashboard
Hay gente que prefiere crear primero los elementos que va a utilizar y luego ya crear el Dashboard para ir incrustándolos. No es mi caso. Por tanto, desde el menú de Visualización y GIS > Mis Dashboards crearemos un nuevo «Dashboard» para nuestro proyecto de sensores.
A la hora de crearlo, introduciremos la siguiente información:
- Identificación: el nombre que tendrá el Dashboard. Para este tutorial le he dado el nombre de «arduinoDHT22_infoPanel», pero como en casos anteriores si estáis haciendo el tutorial también, modificad el nombre con vuestras iniciales o algo que ya sabéis que no se puede duplicar nombres.
- Descripción: aquí meted algún texto que describa vuestro Dashboard.
- Pública: por si queréis que cualquier pueda acceder sin estar registrado. Por ejemplo yo tengo mi Dashboard público para poder incrustarlo en el blog y que podáis consultarlo.
- Categoría y Subcategoría: lo he dejado vacío, pero podéis rellenarlo si queréis.
Una vez que tengamos creado el Dashboard, lo decoraremos al gusto (cabecera, color de fondo, etc.) y lo dejamos listo para llenarlo con Gadgets.
Preparación de los Gadgets
Vamos a generar un primer Gadget con colorines e iconos bonitos que sea el que nos muestre la temperatura y humedad de una de las habitaciones.
Este tipo de Gadget que vamos a crear no tiene una plantilla predefinida, sino que tendremos que crearlo desde cero (por eso no lo hacemos desde el creador de Gadgets). Para ello desde el propio Dashboard pulsaremos en el botoncito de ( + ) y de las distintas opciones que salen elegiremos la de «Template».
Cuando nos pregunte si queremos usar alguna plantilla, diremos que no. Esto nos generará un Gadget vacío con un aspecto como este:
Seleccionando los tres puntitos de arriba a la derecha, accederemos al menú del Gadget. De entre las distintas opciones disponibles, seleccionaremos la de «Edit», lo que nos abrirá el editor de código del Gadget.
Si ya habéis trabajado antes con este tipo de Gadgets, la cosa no tiene misterio; a la izquierda se añade el código HTML y CSS (vamos a hacer una mini página web, podríamos decir), y a la derecha incluimos el código JavaScript necesario para hacer las lógicas y eso.
Para mi ejemplo de tarjeta, he creado una especie de lista en la que se muestra la temperatura, con un icono de temperatura, y la humedad, con un icono de humedad. Esto explicado a nivel de código vendría a ser algo como esto:
<!-- Write your HTML <div></div> and CSS <style></style> here -->
<!--Focus here and F11 to full screen editor-->
<style>
#container {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
width: 100%;
height: 100%;
}
.row {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100px;
}
.icon-temperature {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 60 60'%3E%3Cg id='Grupo_7' data-name='Grupo 7' transform='translate(-91 -3034)'%3E%3Ccircle id='Elipse_2' data-name='Elipse 2' cx='30' cy='30' r='30' transform='translate(91 3034)' fill='%23eebe22'/%3E%3Cg id='termometro_1_' data-name='termometro (1)' transform='translate(110.105 3042.09)'%3E%3Cg id='Grupo_2' data-name='Grupo 2' transform='translate(0)'%3E%3Cg id='Grupo_1' data-name='Grupo 1'%3E%3Cpath id='Trazado_1' data-name='Trazado 1' d='M146.359,24.836V7.344a7.344,7.344,0,1,0-14.687,0V24.836a11.015,11.015,0,1,0,14.687,0ZM139.015,40.39a7.344,7.344,0,0,1-4.895-12.818l1.223-1.095V7.344a3.672,3.672,0,1,1,7.344,0V26.477l1.223,1.095a7.344,7.344,0,0,1-4.895,12.818Z' transform='translate(-128 0)' fill='%23fff'/%3E%3C/g%3E%3C/g%3E%3Cg id='Grupo_4' data-name='Grupo 4' transform='translate(9.18 14.687)'%3E%3Cg id='Grupo_3' data-name='Grupo 3'%3E%3Crect id='Rectángulo_2' data-name='Rectángulo 2' width='3.672' height='22.031' fill='%23fff'/%3E%3C/g%3E%3C/g%3E%3Cg id='Grupo_6' data-name='Grupo 6' transform='translate(6.091 27.605)'%3E%3Cg id='Grupo_5' data-name='Grupo 5' transform='translate(0 0)'%3E%3Cellipse id='Elipse_1' data-name='Elipse 1' cx='5.5' cy='5' rx='5.5' ry='5' transform='translate(-0.196 0.306)' fill='%23fff'/%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
width: 60px;
height: 60px;
}
.icon-humidity {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 60 60'%3E%3Cg id='Grupo_12' data-name='Grupo 12' transform='translate(-158 -3034)'%3E%3Ccircle id='Elipse_3' data-name='Elipse 3' cx='30' cy='30' r='30' transform='translate(158 3034)' fill='%2327bef6'/%3E%3Cg id='soltar_1_' data-name='soltar (1)' transform='translate(130.768 3042.084)'%3E%3Cg id='Grupo_9' data-name='Grupo 9' transform='translate(41.232 0)'%3E%3Cg id='Grupo_8' data-name='Grupo 8' transform='translate(0 0)'%3E%3Cpath id='Trazado_2' data-name='Trazado 2' d='M61.1,4.842C60.083,3.351,59.188,1.978,58.353.726a1.816,1.816,0,0,0-.477-.477,1.554,1.554,0,0,0-2.148.477c-.776,1.253-1.67,2.565-2.744,4.116-4.713,6.92-11.752,17.36-11.752,23.325a15.738,15.738,0,0,0,4.653,11.156,15.938,15.938,0,0,0,11.156,4.593A15.887,15.887,0,0,0,72.849,28.108C72.849,22.142,65.81,11.762,61.1,4.842Zm4.951,32.274a12.617,12.617,0,0,1-9.008,3.7,12.868,12.868,0,0,1-9.008-3.7,12.617,12.617,0,0,1-3.7-9.008c0-5.011,6.741-14.974,11.215-21.6.537-.776,1.014-1.551,1.491-2.207.477.656.954,1.432,1.491,2.207,4.474,6.681,11.215,16.584,11.215,21.6A12.868,12.868,0,0,1,66.049,37.115Z' transform='translate(-41.232 0)' fill='%23fff'/%3E%3C/g%3E%3C/g%3E%3Cg id='Grupo_11' data-name='Grupo 11' transform='translate(60.012 27.03)'%3E%3Cg id='Grupo_10' data-name='Grupo 10'%3E%3Cpath id='Trazado_3' data-name='Trazado 3' d='M173.428,181.243a1.529,1.529,0,0,0-1.611,1.432,7.679,7.679,0,0,1-1.133,3.639,7.25,7.25,0,0,1-2.744,2.625,1.576,1.576,0,0,0,1.551,2.744,10.337,10.337,0,0,0,3.818-3.7,10.152,10.152,0,0,0,1.551-5.13A1.529,1.529,0,0,0,173.428,181.243Z' transform='translate(-167.152 -181.24)' fill='%23fff'/%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A");
width: 60px;
height: 60px;
}
.measure {
font-weight: bold;
margin-left: -40px;
}
#value {
font-size: 300%;
margin-left: -20px;
}
.unit {
margin-left: -60px;
margin-top: -20px;
}
</style>
<div id="container" class="diningRoom">
<div class="row">
<div class="icon-temperature"></div>
<div class="measure">Temperature</div>
<div id="value" class="temperature">-</div>
<div class="unit">ºC</div>
</div>
<div class="row">
<div class="icon-humidity"></div>
<div class="measure">Humidity</div>
<div id="value" class="humidity">-</div>
<div class="unit">%</div>
</div>
</div>
Aquí cualquiera que sepa algo de HTML se puede montar su tarjeta como prefiera. Lo de arriba es un mero ejemplo, pero con un par de detalles a remarcar.
El primero tiene que ver con las imágenes de los iconos de temperatura y humedad. En vez de enlazar a algo externo, los he generado en formato SVG e introducido a pelo como un elemento data:image/svg+xml de fondo de DIV (por eso esa ristra de letras y numeritos tan larga). Esta es una solución rápida ya que evita depender de elementos externos, pero quizás prefiráis ser más tradicionales y enlazar a alguna imagen que tengáis por ahí.
Otro punto a indicar es el nombre de las clases; el contenedor tiene un nombre de clase de «diningRoom», para poder identificarlo y diferenciarlo de otras habitaciones (en caso de que uséis más de un sensor, como es mi caso). También hay una clase llamada «temperature» y otra llamada «humidity». Esto es importante porque a partir de esos nombres de clase identificaremos el elemento del DOM al que le meteremos los valores de temperatura y humedad del Datasource. Si os da por cambiar los nombres, ´simplemente tenedlo en cuenta.
Luego, la lógica de funcionamiento con Javascript, la meteremos en el panel derecho del Gadget. De entre las diferentes funciones que nos aparecen por defecto, utilizaremos la segunda, la de «drawLiveComponent». Esta función se ejecuta cada vez que se modifica el Datasource, que en nuestro caso hemos definido que sea cada minuto, que es cuando recibimos los datos desde nuestro sensor.
A nivel de código introduciremos lo siguiente:
vm.drawLiveComponent = function(newData, oldData){
const deviceData = newData[0]
const temperature = deviceData.temperature
const humidity = deviceData.humidity
const div = document.getElementsByClassName("diningRoom")[0]
div.getElementsByClassName("temperature")[0].innerHTML = temperature
div.getElementsByClassName("humidity")[0].innerHTML = humidity
};
Aquí lo que hacemos no tiene mucho misterio. Del Datasource recuperamos los valores de temperatura y humedad, seleccionamos el elemento del DOM con el nombre de clase asignado al comedor («diningRoom» en mi código), y sustituimos el contenido de los elementos con nombre de clase de temperatura y humedad con su valor correspondiente.
Si a continuación compilamos y sincronizamos los cambios, grabamos el Dashboard y lo actualizamos, el cajetín que hemos preparado debería de estar recibiendo y mostrando los datos de temperatura y humedad.
En caso de que tengáis un segundo sensor (o los que sean), os dejo a vosotros que creéis los Gadgets correspondientes. En esencia es lo mismo pero cambiando el identificador de habitación, y el Datasource que le metéis.
Pues con esto ya lo tendríamos. Así podéis visualizarlo por el móvil, tableta o portátil rápidamente y de un vistazo (si habéis puesto el Dashboard como público, claro. Sino tendréis que loguearos para entrar).
Si os queréis poner creativos, podéis jugar con los Gadgets y crearos algo más personalizado. Por ejemplo, mi segunda pestaña, la de «Home Map» muestra una representación pseudo-fidedigna de las habitaciones de mi casa, y se puede ver de un vistazo la temperatura que hace en casa sitio. Os dejo una captura porque lo que se ve en el Dashboard incrustado es en tamaño móvil y esto hay que verlo en pantalla ancha:
Aquí ya cada uno puede organizárselo como quiera; poner en el centro de cada habitación los datos, poner un reloj de actualización, modificar los colores de fondo según umbrales de temperatura, etc. Estos Gadgets serían también de tipo «Template», así que con HTML + CSS + JS tenéis un mundo por delante.
A continuación vamos a pasar al segundo tipo de Gadget que queríamos crear; el de la evolución temporal.
Este Gadget lo podemos crear desde el propio Dashboard, o desde el gestor de Gadgets. Por variar un poco vamos a hacerlo con esto último, así que navegaremos hasta el menú de Visualización y GIS > Mis Gadgets, y crearemos uno nuevo.
Aquí no tendremos más que escoger un nombre para el Gadget, y la Ontología o Datasource con el que lo alimentaremos.
- Nombre de Gadget: para este ejemplo he usado un nombre que sea fácil de identificar: «arduinoDHT22_diningRoom_temperature_lastHour».
- Ontología o Datasource: aquí he escogido el Datasource que hemos creado al principio, el de «arduinoDHT22_diningRoom_temperature_lastHour» (si, se llama igual que el Gadget).
Una vez que hayamos introducido estos datos, tendremos que elegir el tipo de Gadget que nos interesa. Entre las diferentes opciones he usado el de «line».
Seguidamente nos saldrá el configurador del Gadget, donde tendremos que indicar los parámetros que nos vayan solicitando. Aquí lo importante es indicar que en el eje X queremos mostrar el tiempo, el campo «timestamp»; y en el eje Y el valor de la medida, en este caso el campo «temperature». Luego escogemos algún colorcillo que nos guste y gráfica lista.
Y ya está. Sí, en serio, ya hemos creado una gráfica temporal con la información de la última hora (o deberíamos decir mejor, de los últimos sesenta registros).
Esta gráfica corresponde con la temperatura del salón, pero podéis generar también la de la humedad (en el mismo Gadget o en otro diferente), las gráficas de otra habitación si tenéis más de un sensor, etc.
Bueno, pues ahora si, con esto damos finalizada esta trilogía de cómo conectar un sensor IoT a la Plataforma, y cómo representarlo de una manera visual.
Espero que os haya gustado, y si tenéis alguna duda, no os sale nada o queréis decir hola, dejéis un comentario. Hasta la próxima.
Pingback: Creando Ontologías desde Time Series – Onesait Platform Blog