Gráficas de estado de sensores conectados a la Internet de las cosas IoT
Una de las ventajas de conectar una red de sensores a la Internet de las cosas es poder analizar los datos que se obtienen. Representando gráficamente esa información una persona (en contraposición a un programa) puede comprender de manera más intuitiva el significado de las magnitudes monitorizadas, por ejemplo, comparándolas entre ellas o siguiendo su desarrollo a lo largo del tiempo.
Este artículo comienza una serie, formada por cuatro partes, que explica una sencilla propuesta de representación gráfica de datos obtenidos por sensores conectados a la IoT. Con la misma filosofía que en otros artículos, el método sugerido es perfectamente funcional aunque el principal objetivo sea el didáctico. Como el perfil técnico del público al que va dirigido el blog polaridad.es, y este texto, es de electrónica y no de desarrollo web, cada uno de los apartados sirve de introducción a los lenguajes o tecnología utilizados: HTML, CSS, SVG y JavaScript.
Los artículos de la anterior serie sobre cómo almacenar los datos obtenidos por los dispositivos conectados a la Internet de las cosas (IoT) terminaban explicando cómo acceder a la información guardada en las bases de datos. En los ejemplos de la serie, para hacer más fácil el proceso, se utilizaba como intermediario un servidor web que se encargaba de recibir los datos por medio de peticiones POST del protocolo HTTP, almacenarlos en una base de datos y mostrarlos en una página web.
Si bien el principal inconveniente de este sistema es el rendimiento (que se podría paliar con alternativas como Node.js y MongoDB, que se explicarán en próximos artículos) a cambio aporta dos grandes ventajas: su implementación es muy sencilla (incluyendo la disponibilidad de servicios púplicos) y puede mostrar los datos en un navegador, es decir, no necesita aplicaciones específicas (como una app para un dispositivo móvil) para presentar la información almacenada que representaría el histórico del estado de los dispositivos conectados a Internet de las cosas.
Explotando la ventaja que supone poder presentar fácilmente en una página web la información que se ha ido almacenando con este sistema sobre el estado de los dispositivos conectados a IoT, en este artículo se explica cómo mostrar gráficamente esa información utilizando el formato SVG desde JavaScript para generar dinámicamente una página web en HTML.
Existen multitud de librerías JavaScript con las que poder resolver la presentación gráfica de datos. Estos artículos no pretenden desarrollar otra más; la finalidad de este texto es comprender el proceso y poder desarrollar implementaciones propias; un objetivo didáctico además de productivo. Si estás interesado en utilizar un producto más que en desarrollarlo tú mismo, te recomiendo que eches un vistazo a alguna de las excelentes librerías para generar gráficos con JavaScript con licencias libres como Charts.js, Highcharts, Google Charts Tools, Epoch, Raphaël, Grafico (basada en Raphaël), dc.js, Chartist.js, D3.js (mi recomendación), C3.js (basada en D3.js), NVD3 (gráficos reusables para D3.js)…
Estructura del documento HTML con los gráficos SVG
En la propuesta de este artículo para presentar gráficamente los datos de los sensores, la página web en la que se muestran está formada por:
- el documento que sirve de contenedor está escrito en HTML,
- el aspecto de la página se define con código CSS,
- el dibujo de la gráfica se hace usando el lenguaje SVG y
- la lectura de los datos del servidor y la presentación de los gráficos se programa en JavaScript
Todos los elementos, especialmente el código HTML de la página, pueden generarse en el servidor con PHP como explica el artículo sobre el lenguaje de programación PHP de la serie sobre almacenamiento de datos de dispositivos conectados a Internet de las cosas.
El código CSS y JavaScript se pueden cargar (importar) en el código HTML en lugar de estar escritos directamente como parte del documento HTML. Esto presenta la ventaja de poder reutilizar los mismos documentos en varias páginas y la de poder editarlos más cómodamente; pero quizá el inconveniente de tardar un poco más en cargar dependiendo de si se puede usar el código contenido en caché (cargado en anteriores uso) o hasta un CDN. En la fase de producción es trivial integrar todo el código desde PHP generando un único documento en formato HTML con toda la información si es que se opta por esta alternativa. A lo largo de esta serie de artículos, por claridad, se considera que se trabaja con documentos separados.
A los efectos que nos interesan, para usarlo como contenedor de gráficos, y muy a grandes rasgos, el contenido del primer nivel de la estructura de un documento HTML sería:
1
2
3
4
5
6
7
|
<!DOCTYPE html>
<html lang=«es»> <!– El código del documento HTML está escrito en español –>
<head>
</head>
<body onload=«funcion();»>
</body>
</html>
|
La primera línea sirve para indicar al navegador web que el documento que está leyendo está escrito en HTML, concretamente en la versión 5 (conocida como HTML5). Las versiones anteriores de HTML, basadas en SGML (Standard Generalized Markup Language), incluían una definición de tipo de documento (DTD) en la que se declaraba el tipo de reglas usadas en el lenguaje para describir el documento.
La segunda y la última línea encierran el código HTML entre las directivas <html>
y </html>
que funcionan como apertura y cierre respectivamente. Las directivas HTML encierran el nombre y los atributos entre los signos «menor que» y «mayor que» formando una especie de signos de «paréntesis agudos». Los elementos HTML que encierran contenido tienen una directiva de cierre que incluye la barra delante del nombre como en </html>
.
Las propiedades o atributos de los elementos se separan con espacios del nombre y entre sí y se expresan como un texto sin más o, más frecuentemente, como un texto (el nombre de la propiedad) seguido de un signo igual y entre comillas un valor. En el caso de la directiva de apertura del código HTML se ha usado la propiedad lang
con el valor es
, lang="es"
para indicar que el texto del documento HTML utiliza el idioma español.
Después de la directiva de apertura del código HTML se ha incluido un comentario. Los comentarios en HTML pueden ocupar varias líneas y utilizan como signo de apertura el código <!--
y como cierre -->
El código HTML está formado por dos bloques: la cabecera <head>
y el cuerpo <body>
. La primera tiene como objetivo informar sobre el propio documento incluyendo información del mismo (metainformación) y el segundo es el soporte del contenido del documento.
En la directiva <body>
se ha incluido un evento onload
con el que ejecutar automáticamente una función JavaScript una vez que se haya cargado el contenido. Este recurso permite iniciar la ejecución del código que definirá los objetos gráficos y los irá actualizando conforme se vaya cargando información del servidor sobre el estado de los sensores que representan estos gráficos.
De toda la metainformación que puede incluirse dentro de la cabecera del documento HTML, nos interesa especialmente conocer la descrita por las siguientes directivas:
-
<title>
que sirve para darle un título al documento. Normalmente aparecerá en la ventana del navegador o en la solapa correspondiente y nos ayudará a identificar los gráficos que contiene. -
<charset>
declara el juego de caracteres utilizado para codificar el documento. Es especialmente importante para los signos «especiales» como eñes o tildes. -
<link>
permite establecer una relación entre el documento HTML actual y otros externos. Nos servirá para cargar la hoja de estilos en formato CSS con el aspecto del documento. -
<script>
contiene un guión (script) con código ejecutable. Usando esta directiva cargaremos las funciones JavaScript con las que generar o modificar los gráficos SVG.
1
2
3
4
5
6
7
8
9
10
11
|
<!DOCTYPE html>
<html lang=«es»> <!– El código del documento HTML está escrito en español… –>
<head>
<meta charset=«utf-8»> <!– …y codificado en el juego de caracteres UTF-8 –>
<title>Gáfico SVG de sensores conectados a la IoT</title>
<link href=«https://polaridad.es/grafica-sensor-internet-de-las-cosas-iot/aspecto.css» type=«text/css» rel=«stylesheet» media=«all»>
<script src=«graficos.js» type=«text/javascript»></script>
</head>
<body onload=«funcion();»>
</body>
</html>
|
Como puede verse en el ejemplo del HTML anterior, el nombre (y la ruta, si procede) del documento con el estilo CSS se indica con el atributo href
, mientras que en el caso del código JavaScript se usa src
. Ambos comparten la propiedad type
con el valor text/css
y text/javascript
respectivamente.
Con respecto al contenido del documento, la parte que corresponde al elemento <body>
, HTML5 permite crear estructuras específicas para los componentes más frecuentes en una página web como un pie, un apartado lateral o una barra de navegación pero lo que nos interesa para usar el documento como contenedor de gráficos SVG son los elementos <div>
que funcionan como bloques independientes que permiten definir una estructura jerárquica anidando unos <div>
dentro de otros.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<!DOCTYPE html>
<html lang=«es»> <!– El código del documento HTML está escrito en español… –>
<head>
<meta charset=«utf-8»> <!– …y codificado en el juego de caracteres UTF-8 –>
<title>Gáfico SVG de sensores conectados a la IoT</title>
<link href=«https://polaridad.es/grafica-sensor-internet-de-las-cosas-iot/aspecto.css» type=«text/css» rel=«stylesheet» media=«all»>
<script src=«graficos.js» type=«text/javascript»></script>
</head>
<body onload=«funcion();»>
<div id=«padre» class=«aspecto_de_padre»>
<div id=«primer_hijo» class=«aspecto_de_hijo»>
</div>
<div id=«segundo_hijo» class=«aspecto_de_hijo»>
</div>
</div>
</body>
</html>
|
En el ejemplo anterior se usa un elemento <div>
que contiene otros dos. Este ejemplo introduce dos propiedades muy importantes para el uso que queremos hacer del código HTML: id
que se utiliza para asignar un identificador único a un elemento HTML (un <div>
, en este caso) y class
con el que se le asigna una categoría que usaremos para establecer el aspecto. La categoría, la clase, no tiene por qué ser única, de hecho, gran parte de su eficacia reside en que varios elementos compartan el mismo aspecto.
El elemento (o etiqueta) <p>
sirve para definir un párrafo que normalmente contendrá texto (aunque en HTML no hay limitación al respecto). Para hacer agrupaciones dentro de un párrafo (o de un <div>
, igualmente no hay limitaciones) se utiliza la etiqueta <span>
. Con este elemento es posible, por ejemlo, incluir un texto dentro de un párrafo para darle un aspecto diferente como subrayado o negrita.
La definición de las características gráficas y en general, el comportamiento que se asocia a un elemento HTML al atribuirle una clase se realiza en el código CSS; en el caso del ejemplo anterior en el documento aspecto.css
.
Para optimizar la asignación de las características CSS es posible que un mismo elemento HTML pertenezca a varias clases y de esta forma tenga el aspecto o el comportamiento definido por ellas. Para hacer esa asignación se escriben los nombres de las diferentes clases separándolos por comas a la derecha de la propiedad class
9
10
11
12
13
14
15
16
|
<body onload=«funcion();»>
<div id=«padre» class=«aspecto_de_padre»>
<div id=«primer_hijo» class=«aspecto_de_hijo aspecto_raro tipografia_grande»>
</div>
<div id=«segundo_hijo» class=«aspecto_de_hijo»>
</div>
</div>
</body>
|
En el ejemplo anterior, al elemento <div>
que se ha identificado como primer_hijo
se le han asignado tres clases: aspecto_de_hijo
, aspecto_raro
y tipografia_grande
, que se supone que definen en conjunto el aspecto y el comportamiento del elemento. Como se explica en el siguiente artículo sobre la definición con CSS del aspecto de la web de gráficos de sensores en la IoT, cuando se usan varias clases, si alguna de las propiedades que define el aspecto se encuentra definida en ambas, prevalece la última a la que se haga referencia.
Como se ha visto, los elementos <div>
pueden contener otros elementos, incluyendo también otros <div>
. Un caso más simple sería un <div>
que contuviera texto. El aspecto que define el estilo CSS afectaría también al texto contenido en el elemento.
Para optimizar la asignación de las características CSS es posible que un mismo elemento HTML pertenezca a varias clases y de esta forma tenga el aspecto o el comportamiento definido por ellas. Para hacer esa asignación se escriben los nombres de las diferentes clases separándolos por comas a la derecha de la propiedad class
9
10
11
12
13
14
15
16
17
|
<body onload=«funcion();»>
<div id=«padre» class=«aspecto_de_padre»>
<div id=«primer_hijo» class=«aspecto_de_hijo aspecto_raro tipografia_grande»>
Este hijo de aspecto raro tiene la tipografía grande
</div>
<div id=«segundo_hijo» class=«aspecto_de_hijo»>
</div>
</div>
</body>
|
En el ejemplo anterior, las tres clases asociadas al <div>
primer_hijo
definirían el aspecto del elemento y del texto que lo contiene, por ejemplo, haciendo que la tipografía con que se escribe sea grande (de ser cierta la finalidad que apunta por su nombre la última clase)
Desde la versión 5 (HTML5) es posible incluir el código de los gráficos en formato SVG dentro del propio código HTML como un elemento más. Desde el punto de vista del código HTML, el contenido SVG es un elemento <svg>
que contiene los diferentes elementos gráficos (líneas, círculos, rectángulos…
9
10
11
12
13
14
15
16
17
18
19
20
|
<body onload=«funcion();»>
<div id=«padre» class=«aspecto_de_padre»>
<div id=«primer_hijo» class=«aspecto_de_hijo aspecto_raro tipografia_grande»>
Este hijo de aspecto raro tiene la tipografía grande
</div>
<div id=«segundo_hijo» class=«aspecto_de_hijo»>
<svg id=«dibujo» class=«grafico» width=«100%» height=«100%» viewBox=«0 0 100 100» preserveAspectRatio=«none»>
<circle cx=«100» cy=«200» r=«50»>
</svg>
</div>
</div>
</body>
|
Aunque se ha dicho que las características gráficas de los elementos HTML se definien en un estilo CSS y se le asocian por medio de una clase, también es posible asignar algunas de ellas directamente en los elementos de dos formas. Por una parte se puede utilizar la propiedad style
y asignar como valor de la misma las diferentes características gráficas del objeto. Lógicamente es preferible usar la técnica citada de la asignación del aspecto a una clase pero con esta posibilidad se puede añadir una pequeña corrección a un elemento (una excepción muy particular) sin tener que crear una nueva clase.
Por otro lado, algunos elementos HTML permiten usar propiedades específicas que definen su aspecto. En general, aunque existan esas propiedades, es preferible usar clases pero, desafortunadamente, no todos los elementos ofrecen esta alternativa, algunos esperan que determinado valor se indique directamente con esas propiedades específicas en lugar de atender a la clase asociada. Uno de los elementos que tienen este tipo de comportamiento es precisamente el código SVG, al que debemos asignar el valor porcentual del ancho y del alto en las propiedades width
y height
, respectivamente, en lugar de la clase.
Como se verá con más detalle en el artículo en el que se habla del código SVG, para poder utilizar el sencillo método que se propone, es recomendable considerar las dimensiones del gráfico como tantos por ciento. En el caso del tamaño total del objeto, al indicar 100% en el valor de ancho y alto, será el contenedor el que fije las dimensiones finales (el <div>
con id="dibujo"
, en el ejemplo anterior)
En el caso de los diferentes componentes del gráfico SVG (líneas, círculos, rectángulos…), se incluyen en una zona que mide 100×100 (cualquier unidad) y se expanden de forma rectangular sin conservar la proporción. Las propiedades viewBox
y preserveAspectRatio
del elemento SVG se encargan de establecer estos valores. en el primer caso con una vista rectangular que va desde el punto de coordenadas (0,0) hasta el punto de coordenadas (100,100) y que se expresa como "0 0 100 100"
y en el segundo con el valor none
.
14
15
16
17
18
|
<div id=«segundo_hijo» class=«aspecto_de_hijo»>
<svg viewBox=«0 0 100 100» preserveAspectRatio=«none» width=«100%» height=«100%» id=«dibujo» class=«grafico»>
<circle cx=«100» cy=«200» r=«50»>
</svg>
</div>
|
Con todo lo anterior ya se puede definir un código completo que serviría como contenedor de gráficos SVG generados o modificados desde JavaScript. El ejemplo de abajo contiene cuatro bloques de gráficos que usan el formato HTML de la propuesta de representación que vamos a usar.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
<!DOCTYPE html>
<html lang=«es»> <!– Inicio del documento HTML con el idioma –>
<head> <!– Cabecera del documento HTML –>
<meta charset=«utf-8»> <!– Se utiliza el juego de caracteres UTF8 –>
<title>Temperaturas Nave E1</title> <!– Título del documento y seguramente de la ventana del navegador –>
<link rel=«stylesheet» href=«https://polaridad.es/grafica-sensor-internet-de-las-cosas-iot/estilo.css» type=«text/css» media=«all»> <!– Cargar el estilo «https://polaridad.es/grafica-sensor-internet-de-las-cosas-iot/estilo.css» guardado en la misma carpeta que este documento HTML –>
<script type=«text/javascript» src=«graficos.js»></script> <!– Cargar el código JavaScript del documento «graficos.js» guardado en la misma carpeta que este documento HTML –>
</head> <!– Final de la cabecera del documento HTML –>
<body onload=«iniciar_graficos();»> <!– Cuerpo del documento HTML. Al cargar el contenido llama a la función JavaScript iniciar_graficos() –>
<div id=«temperatura_frigorifico_a» class=«bloque_sensor»> <!– Bloque de datos del primer sensor –>
<div id=«titulo_temperatura_frigorifico_a» class=«bloque_titulo»>Temperatura frigorífico 01A</div> <!– Título del bloque de datos del sensor –>
<div id=«descripcion_temperatura_frigorifico_a» class=«bloque_descripcion»>Media de las sondas de temperatura del frigorífico 01A</div> <!– Descripción del bloque de datos del sensor –>
<div id=«fecha_temperatura_frigorifico_a» class=«bloque_fecha»>Cargando emperaturas</div> <!– Fecha de la última lectura de datos del sensor. Por ahora vacío, luego se rellenará con la aplicación JavaScript –>
<div id=«bloque_temperatura_frigorifico_a» class=«bloque_grafico»> <!– Bloque con el gráfico –>
<svg id=«grafico_temperatura_frigorifico_a» class=«grafico» width=«100%» height=«100%» viewBox=«0 0 100 100» preserveAspectRatio=«none»>
<path id=«linea_temperatura_frigorifico_a» d=«» style=«fill:none;stroke:#205587;stroke-width:4;stroke-opacity:1;» vector-effect=«non-scaling-stroke» />
</svg> <!– Gráfico de los datos –>
</div> <!– Final del bloque que contiene el gráfico –>
</div> <!– Final del bloque de datos del primer sensor –>
<div id=«temperatura_frigorifico_b» class=«bloque_sensor»>
<div id=«titulo_temperatura_frigorifico_b» class=«bloque_titulo»>Temperatura frigorífico 01B</div>
<div id=«descripcion_temperatura_frigorifico_b» class=«bloque_descripcion»>Media de las sondas de temperatura del frigorífico 01B</div>
<div id=«fecha_temperatura_frigorifico_b» class=«bloque_fecha»>Cargando emperaturas</div>
<div id=«bloque_grafico_temperatura_frigorifico_b» class=«bloque_grafico»>
<svg id=«grafico_temperatura_frigorifico_b» class=«grafico» width=«100%» height=«100%» viewBox=«0 0 100 100» preserveAspectRatio=«none»>
<path id=«linea_temperatura_frigorifico_b» d=«» style=«fill:none;stroke:#205587;stroke-width:4;stroke-opacity:1;» vector-effect=«non-scaling-stroke» />
</svg>
</div>
</div>
<div id=«temperatura_frigorifico_c» class=«bloque_sensor»>
<div id=«titulo_temperatura_frigorifico_c» class=«bloque_titulo»>Temperatura frigorífico 01C</div>
<div id=«descripcion_temperatura_frigorifico_c» class=«bloque_descripcion»>Media de las sondas de temperatura del frigorífico 01C</div>
<div id=«fecha_temperatura_frigorifico_c» class=«bloque_fecha»>Cargando emperaturas</div>
<div id=«bloque_grafico_frigorifico_c» class=«bloque_grafico»>
<svg id=«grafico_temperatura_frigorifico_c» class=«grafico» width=«100%» height=«100%» viewBox=«0 0 100 100» preserveAspectRatio=«none»>
<path id=«linea_temperatura_frigorifico_c» d=«» style=«fill:none;stroke:#205587;stroke-width:4;stroke-opacity:1;» vector-effect=«non-scaling-stroke» />
</svg>
</div>
</div>
<div id=«temperatura_frigorifico_d» class=«bloque_sensor»>
<div id=«titulo_temperatura_frigorifico_d» class=«bloque_titulo»>Temperatura frigorífico 01D</div>
<div id=«descripcion_temperatura_frigorifico_d» class=«bloque_descripcion»>Media de las sondas de temperatura del frigorífico 01D</div>
<div id=«fecha_temperatura_frigorifico_d» class=«bloque_fecha»>Cargando emperaturas</div>
<div id=«bloque_grafico_frigorifico_d» class=«bloque_grafico»>
<svg id=«grafico_temperatura_frigorifico_d» class=«grafico» width=«100%» height=«100%» viewBox=«0 0 100 100» preserveAspectRatio=«none»>
<path id=«linea_temperatura_frigorifico_d» d=«» style=«fill:none;stroke:#205587;stroke-width:4;stroke-opacity:1;» vector-effect=«non-scaling-stroke» />
</svg>
</div>
</div>
</body> <!– Final del cuerpo del documento HTML –>
</html> <!– Final del documento HTML –>
|
Abajo puede verse el aspecto que tendría el código anterior, formateado con el estilo CSS correspondiente, generando con JavaScript los gráficos SVG con las lecturas del servidor de los datos almacenados por los sensores conectados a la IoT. Salvo que los datos no se están cargando del servidor sino que se están generando aleatoriamente en el cliente (tu navegador) el resto del código es el que se utilizará en la propuesta que se define en esta serie de artículos.
En el siguiente artículo de esta serie se explica cómo definir los estilos CSS para dar aspecto al código HTML que hace de contenedor a los gráficos SVG con los que representar el estado de los sensores conectados a la Internet de las cosas (IoT).
Publicar comentario