Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

De los datos al gráfico:un viaje web con Flask y SQLite

Capturar datos reales (RPi / DHT22), guardarlos en una base de datos (SQLite), crear gráficos (Matplotlib) y presentarlos en una página web (Flask).

Introducción:De los datos al gráfico. un Web Jorney con Flask y SQLite

En mi tutorial anterior, Python WebServer With Flask y Raspberry Pi, aprendimos cómo interactuar con el mundo físico, a través de una página web, construida con Flask. Por lo tanto, el siguiente paso natural es recopilar datos del mundo real y tenerlos disponibles en una página web. ¡Muy simple! Pero, ¿qué pasará si queremos saber cuál fue la situación el día anterior, por ejemplo? ¿O hacer algún tipo de análisis con esos datos? En esos casos, también debemos tener los datos almacenados en una base de datos.

En resumen, en este nuevo tutorial:

Capture datos reales (temperatura del aire y humedad relativa) con un sensor DHT22; cargue esos datos en una base de datos local , construido con SQLite; Crea gráficos con datos históricos usando Matplotlib; Mostrar datos con "indicadores" animados, creados con JustGage; Haga que todo esté disponible en línea a través de un servidor web local creado con Python y Frasco;

El diagrama de bloques nos da una idea de todo el proyecto:

Paso 1:BoM - Lista de materiales

Paso 2:Instalar SQLite

De acuerdo, la idea general será recopilar datos de un sensor y almacenarlos en una base de datos.

Pero, ¿qué "motor" de base de datos debería utilizarse?

Hay muchas opciones en el mercado y probablemente las 2 más utilizadas con Raspberry Pi y sensores son MySQL y SQLite. MySQL es muy conocido pero un poco "pesado" para su uso en proyectos simples basados ​​en Raspberry (¡además de que es propiedad de Oracle!). SQLite es probablemente la opción más adecuada. Porque no tiene servidor, es liviano, de código abierto y es compatible con la mayoría de los códigos SQL (su licencia es de “dominio público”). Otra cosa útil es que SQLite almacena datos en un solo archivo que se puede almacenar en cualquier lugar.

Pero, ¿qué es SQLite?

SQLite es un sistema de administración de bases de datos relacionales contenido en una biblioteca de programación C. A diferencia de muchos otros sistemas de administración de bases de datos, SQLite no es un motor de base de datos cliente-servidor. Más bien, está integrado en el programa final.

SQLite es un dominio público popular elección como software de base de datos integrado para almacenamiento local / cliente en software de aplicación como navegadores web. Podría decirse que es el motor de base de datos más ampliamente implementado, ya que lo utilizan hoy en día varios navegadores, sistemas operativos y sistemas integrados (como teléfonos móviles) generalizados, entre otros. SQLite tiene enlaces a muchos lenguajes de programación como Python, el que se usa en nuestro proyecto.

(Más en Wikipedia)

No entraremos en demasiados detalles aquí, pero la documentación completa de SQLite se puede encontrar en este enlace:https://www.sqlite.org/docs.html

¡Que así sea! Instalemos SQLite en nuestro Pi

Instalación:

Siga los pasos a continuación para crear una base de datos.

1. Instale SQLite en Raspberry Pi usando el comando:

  sudo apt-get install sqlite3  

2. Cree un directorio para desarrollar el proyecto:

  mkdir Sensors_Database  

3. Mover a este directorio:

  cd mkdir Sensors_Database /  

3. Dé un nombre y cree una base de datos como databaseName.db (en mi caso, "sensorData.db"):

  sqlite3 sensorsData.db  

Aparecerá un "shell", donde puede ingresar con comandos SQLite. Volveremos a ello más tarde.

  sqlite>  

Los comandos comienzan con un ".", Como ".help", ".quit", etc.

4. Salga del shell para volver a la Terminal:

  sqlite> .quit  

La pantalla de impresión de Terminal anterior muestra lo que se explicó.

El "sqlite>" anterior es solo para ilustrar cómo aparecerá el shell SQLite. No es necesario que lo escriba. Aparecerá automáticamente.

Paso 3:Cree y complete una tabla

Para registrar los datos medidos del sensor DHT en la base de datos, debemos crear una tabla (una base de datos puede contener varias tablas). Nuestra tabla se llamará "DHT_data" y tendrá 3 columnas, donde registraremos nuestros datos recopilados:Fecha y Hora (nombre de la columna: marca de tiempo ), Temperatura (nombre de la columna: temp ) y Humedad (nombre de la columna: hum ).

Crear una tabla:

Para crear una tabla, puede hacerlo:

1. Usando Shell:

Abra la base de datos que se creó en el último paso:

  sqlite3 sensorsData.db  

Y entrando con sentencias SQL:

  sqlite> BEGIN; sqlite> CREAR TABLA DHT_data (marca de tiempo DATETIME, temp NUMERIC, hum NUMERIC); sqlite> COMMIT;  

Todas las sentencias SQL deben terminar con ";". Además, por lo general, esas declaraciones se escriben con letras mayúsculas. No es obligatorio, pero es una buena práctica.

2. Usando Python

  importar sqlite3 como liteimport syscon =lite.connect ('sensorsData.db') con con:cur =con.cursor () cur.execute ("DROP TABLE IF EXISTS DHT_data ") cur.execute (" CREAR TABLA DHT_data (marca de tiempo DATETIME, temp NUMERIC, hum NUMERIC) ")  

Abra el código anterior de mi GitHub:createTableDHT.py

Ejecútelo en su Terminal:

  python3 createTableDHT.py  

Dondequiera que se utilice el método, se debe crear la tabla. Puede verificarlo en SQLite Shell usando el comando ".table". Abra el shell de la base de datos:

  sqlite3> sensorData.db  

En el shell, una vez que use .table comando, los nombres de las tablas creadas aparecerán (en nuestro caso será solo uno:"DHT_table". Salga del shell después, usando el .quit comando.

  sqlite> .tableDHT_datasqlite> .quit  

Insertar datos en una tabla:

Ingresemos en nuestra base de datos 3 conjuntos de datos, donde cada conjunto tendrá 3 componentes cada uno:(marca de tiempo, temperatura y zumbido). El componente marca de tiempo será real y se tomará del sistema, utilizando la función incorporada "ahora" y temp y tararear son datos ficticios en oC y% respectivamente.

Nota que la hora está en "UTC", lo que es bueno porque no tiene que preocuparse por problemas relacionados con el horario de verano y otros asuntos. Si desea generar la fecha en la hora localizada, simplemente conviértala a la zona horaria adecuada después.

De la misma manera que se hizo con la creación de tablas, puede insertar datos manualmente a través de SQLite shell o mediante Python. En el shell, lo haría, datos por datos usando declaraciones SQL como esta (para nuestro ejemplo, lo hará 3 veces):

  sqlite> INSERT INTO DHT_data VALUES (datetime ('now'), 20.5, 30);  

Y en Python, harías lo mismo pero de una vez:

  importar sqlite3 como liteimport syscon =lite.connect ('sensnsData.db') con con:cur =con.cursor () cur.execute ("INSERT INTO DHT_data VALUES (datetime ('ahora'), 20.5, 30) ") cur.execute (" INSERT INTO DHT_data VALUES (datetime ('now'), 25.8, 40) ") cur.execute (" INSERT INTO DHT_data VALUES (datetime (') ahora '), 30.3, 50) ")  

Abra el código anterior desde mi GitHub:insertTableDHT.py

Ejecútelo en la terminal Pi:

  python3 insertTableDHT.py  

Para confirmar que el código anterior funcionó, puede verificar los datos en la tabla a través del shell, con la declaración SQL:

  sqlite> SELECCIONAR * FROM DHT_DATA;  

La pantalla de impresión de Terminal anterior muestra cómo aparecerán las filas de la tabla.

Paso 4:Insertar y verificar datos con Python

Para comenzar, hagamos lo mismo que hicimos antes (ingresar y recuperar datos), pero haciendo ambas cosas con Python y también imprimiendo los datos en la terminal:

  import sqlite3import sysconn =sqlite3.connect ('sensnsData.db') curs =conn.cursor () # función para insertar datos en una tabledef add_data (temp, hum) :curs.execute ("INSERT INTO DHT_data values ​​(datetime ('now'), (?), (?))", (temp, hum)) conn.commit () # llame a la función para insertar dataadd_data (20.5, 30 ) add_data (25.8, 40) add_data (30.3, 50) # print database contentprint ("\ nContenido completo de la base de datos:\ n") para la fila en curs.execute ("SELECT * FROM DHT_data"):print (fila) # cierra el base de datos después de useconn.close ()  

Abra el código anterior de mi GitHub:insertDataTableDHT.py y ejecútelo en su Terminal:

  python3 insertDataTableDHT.py  

La pantalla de impresión de Terminal anterior muestra el resultado.

Paso 5:Sensor de temperatura y humedad DHT22

Hasta ahora hemos creado una tabla en nuestra base de datos, donde guardaremos todos los datos que leerá un sensor. También hemos ingresado allí con algunos datos ficticios. Ahora es el momento de utilizar datos reales que se guardarán en nuestra tabla, temperatura del aire y humedad relativa. Para eso, usaremos el antiguo y bueno DHTxx (DHT11 o DHT22). El sitio de ADAFRUIT proporciona gran información sobre esos sensores. A continuación, información recuperada de allí:

Descripción general

Los sensores de temperatura y humedad DHT de bajo costo son muy básicos y lentos, pero son excelentes para los aficionados que desean realizar un registro de datos básico. Los sensores DHT están hechos de dos partes, un sensor de humedad capacitivo y un termistor. También hay un chip muy básico en el interior que realiza una conversión analógica a digital y escupe una señal digital con la temperatura y la humedad. La señal digital es bastante fácil de leer con cualquier microcontrolador.

DHT11 frente a DHT22

Tenemos dos versiones del sensor DHT, se ven un poco similares y tienen el mismo pinout, pero tienen características diferentes. Aquí están las especificaciones:

DHT11 (generalmente azul)

Bueno para lecturas de humedad del 20 al 80% con una precisión del 5% Bueno para lecturas de temperatura de 0 a 50 ° C Exactitud de ± 2 ° C Frecuencia de muestreo de no más de 1 Hz (una vez por segundo)

DHT22 (generalmente blanco)

Bueno para lecturas de humedad de 0-100% con precisión de 2-5% Bueno para lecturas de temperatura de -40 a 125 ° C Precisión de ± 0.5 ° C Frecuencia de muestreo de no más de 0.5 Hz (una vez cada 2 segundos)

Como puede ver, el DHT22 es un poco más preciso y bueno en un rango ligeramente mayor. Ambos usan un solo pin digital y son "lentos" en el sentido de que no puede consultarlos más de una vez por segundo (DHT11) o dos (DHT22).

Ambos sensores funcionarán bien para que la información interior se almacene en nuestra base de datos.

El DHTxx tiene 4 pines (mirando hacia el sensor, el pin 1 es el más a la izquierda):

Usaremos un DHT22 en nuestro proyecto.

Una vez que, por lo general, usará el sensor en distancias inferiores a 20 m, se debe conectar una resistencia de 4K7 ohmios entre los pines Data y VCC. El pin de datos de salida DHT22 se conectará a Raspberry GPIO 16.

Consulte el diagrama eléctrico anterior que conecta el sensor a los pines RPi como se muestra a continuación:

No olvide instalar la resistencia de 4K7 ohmios entre los pines Vcc y Data. Una vez conectado el sensor, también debemos instalar su librería en nuestro RPi. Haremos esto en el siguiente paso.

Paso 6:Instalación de la biblioteca DHT

En su Raspberry, comenzando en / home, vaya a / Documents:

  Documentos de cd  

Cree un directorio para instalar la biblioteca y muévase allí:

  mkdir DHT22_Sensorcd DHT22_Sensor  

En su navegador, vaya a Adafruit GITHub:https://github.com/adafruit/Adafruit_Python_DHT

Descargue la biblioteca haciendo clic en el enlace zip de descarga a la derecha y descomprima el archivo en su carpeta recientemente creada de Raspberry Pi. Luego vaya al directorio de la biblioteca (subcarpeta que se crea automáticamente cuando descomprimió el archivo) y ejecute el comando:

  sudo python3 setup.py install  

Abra un programa de prueba (DHT22_test.py) desde mi GITHUB:

  import Adafruit_DHTDHT22Sensor =Adafruit_DHT.DHT22DHTpin =16humidity, temperature =Adafruit_DHT.read_retry (DHT22Sensor, DHTpin) si la humedad no es Ninguna y la temperatura no es Ninguna:print ('Temp ={0:0.1f} * C Humedad ={1:0.1f}% '. Formato (temperatura, humedad)) else:print (' No se pudo obtener la lectura. Vuelve a intentarlo ')  

Ejecute el programa con el comando:

  python3 DHT22_test.py  

La pantalla de impresión de Terminal anterior muestra el resultado.

Paso 7:captura de datos reales

Ahora que tenemos tanto el sensor como nuestra base de datos instalados y configurados, es hora de leer y guardar datos reales.

Para eso, usaremos el código:

  import timeimport sqlite3import Adafruit_DHTdbname ='sensoresData.db'sampleFreq =2 # tiempo en segundos # obtener datos de DHT sensordef getDHTdata ():DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 hum, temp =Adafruit_DHT.read_retry (DHT22Sensor, DHTpin) si el zumbido no es Ninguno y la temperatura no es Ninguno:hum =round (hum) temp =round (temp, 1) logData (temp, hum) # registrar datos del sensor en la base de datos def logData (temp, hum):conn =sqlite3.connect (dbname) curs =conn.cursor () curs.execute ("INSERT INTO DHT_data values ​​(datetime ('now'), (?), (?))", (temp , hum)) conn.commit () conn.close () # display database datadef displayData ():conn =sqlite3.connect (dbname) curs =conn.cursor () print ("\ nContenido completo de la base de datos:\ n") para fila en curs.execute ("SELECT * FROM DHT_data"):print (fila) conn.close () # main functiondef main ():for i in range (0,3):getDHTdata () time.sleep (sampleFreq) displayData () # Ejecutar programa main ()  

Abra el archivo anterior desde mi GitHub:appDHT.py y ejecútelo en su Terminal:

  python3 appDHT.py  

La función getDHTdata () captura 3 muestras del sensor DHT, prueba si hay errores y, si está bien, guarda los datos en la base de datos usando la función logData (temp, hum) . La parte final del código llama a la función displayData () que imprime todo el contenido de nuestra tabla en la Terminal.

La pantalla de impresión anterior muestra el resultado. Observe que las últimas 3 líneas (filas) son los datos reales capturados con este programa y las 3 filas anteriores fueron las que se ingresaron manualmente antes.

De hecho, appDHT.py no es un buen nombre. En general, "appSomething.py" se usa con scripts de Python en servidores web, como veremos más adelante en este tutorial. Pero, por supuesto, puede usarlo aquí.

Paso 8:capturando datos automáticamente

En este punto, lo que debemos implementar es un mecanismo para leer e insertar datos en nuestra base de datos automáticamente, nuestro “Logger”.

Abrir una nueva ventana de Terminal e ingrese con el código Python a continuación:

  import timeimport sqlite3import Adafruit_DHTdbname ='sensoresData.db'sampleFreq =1 * 60 # tiempo en segundos ==> Muestra cada 1 min # obtiene datos de DHT sensordef getDHTdata () :DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 hum, temp =Adafruit_DHT.read_retry (DHT22Sensor, DHTpin) si el zumbido no es Ninguno y la temperatura no es Ninguno:zumbido =redondo (zumbido) temp =redondo (temp, 1) temperatura de retorno, zumbido # registrar datos del sensor en databasedef logData (temp, hum):conn =sqlite3.connect (dbname) curs =conn.cursor () curs.execute ("INSERT INTO DHT_data values ​​(datetime ('now'), (?), ( ?)) ", (temp, hum)) conn.commit () conn.close () # main functiondef main ():while True:temp, hum =getDHTdata () logData (temp, hum) time.sleep (sampleFreq) # ------------ Ejecutar el programa main ()  

O obténgalo de mi GitHub:logDHT.py. Ejecútelo en la Terminal:

  python3 logDHT.py  

Lo que hace la función main () es:

Llame a la función getDHTdata () , que devolverá los datos capturados por el sensor DHT22. Tome esos datos (temperatura y humedad) y páselos a otra función: logData (temp, hum) que los insertan, junto con la fecha y hora reales, en nuestra mesa y se van a dormir, esperando hasta la próxima hora programada para capturar datos (definida por sampleFreq , que en este ejemplo es 1 minuto).

Deje abierta la ventana de Terminal.

Hasta que elimine el programa con [Ctr + z], por ejemplo, el programa capturará datos continuamente, alimentándolos en nuestra base de datos. Lo dejé funcionando durante un tiempo con una frecuencia de 1 minuto para completar la base de datos más rápido, cambiando la frecuencia después de unas horas a 10 minutos.

Hay otros mecanismos mucho más eficientes para realizar este tipo de "registrador automático" que usar "time.sleep", pero el código anterior funcionará bien para nuestro propósito aquí. De todos modos, si desea implementar un mejor "planificador", puede utilizar Crontab , que es una práctica herramienta de UNIX para programar trabajos. Se puede encontrar una buena explicación de lo que es Crontab en este tutorial:"Programar tareas en Linux usando Crontab", por Kevin van Zonneveld.

Paso 9:consultas

Ahora que nuestra base de datos se alimenta automáticamente, deberíamos encontrar formas de trabajar con todos esos datos. ¡Lo hacemos con consultas!

¿Qué es una consulta?

Una de las características más importantes de trabajar con lenguaje SQL sobre bases de datos es la capacidad de crear "consultas de base de datos". En otras palabras, las consultas extraen datos de una base de datos y les dan formato de forma legible. Una consulta debe estar escrita en lenguaje SQL , que usa un SELECT declaración para seleccionar datos específicos.

De hecho, lo hemos usado de manera "amplia" en el último paso:"SELECT * FROM DHT_data".

Ejemplos:

Creemos algunas consultas sobre los datos de la tabla que ya hemos creado. Para eso, ingrese con el siguiente código:

  importar sqlite3conn =sqlite3.connect ('sensoresData.db') curs =conn.cursor () maxTemp =27.6print ("\ nContenido completo de la base de datos:\ n") para la fila en curs.execute ("SELECT * FROM DHT_data"):print (row) print ("\ nEntradas de la base de datos para un valor de humedad específico:\ n") para la fila en curs.execute ("SELECT * FROM DHT_data WHERE hum ='29' "):print (fila) print (" \ nEntradas de la base de datos donde la temperatura es superior a 30oC:\ n ") para la fila en curs.execute (" SELECT * FROM DHT_data WHERE temp>
 30.0 "):print (row) print ("\ nEntradas de la base de datos donde la temperatura es superior a x:\ n") para la fila en curs.execute ("SELECT * FROM DHT_data WHERE temp>
 (?)", (maxTemp,)):print (row)  

O obténgalo de mi GitHub:queryTableDHT.py y ejecútelo en la Terminal:

  python3 queryTableDHT.py  

Puede ver el resultado en la pantalla de impresión de la Terminal arriba. Estos son ejemplos simples para darle una idea con respecto a las consultas. Tómese un tiempo para comprender las declaraciones SQL en el código anterior.

Si desea saber más sobre el lenguaje SQL, una buena fuente es W3School SQL Tutorial.

Paso 10:Últimos datos ingresados ​​en una tabla:

Una consulta muy importante es la de recuperar los últimos datos ingresados ​​ (o registrado) en una mesa. Podemos hacerlo directamente en el shell SQLite, con el comando:

  sqlite> SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1;  

O ejecutando un código Python simple como se muestra a continuación:

  importar sqlite3conn =sqlite3.connect ('sensoresData.db') curs =conn.cursor () print ("\ nÚltimos datos registrados en la base de datos:\ n") para fila en curs.execute ("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):imprimir (fila)  

Puede ver el resultado en la primera pantalla de impresión de Terminal arriba.

Tenga en cuenta que el resultado aparecerá como una "tupla de valores":("marca de tiempo", temp, hum).

La tupla devolvió el contenido de la última fila de nuestra tabla, que está formada con 3 elementos:

Entonces, podemos trabajar mejor nuestro código, para recuperar datos "limpios" de la tabla, por ejemplo:

  importar sqlite3conn =sqlite3.connect ('sensoresData.db') curs =conn.cursor () print ("\ nÚltimos datos sin procesar registrados en la base de datos:\ n") para la fila en curs.execute ("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):print (str (fila [0]) + "==> Temp =" + str (fila [1]) + "Hum ="+ str (fila [2]))  

Abra el archivo de mi GitHub:lastLogDataTableDHT.py y ejecútelo en la Terminal:

  python3 lastLogDataTableDHT.py  

Puede ver el resultado en la pantalla de impresión de la 2da Terminal arriba.

Paso 11:Una interfaz web para la visualización de datos

En mi último tutorial:Python WebServer con Flask y Raspberry Pi, aprendimos cómo implementar un servidor web (usando Flask) para capturar datos de sensores y mostrar su estado en una página web.

Esto es lo que también queremos lograr aquí. La diferencia está en los datos que se enviarán a nuestro front end, que serán tomados de una base de datos y no directamente de los sensores como hicimos en ese tutorial.

Creación de un entorno de servidor web:

Lo primero que debe hacer es instalar Flask en su Raspberry Pi. Si no lo tiene, vaya a la Terminal e ingrese:

  sudo apt-get install python3-flask  

Lo mejor cuando comienzas un nuevo proyecto es crear una carpeta donde tener tus archivos organizados. Por ejemplo:

Desde casa, vaya a nuestro directorio de trabajo:

  cd Documents / Sensors_Database  

Cree una nueva carpeta, por ejemplo:

  mkdir dhtWebServer  

El comando anterior creará una carpeta llamada "dhtWebServer", donde guardaremos nuestros scripts de Python:

  / home / pi / Documents / Sensor_Database / rpiWebServer  

Ahora, en esta carpeta, creemos 2 subcarpetas: estática para CSS y eventualmente archivos JavaScript y plantillas para archivos HTML . Vaya a su nueva carpeta creada:

  cd dhtWebServer  

Y cree las 2 nuevas subcarpetas:

  mkdir static  

y

  plantillas mkdir  

El "árbol" de directorios final se verá así:

  ├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebSensor ├── templates └── static  

Dejaremos nuestra base de datos creada en el directorio / Sensor_Database, por lo que deberá conectar SQLite con "../sensorsData.db".

¡OK! Con nuestro entorno en su lugar, ensamblemos las piezas y creemos nuestra Aplicación Python WebServer . ¡El diagrama anterior nos da una idea de lo que se debe hacer!

Paso 12:La aplicación Python WebServer

Comenzando desde el último diagrama, creemos un servidor web Python usando Flask. Sugiero Geany como el IDE que se utilizará una vez que pueda trabajar simultáneamente con diferentes tipos de archivos (.py, .html y .css).

El siguiente código es el script de Python que se utilizará en nuestro primer servidor web:

  from flask import Flask, render_template, requestapp =Flask (__ name __) import sqlite3 # Recuperar datos de databasedef getData ():conn =sqlite3.connect ('../ sensorsData .db ') curs =conn.cursor () para la fila en curs.execute ("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):time =str (fila [0]) temp =fila [1] hum =fila [2] conn.close () return time, temp, hum # ruta principal @ app.route ("/") def index ():time, temp, hum =getData () templateData ={'time':time, ' temp ':temp,' hum ':hum} return render_template (' index.html ', ** templateData) if __name__ =="__main__":app.run (host =' 0.0.0.0 ', port =80, debug =Falso)  

Puede obtener el script de Python appDhtWebServer.py desde mi GitHub. Lo que hace el código anterior es:

Con esta solicitud, lo primero que se hace en el código es tomar datos de la base de datos usando la función time, temp, hum =getData (). Esta función es básicamente la misma consulta que se utilizó antes para recuperar datos almacenados en la tabla. Con los datos disponibles, nuestro script vuelve a la página web ( index.html ): hora , temp y tararear como respuesta a la solicitud anterior.

Entonces, veamos el index.html y style.css archivos que se utilizarán para construir nuestro front-end:

index.html

     Datos del sensor DHT     

Datos del sensor DHT

TEMPERATURA ==> {{tempLab}} oC

HUMEDAD (Rel.) ==> { {humLab}}%


Última lectura de sensores:{{time}} ==> ACTUALIZAR


@ 2018 Desarrollado por MJRoBot.org

Puede obtener el archivo index.html de mi GitHub.

style.css

  cuerpo {fondo:azul; color amarillo; relleno:1%}. button {fuente:negrita 15px Arial; decoración de texto:ninguna; color de fondo:#EEEEEE; color:# 333333; relleno:2px 6px 2px 6px; borde superior:1px sólido #CCCCCC; borde derecho:1px sólido # 333333; borde inferior:1px sólido # 333333; borde izquierdo:1px sólido #CCCCCC;}  

Puede obtener el archivo style.css de mi GitHub. Los archivos deben colocarse en su directorio así:

  ├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebSensor ├── appDhtWebSensor.py ├── templates │ ├── index .html └── estático ├── style.css  

Ahora, ejecute el script de Python en la Terminal:

  sudo python3 appDhtWebServer.py  

Vaya a cualquier navegador en su red e ingrese con http:// YOUR_RPI_IP (por ejemplo, en mi caso:http://10.0.1.27)

La pantalla de impresión anterior muestra lo que debe ver. NOTA:Si no está seguro de su dirección IP de RPi, ejecute en su terminal:

  ifconfig  

En la sección wlan0:lo encontrará. En mi caso:10.0.1.27

Paso 13:¡Haga que nuestro Web Front-End sea más elegante!

Presentamos algunos medidores para presentar los valores reales de temperatura y humedad de una mejor manera. Tenga en cuenta que nuestro script de Python no cambiará, pero el uso de JustGage en nuestros archivos html / css mejorará mucho la forma en que se presentarán los datos.

¿Qué es JustGage?

JustGage es un útil complemento de JavaScript para generar y animar indicadores agradables y limpios. Se basa en la biblioteca Raphaël para dibujo vectorial, por lo que es completamente independiente de la resolución y autoajustable, y funciona en casi cualquier navegador.

Instalación:

justgage-1.2.2.zip

      Sensor de datos DHT       

Datos del sensor DHT


Última lectura de sensores:{{time}} ==> ACTUALIZAR


@ 2018 Desarrollado por MJRoBot.org

Descargue de mi GitHub el archivo:index_gage.html y cámbiele el nombre a index.html (no olvide cambiar el nombre del anterior con un nombre diferente si desea conservarlo, por ejemplo, index_txt.html).

El árbol de directorios final debería tener el siguiente aspecto:

  ├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebServer ├── appDhtWebServer.py ├── templates │ ├── index .html └── estático ├── style.css ├── justgage.js ├── raphael-2.1.4.min.js  

Presione [Crl-C] en su Terminal para salir de appDhtWebServer.py y simplemente inícielo de nuevo. Cuando actualice su navegador, debe ver la pantalla de impresión anterior.

Mire los archivos de ejemplo que descargó del sitio web de JustGage. Intente hacer cambios en sus instrumentos. Es muy simple.

Paso 14:El proceso completo

El diagrama anterior resume lo que hemos logrado hasta ahora:2 scripts separados que se ejecutan en paralelo, realizando sus tareas de forma independiente:

Capturar datos con sensor y cargarlos en una base de datos ( logDHT.py ) Busque datos en la base de datos y preséntelos en una interfaz web ( appDhtWebServer.py ).

En términos generales nuestro proyecto de capturar datos, guardarlos en una base de datos y mostrar esos datos en una página web está terminado. Pero no tiene sentido tener una base de datos con datos históricos y usarla solo para los últimos datos capturados. Debemos jugar con datos históricos y lo más básico es presentarlos en un gráfico. ¡Vamos a hacerlo!

Paso 15:Graficando los datos históricos

Una muy buena biblioteca para graficar datos es Matplotlib , that is a Python 2D plotting library which produces publication quality figures in a variety of hardcopy formats and interactive environments across platforms.

To install matplotlib , run the command below on your Terminal:

sudo apt-get install python3-matplotlib 

Before we start, let’s create a new environment, where we will save the new application to be developed: appDhtWebHist.py  and its correspondent index.html  and style.css

├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebHist ├── appDhtWebHist.py ├── templates │ ├── index.html └── static ├── style.css  

Create the new 3 directories (dhtWebHist; /templates  and /static ) same as we did before and open from my GitHub the 3 files below:

1. appDhtWebHist.py

from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfrom matplotlib.figure import Figureimport iofrom flask import Flask, render_template, send_file, make_response, requestapp =Flask(__name__)import sqlite3conn=sqlite3.connect('../sensorsData.db')curs=conn.cursor()# Retrieve LAST data from databasedef getLastData():for row in curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):time =str(row[0]) temp =row[1] hum =row[2] #conn.close() return time, temp, humdef getHistData (numSamples):curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT "+str(numSamples)) data =curs.fetchall() dates =[] temps =[] hums =[] for row in reversed(data):dates.append(row[0]) temps.append(row[1]) hums.append(row[2]) return dates, temps, humsdef maxRowsTable():for row in curs.execute("select COUNT(temp) from DHT_data"):maxNumberRows=row[0] return maxNumberRows# define and initialize global variablesglobal numSamplesnumSamples =maxRowsTable() if (numSamples> 101):numSamples =100# main [email protected]("/")def index():time, temp, hum =getLastData() templateData ={ 'time' :time, 'temp' :temp, 'hum' :hum, 'numSamples' :numSamples } return render_template('index.html', **templateData)@app.route('/', methods=['POST'])def my_form_post():global numSamples numSamples =int (request.form['numSamples']) numMaxSamples =maxRowsTable() if (numSamples> numMaxSamples):numSamples =(numMaxSamples-1) time, temp, hum =getLastData() templateData ={ 'time' :time, 'temp' :temp, 'hum' :hum, 'numSamples' :numSamples } return render_template('index.html', **templateData)@app.route('/plot/temp')def plot_temp():times, temps, hums =getHistData(numSamples) ys =temps fig =Figure() axis =fig.add_subplot(1, 1, 1) axis.set_title("Temperature [°C]") axis.set_xlabel("Samples") axis.grid(True) xs =range(numSamples) axis.plot(xs, ys) canvas =FigureCanvas(fig) output =io.BytesIO() canvas.print_png(output) response =make_response(output.getvalue()) response.mimetype ='image/png' return [email protected]('/plot/hum')def plot_hum():times, temps, hums =getHistData(numSamples) ys =hums fig =Figure() axis =fig.add_subplot(1, 1, 1) axis.set_title("Humidity [%]") axis.set_xlabel("Samples") axis.grid(True) xs =range(numSamples) axis.plot(xs, ys) canvas =FigureCanvas(fig) output =io.BytesIO() canvas.print_png(output) response =make_response(output.getvalue()) response.mimetype ='image/png' return responseif __name__ =="__main__":app.run(host='0.0.0.0', port=80, debug=False) 

A new function was created here: getHistData (numSamples) , that receives as a parameter the number of rows that should be taken from the database. Basically, it is very similar to getLastData(), where numSamples  was “1”. Of course, now we must “append” the return array for all required rows.

In fact, we could use only this last function for both tasks.

The number of samples is set by default as 100, at the beginning (if there are more them 100 rows into the database) and also received it as an input from the webpage, during normal operation. When we receive the number of samples to be retrieved, we must also check if it is lower than the maximum number of rows in the database (otherwise we will get an error). The function maxRowsTable() , returns this number.

With the historical data in hand: times, temps  and hums  that are arrays, we must build the graphs saving them as a .png ímage . Those images will be the return for the routes:

@app.route(‘/plot/temp’)  and @app.route(‘/plot/hum’).

The request for the images is done by index.html, by the IMG TAG.

2. index.html

  DHT Sensor data     

DHT Sensor Data

TEMPERATURE ==> {{ temp }} oC

HUMIDITY (Rel.) ==> {{ hum }} %


Last Sensors Reading:{{ time }} ==> REFRESH


HISTORICAL DATA

Enter number of samples to retrieve:


Image Placeholder Image Placeholder

@2018 Developed by MJRoBot.org

3. style.css

body{ background:blue; color:yellow; padding:1%}.button { font:bold 15px Arial; decoración de texto:ninguna; background-color:#EEEEEE; color:#333333; padding:2px 6px 2px 6px; border-top:1px solid #CCCCCC; border-right:1px solid #333333; border-bottom:1px solid #333333; border-left:1px solid #CCCCCC;}img{ display:display:inline-block} 

The above print screen shows the result.

Step 16:Including Gage on History Webpage

If instead of text, you want also to include gages to display the actual data, you must have the 2 .js files that you have used before on /static and change the index.html file on /templates:

Below how the directory tree looks like:

├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebHist ├── appDhtWebHist.py ├── templates │ ├── index.html └── static ├── style.css ├── justgage.js ├── raphael-2.1.4.min.js 

From my GitHub, open index_gage.html and rename it index.html. Replace the actual index.html (text version) and voilá! You will get a beautiful webpage, showing as gages the last captured data of temperature and humidity by the DHT22 and the historical graphs of those data.

Press[Crl-C] on your Terminal to Quit appDhtWebServer.py and just start it again. When you refresh your browser you must see the above print screen.

Step 17:Retrieving Data by Time Instead of Samples

So far we have build our graphics based on historical data, sending as a input parameter the numbers of samples to be retrieved from our database. Alternatively we could use as a parameter the number of past minutes that we want to show on a graph.

In order to do that, the first thing to know is the frequency of logged data on our database. Remember that this task is done for an independent program (in our case, logDHT.py ). One simple way to finfd this frequency is to retrieve the last 2 data logged on database and subtracting their correspondent timeStamp data:

in general terms: frequency =timeStamp(1) – timeStamp(0)

The function below does the work for us, using “datetime.striptime()”:

# Get sample frequency in minutesdef freqSample():times, temps, hums =getHistData (2) fmt ='%Y-%m-%d %H:%M:%S' tstamp0 =datetime.strptime(times[0], fmt) tstamp1 =datetime.strptime(times[1], fmt) freq =tstamp1-tstamp0 freq =int(round(freq.total_seconds()/60)) return (freq) 

Once we we have this frequency parameter in minutes, we will show it on index.html and asking for a “rangeTime” number of minutes to be send back to our server ==> @app.route(‘/’, methods=[‘POST’]):

@app.route('/', methods=['POST'])def my_form_post():global numSamples global freqSamples global rangeTime rangeTime =int (request.form['rangeTime']) if (rangeTime  numMaxSamples):numSamples =(numMaxSamples-1) 

The picture shows the result:

Eliminating Possible errors when constructing the graphs:

Ocasionally, strange (or corrupted) data can be storaged on database, jeopardizing our analysis. Those data can be verified (or cleaneed) on several places (like during the time sensor are capturing the data, etc). But once the script that display data is independent of the one that logged the data, let’s “cap” the maximum and minimum values of our sensors, before using the data to buit the graphs. This can be achieved with the function testData(temps, hums) :

# Test data for cleanning possible "out of range" valuesdef testeData(temps, hums):n =len(temps) for i in range(0, n-1):if (temps[i] <-10 or temps[i]>50):temps[i] =temps[i-2] if (hums[i] <0 or hums[i]>100):hums[i] =temps[i-2] return temps, hums 

The scripts for this new version can be download from my GitHub: dhtWebHist_v2

Step 18:Conclusion

As always, I hope this project can help others find their way into the exciting world of electronics!

For details and final code, please visit my GitHub depository: RPI-Flask-SQLite

For more projects, please visit my blog: MJRoBot.org

Saludos from the south of the world!

See you at my next tutorial!

Thank you,

Source:From Data to Graph:A Web Journey With Flask and SQLite


Proceso de manufactura

  1. Almacene y administre datos confidenciales con Secret Manager
  2. Microchip:ADC de 24 y 16 bits con velocidades de datos de hasta 153,6 kSPS
  3. Monitor de temperatura y humedad en el hogar (habitación) con gráfico basado en web - Raspberry Pi
  4. Creación de robots con Raspberry Pi y Python
  5. Acelerando la transformación digital con IoT Data, gracias a Cisco e IBM
  6. Aprovechar los datos de IoT desde el borde hasta la nube y viceversa
  7. El viaje de IIoT comienza con la telemetría remota
  8. Cómo hacer que IOT sea real con Tech Data e IBM Part 2
  9. Cómo hacer que IoT sea real con Tech Data e IBM Parte 1
  10. Impulsar los resultados comerciales con proyectos de macrodatos e inteligencia artificial
  11. Resolviendo necesidades en tiempo real a medida que los líderes empresariales avanzan con ML e IA