亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

从数据到图形:使用 Flask 和 SQLite 的网络之旅

捕获真实数据 (RPi/DHT22),将它们保存在数据库 (SQLite) 中,创建图形 (Matplotlib) 并将它们呈现在网页上 (Flask)。

简介:从数据到图形。 Flask 和 SQLite 的网络之旅

在我之前的教程 Python WebServer With Flask 和 Raspberry Pi 中,我们学习了如何通过使用 Flask 构建的 Web 前端页面与物理世界进行交互。因此,下一个自然步骤是从现实世界中收集数据,并在网页上提供给我们。很简单的!但是,例如,如果我们想知道前一天的情况会发生什么?或者对这些数据进行某种分析?在这些情况下,我们必须将数据也存储在数据库中。

简而言之,在这个新教程中,我们将:

捕获真实数据 (空气温度和相对湿度)使用 DHT22 传感器;加载这些数据 在本地数据库上 , 使用 SQLite; 构建 创建图形 使用历史数据 使用 Matplotlib; 显示数据 带有动画“量具”,使用 JustGage; 创建 通过使用Python创建的本地网络服务器使所有内容在线可用 和烧瓶;

框图让我们了解了整个项目:

第 1 步:物料清单 - 物料清单

第 2 步:安装 SQLite

好的,总体思路是从传感器收集数据并将其存储在数据库中。

但是应该使用什么数据库“引擎”?

市场上有很多选择,可能最常用于 Raspberry Pi 和传感器的 2 个是 MySQL 和 SQLite。 MySQL 是众所周知的,但在简单的基于 Raspberry 的项目中使用有点“重”(除了它是 Oracle 自己的!)。 SQLite 可能是最合适的选择。因为它是无服务器的、轻量级的、开源的并且支持大多数 SQL 代码(它的许可证是“公共域”)。另一个方便的事情是 SQLite 将数据存储在可以存储在任何地方的单个文件中。

但是,什么是 SQLite?

SQLite 是一个包含在 C 编程库中的关系数据库管理系统。与许多其他数据库管理系统相比,SQLite 不是客户端-服务器数据库引擎。而是嵌入到最终程序中。

SQLite 是一个流行的公共领域 选择作为嵌入式数据库软件,用于应用程序软件(如 Web 浏览器)中的本地/客户端存储。它可以说是部署最广泛的数据库引擎,因为今天它被几个广泛使用的浏览器、操作系统和嵌入式系统(例如移动电话)等使用。 SQLite 绑定了许多编程语言,例如 Python,我们的项目中使用了这种语言。

(更多关于维基百科)

我们不会在这里介绍太多细节,但可以在此链接中找到完整的 SQLite 文档:https://www.sqlite.org/docs.html

就这样吧!让我们在 Pi 上安装 SQLite

安装:

请按照以下步骤创建数据库。

1. 使用以下命令将 SQLite 安装到树莓派:

sudo apt-get install sqlite3 

2.创建一个目录来开发项目:

mkdir Sensors_Database 

3.移动到这个目录:

cd mkdir Sensors_Database/ 

3. 命名并创建一个像 databaseName.db 这样的数据库 (在我的例子中是“sensorsData.db”):

sqlite3 sensorData.db 

将出现一个“shell”,您可以在其中输入 SQLite 命令。我们稍后会返回。

sqlite> 

命令以“.”开头,例如“.help”、“.quit”等

4.退出shell返回终端:

sqlite> .quit 

上面的终端打印屏幕显示了所解释的内容。

上面的“sqlite>”只是为了说明 SQLite shell 将如何出现。您不需要键入它。它会自动出现。

第 3 步:创建和填充表

为了在数据库中记录 DHT 传感器测量数据,我们必须创建 (一个数据库可以包含多个表)。我们的表将被命名为“DHT_data”并且有 3 列,我们将在其中记录我们收集的数据:日期和时间(列名:时间戳 )、温度(列名:temp ) 和湿度(列名:hum ).

创建表格:

要创建表,您可以这样做:

1.使用外壳:

打开上一步创建的数据库:

sqlite3 sensorData.db 

并用SQL语句输入:

sqlite> BEGIN;sqlite> CREATE TABLE DHT_data (timestamp DATETIME, temp NUMERIC, hum NUMERIC);sqlite> COMMIT; 

所有 SQL 语句都必须以“;”结尾。通常,这些语句使用大写字母书写。这不是强制性的,而是一种很好的做法。

2. 使用Python

import sqlite3 as liteimport syscon =lite.connect('sensorsData.db')with con:cur =con.cursor() cur.execute("DROP TABLE IF EXISTS DHT_data") cur.execute("CREATE TABLE DHT_data(timestamp DATETIME, temp NUMERIC, hum NUMERIC)") 

从我的 GitHub 打开上面的代码:createTableDHT.py

在您的终端上运行它:

python3 createTableDHT.py 

无论使用何种方法,都应创建该表。您可以使用“.table”命令在 SQLite Shell 上验证它。打开数据库外壳:

sqlite3>sensorsData.db 

在 shell 中,一旦您使用 .table 命令,创建的表名称将出现(在我们的例子中只有一个:“DHT_table”。然后退出 shell,使用 .quit 命令。

sqlite> .tableDHT_datasqlite> .quit 

在表格中插入数据:

让我们在我们的数据库中输入 3 组数据,其中每组将有 3 个组件:(时间戳、温度和嗡嗡声)。组件时间戳 将是真实的并从系统中获取,使用内置函数“now”和temp嗡嗡声 分别为 oC 和 % 中的虚拟数据。

注意 时间在“UTC”中,这有什么好处,因为您不必担心与夏令时和其他事项相关的问题。如果您想以本地化时间输出日期,只需将其转换为适当的时区即可。

创建表的方法相同,您可以通过 SQLite shell 或 Python 手动插入数据。在 shell 中,您将使用这样的 SQL 语句逐个数据地执行此操作(对于我们的示例,您将执行 3 次):

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

在 Python 中,您可以立即执行相同的操作:

import sqlite3 as liteimport syscon =lite.connect('sensorsData.db')with con:cur =con.cursor() cur.execute("INSERT INTO DHT_data VALUES (datetime('now'), 20.5, 30)") cur.execute("INSERT INTO DHT_data VALUES(datetime('now'), 25.8, 40)") cur.execute("INSERT INTO DHT_data VALUES(datetime(')现在'), 30.3, 50)") 

从我的 GitHub 打开上面的代码:insertTableDHT.py

在 Pi 终端上运行它:

python3 insertTableDHT.py 

为了确认以上代码是否有效,您可以通过shell检查表中的数据,使用SQL语句:

sqlite> SELECT * FROM DHT_DATA; 

上面的终端打印屏幕显示了表格行的显示方式。

第 4 步:使用 Python 插入和验证数据

首先,让我们做与之前相同的操作(输入和检索数据),但同时使用 python 并在终端上打印数据:

import sqlite3import sysconn=sqlite3.connect('sensorsData.db')curs=conn.cursor()# 在tabledef add_data (temp, hum) 上插入数据的函数:curs.execute("INSERT INTO DHT_data values(datetime('now'), (?), (?))", (temp, hum)) conn.commit()#调用函数插入dataadd_data (20.5, 30 )add_data (25.8, 40)add_data (30.3, 50)# print database contentprint ("\nEntire database contents:\n")for row in curs.execute("SELECT * FROM DHT_data"):print (row)# close the useconn.close() 之后的数据库 

从我的 GitHub 中打开上面的代码:insertDataTableDHT.py 并在您的终端上运行它:

python3 insertDataTableDHT.py 

上面的终端打印屏幕显示了结果。

第 5 步:DHT22 温湿度传感器

到目前为止,我们已经在数据库中创建了一个表,我们将在其中保存传感器将读取的所有数据。我们还在那里输入了一些虚拟数据。现在是时候使用要保存在表格中的真实数据、气温和相对湿度了。为此,我们将使用旧的和好的 DHTxx(DHT11 或 DHT22)。 ADAFRUIT 网站提供了有关这些传感器的重要信息。波纹管,从那里检索到的一些信息:

概览

低成本的 DHT 温度和湿度传感器非常基本且速度较慢,但​​非常适合想要进行一些基本数据记录的爱好者。 DHT 传感器由两部分组成,电容式湿度传感器和热敏电阻。里面还有一个非常基础的芯片,可以做一些模数转换,并输出带有温度和湿度的数字信号。使用任何微控制器都可以很容易地读取数字信号。

DHT11 与 DHT22

我们有两个版本的 DHT 传感器,它们看起来有点相似并且具有相同的引脚排列,但具有不同的特性。以下是规格:

DHT11(通常为蓝色)

适用于 20-80% 湿度读数,精度为 5% 适用于 0-50°C 温度读数 ±2°C 精度不超过 1 Hz 采样率(每秒一次)

DHT22(通常为白色)

适用于 0-100% 湿度读数,精度为 2-5% 适用于 -40 至 125°C 温度读数 ±0.5°C 精度不超过 0.5 Hz 采样率(每 2 秒一次)

如您所见,DHT22 在稍大的范围内更加准确和良好。两者都使用单个数字引脚并且“缓慢”,因为您不能每秒查询超过一次 (DHT11) 或两次 (DHT22)。

两个传感器都能正常工作,将室内信息存储在我们的数据库中。

DHTxx 有 4 个引脚(面向传感器,引脚 1 是最左边的):

我们将在我们的项目中使用 DHT22。

通常您会在小于 20m 的距离上使用传感器,数据和 VCC 引脚之间应连接一个 4K7 欧姆电阻器。 DHT22 输出数据引脚将连接到 Raspberry GPIO 16。

检查以上将传感器连接到 RPi 引脚的电气图,如下所示:

不要忘记在 Vcc 和数据引脚之间安装 4K7 欧姆电阻。连接传感器后,我们还必须在我们的 RPi 上安装它的库。我们将在下一步中执行此操作。

第 6 步:安装 DHT 库

在您的 Raspberry 上,从 /home 开始,转到 /Documents:

cd 文档 

创建一个目录来安装库并移动到那里:

mkdir DHT22_Sensorcd DHT22_Sensor 

在浏览器上,转到 Adafruit GITHub:https://github.com/adafruit/Adafruit_Python_DHT

单击右侧的下载 zip 链接下载库,然后将存档解压缩到您最近创建的 Raspberry Pi 文件夹中。然后进入库所在目录(解压时自动创建的子文件夹),执行命令:

sudo python3 setup.py install 

从我的 GITHUB 打开一个测试程序 (DHT22_test.py):

import Adafruit_DHTDHT22Sensor =Adafruit_DHT.DHT22DHTpin =16 湿度,温度 =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin)如果湿度不是 None 并且温度不是 None:print('Temp={0:0.1f}*C Humidity={1:0.1f}%'.format(温度, 湿度))else:print('读取失败。再试一次!') 

使用以下命令执行程序:

python3 DHT22_test.py 

上面的终端打印屏幕显示了结果。

第 7 步:捕获真实数据

现在我们已经安装并配置了传感器和数据库,是时候读取和保存真实数据了。

为此,我们将使用以下代码:

import timeimport sqlite3import Adafruit_DHTdbname='sensorsData.db'sampleFreq =2 # time in seconds# get data from DHT sensordef getDHTdata():DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 hum, temp =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin) 如果 hum 不是 None 并且 temp 不是 None:hum =round(hum) temp =round(temp, 1) logData (temp, hum)# 在 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()# display database datadef displayData():conn=sqlite3.connect(dbname) curs=conn.cursor() print ("\nEntire database contents:\n") for row in curs.execute("SELECT * FROM DHT_data"):print (row) conn.close()# main functiondef main():for i in range (0,3):getDHTdata() time.sleep(sampleFreq) displayData ()#执行程序main() 

从我的 GitHub 中打开上述文件:appDHT.py 并在您的终端上运行它:

python3 appDHT.py 

函数 getDHTdata() 捕获 3 个 DHT 传感器样本,测试它们是否有错误,如果正常,则使用函数logData (temp, hum) 将数据保存在数据库中 .代码的最后一部分调用函数displayData() 在终端上打印我们表格的全部内容。

上面的打印屏幕显示了结果。观察后3行(行)是本程序捕获的真实数据,前3行是之前手动输入的数据。

事实上 appDHT.py 并不是一个好名字。通常,“appSomething.py”与 Web 服务器上的 Python 脚本一起使用,我们将在本教程中进一步介绍。但当然你可以在这里使用它。

第 8 步:自动捕获数据

此时,我们必须实现的是一种自动在我们的数据库中读取和插入数据的机制,即我们的“记录器”。

打开一个新的终端窗口 并输入以下 Python 代码:

import timeimport sqlite3import Adafruit_DHTdbname='sensorsData.db'sampleFreq =1*60 # time in seconds ==> 每 1 分钟采样一次# 从 DHT sensordef getDHTdata() 获取数据:DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 hum, temp =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin) 如果 hum 不是 None 并且 temp 不是 None:hum =round(hum) temp =round(temp, 1) return temp, hum # 在数据库上记录传感器数据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()# main functiondef main():while True:temp, hum =getDHTdata() logData (temp, hum) time.sleep(sampleFreq) # ------------ 执行程序 main() 

或者从我的 GitHub 获取它:logDHT.py。在终端上运行它:

python3 logDHT.py 

main() 函数的作用是:

调用函数 getDHTdata() ,这将返回 DHT22 传感器捕获的数据。获取这些数据(温度和湿度)并将它们传递给另一个函数:logData(temp, hum) 将它们连同实际日期和时间一起插入到我们的表中。然后进入睡眠状态,等待下一个预定时间来捕获数据(由 sampleFreq 定义) ,在本例中为 1 分钟)。

让终端窗口保持打开状态。

例如,在您使用 [Ctr+z] 终止程序之前,该程序将不断捕获数据,并将它们输入到我们的数据库中。我让它以 1 分钟的频率运行一段时间以更快地填充数据库,几个小时后将频率更改为 10 分钟。

还有其他机制可以比使用“time.sleep”更有效地执行这种“自动记录器”,但上面的代码可以很好地满足我们的目的。无论如何,如果你想实现一个更好的“调度器”,你可以使用 Crontab ,这是一个方便的 UNIX 工具来安排作业。在本教程中可以找到对 Crontab 的一个很好的解释:“使用 Crontab 在 Linux 上安排任务”,作者 Kevin van Zonneveld。

第 9 步:查询

现在我们的数据库是自动输入的,我们应该找到处理所有这些数据的方法。我们通过查询来实现!

什么是查询?

在数据库上使用 SQL 语言的最重要特性之一是能够创建“数据库查询”。换句话说,查询从数据库中提取数据,以可读的形式格式化它们。查询必须用SQL 语言编写 , 使用 SELECT 选择特定数据的语句。

事实上,我们在最后一步“广泛地”使用了它:“SELECT * FROM DHT_data”。

示例:

让我们对我们已经创建的表上的数据创建一些查询。为此,输入以下代码:

import sqlite3conn=sqlite3.connect('sensorsData.db')curs=conn.cursor()maxTemp =27.6print ("\n整个数据库内容:\n") for row in curs.execute("SELECT * FROM DHT_data"):print (row)print ("\nDatabase entries for a特定湿度值:\n")for row in curs.execute("SELECT * FROM DHT_data WHERE hum='29'"):print (row) print ("\nDatabase entry where the temperature is above 30oC:\n")for row in curs.execute("SELECT * FROM DHT_data WHERE temp>
30.0"):print (row) print ("\n温度高于 x 的数据库条目:\n")for row in curs.execute("SELECT * FROM DHT_data WHERE temp>
(?)", (maxTemp,)):print (row)  

或者从我的 GitHub 获取它:queryTableDHT.py,然后在终端上运行它:

python3 queryTableDHT.py 

您可以在上面终端的打印屏幕上看到结果。这些是让您了解查询的简单示例。花点时间了解一下上面代码中的SQL语句。

如果您想了解更多关于 SQL 语言的知识,一个很好的来源是 W3School SQL 教程。

第 10 步:在表中输入的最后数据:

一个非常重要的查询是检索最后输入的数据 (或登录)在一张桌子上。我们可以直接在 SQLite shell 上执行,使用命令:

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

或者运行一个简单的python代码如下:

import sqlite3conn =sqlite3.connect('sensorsData.db')curs=conn.cursor()print ("\n上次登录数据库的数据:\n")for curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1")中的行:打印(行) 

您可以在上面的第一个终端打印屏幕上看到结果。

请注意,结果将显示为“值的元组”:('timestamp', temp, hum).

元组返回我们表格的最后一行内容,它由 3 个元素组成:

所以,我们可以更好地工作我们的代码,从表中检索“干净”的数据,例如:

import sqlite3conn=sqlite3.connect('sensorsData.db')curs=conn.cursor()print ("\n上次登录数据库的原始数据:\n") for row in curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):print (str(row[0])+" ==> Temp ="+str(row[1])+" Hum ="+str(row[2])) 

从我的 GitHub 中打开文件:lastLogDataTableDHT.py 并在终端上运行它:

python3 lastLogDataTableDHT.py 

您可以在上面的第二个终端打印屏幕上看到结果。

第 11 步:用于数据可视化的 Web 前端

在我的上一个教程:Python WebServer 与 Flask 和 Raspberry Pi 中,我们学习了如何实现网络服务器(使用 Flask)来捕获来自传感器的数据并在网页上显示它们的状态。

这也是我们在这里想要完成的。不同之处在于要发送到前端的数据将从数据库中提取 而不是像我们在该教程中所做的那样直接来自传感器。

创建网络服务器环境:

首先要做的是在你的树莓派上安装 Flask。如果没有,请转到终端并输入:

sudo apt-get install python3-flask 

当您开始一个新项目时,最好的办法是创建一个文件夹来组织您的文件。例如:

从家里,转到我们的工作目录:

cd Documents/Sensors_Database 

新建一个文件夹,例如:

mkdir dhtWebServer 

上面的命令将创建一个名为“dhtWebServer”的文件夹,我们将在其中保存我们的python脚本:

/home/pi/Documents/Sensor_Database/rpiWebServer 

现在,在这个文件夹上,让我们创建 2 个子文件夹:static 用于 CSS 并最终用于 JavaScript 文件和模板 用于 HTML 文件 转到新创建的文件夹:

cd dhtWebServer 

并创建 2 个新的子文件夹:

mkdir static 

mkdir 模板 

最终目录“tree”将如下所示:

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

我们将创建的数据库保留在 /Sensor_Database 目录中,因此您需要使用“../sensorsData.db”连接 SQLite。

行!环境准备好后,让我们组装部件并创建我们的 Python WebServer 应用程序 .上图让我们知道应该做什么!

第 12 步:Python 网络服务器应用程序

从上一张图开始,让我们使用 Flask 创建一个 python WebServer。我建议 Geany 作为要使用的 IDE, 一旦您可以同时处理不同类型的文件(.py、.html 和 .css)。

下面的代码是我们第一个 web 服务器上使用的 python 脚本:

from flask import Flask, render_template, requestapp =Flask(__name__)import sqlite3# 从 databasedef getData() 检索数据: conn=sqlite3.connect('../sensorsData .db') curs=conn.cursor() 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, hum# main route @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=错误) 

你可以从我的 GitHub 获取 python 脚本 appDhtWebServer.py。上面代码的作用是:

有了这个请求,代码中做的第一件事就是使用函数time, temp, hum =getData()从数据库中获取数据。 此函数与之前用于检索存储在表中的数据的查询基本相同。有了手头的数据,我们的脚本返回到网页 (index.html ):时间 , 温度嗡嗡声 作为对先前请求的响应。

所以,让我们看看 index.htmlstyle.css 将用于构建我们的前端的文件:

index.html

  DHT 传感器数据     

DHT 传感器数据

TEMPERATURE ==> {{ tempLab }} oC

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


最后传感器读数:{{ time }} ==> REFRESH


@2018 由 MJRoBot.org 开发

你可以从我的 GitHub 获取 index.html 文件。

style.css

body{ 背景:蓝色;颜色:黄色; padding:1%}.button { font:bold 15px Arial;文字装饰:无;背景颜色:#EEEEEE;颜色:#333333;填充:2px 6px 2px 6px;边框顶部:1px 实心 #CCCCCC;右边框:1px 实心 #333333;边框底部:1px 实心 #333333;左边框:1px 实心 #CCCCCC;} 

你可以从我的 GitHub 获取文件 style.css。这些文件必须像这样放置在您的目录中:

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

现在,在终端上运行 python 脚本:

sudo python3 appDhtWebServer.py 

转到您网络中的任何浏览器并输入 http://YOUR_RPI_IP (例如,就我而言:http://10.0.1.27)

上面的打印屏幕显示了您必须看到的内容。注意:如果您不确定您的 RPi Ip 地址,请在您的终端上运行:

 ifconfig 

在 wlan0:部分,您会找到它。就我而言:10.0.1.27

第 13 步:让我们的 Web 前端更酷!

让我们介绍一些仪表,以更好的方式呈现实际的温度和湿度值。请注意,我们的 Python 脚本不会改变,但在我们的 html/css 文件上使用 JustGage 将大大改善数据的呈现方式。

JustGage 是什么?

JustGage 是一个方便的 JavaScript 插件,用于生成漂亮和干净的仪表并为其设置动画。它基于用于矢量绘图的 Raphaël 库,因此它完全独立于分辨率和自我调整,几乎适用于任何浏览器。

安装:

justgage-1.2.2.zip

 DHT 数据传感器    

DHT 传感器数据


最后传感器读数:{{ time }} ==> REFRESH


@2018 由 MJRoBot.org 开发

从我的 GitHub 下载文件:index_gage.html,并将其重命名为 index.html(如果您想保留它,请不要忘记将前一个重命名为不同的名称,例如 index_txt.html)。

最终的目录树应如下所示:

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

在终端上按 [Crl-C] 退出 appDhtWebServer.py 并重新启动它。当您刷新浏览器时,您必须看到上面的打印屏幕。

查看您从 JustGage 网站下载的示例文件。尝试对您的量具进行更改。很简单。

第 14 步:完整过程

上图恢复了我们迄今为止所完成的工作:2 个独立的脚本并行运行,独立执行它们的任务:

使用传感器捕获数据并将其加载到数据库中 (logDHT.py ) 在数据库中查找数据并将它们呈现在 Web 前端 (appDhtWebServer.py ).

一般而言,我们捕获数据、将它们保存在数据库中并在网页上显示这些数据的项目已经完成。但是拥有一个包含历史数据的数据库并且仅将其用于最后捕获的数据是没有意义的。我们必须处理历史数据,最基本的事情就是将它们呈现在图表上。去吧!

第 15 步:绘制历史数据

Matplotlib 是一个非常好的图表数据库 这是一个 Python 2D 绘图库,可生成各种硬拷贝格式和跨平台交互环境的出版物质量数字。

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;文字装饰:无; 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


制造工艺

  1. 使用 Secret Manager 存储和管理敏感数据
  2. Microchip:24 位和 16 位 ADC,数据速率高达 153.6 kSPS
  3. 带有基于 Web 的图表的家庭(房间)温度和湿度监视器 – Raspberry Pi
  4. 使用 Raspberry Pi 和 Python 构建机器人
  5. 借助物联网数据加速数字化转型,感谢 Cisco 和 IBM
  6. 利用从边缘到云端再返回的物联网数据
  7. IIoT 之旅从远程遥测开始
  8. 如何使用 Tech Data 和 IBM Part 2 实现物联网
  9. 如何使用技术数据和 IBM 第 1 部分使物联网成为现实
  10. 利用大数据项目和人工智能推动业务成果
  11. 解决企业领导者与 ML 和 AI 竞争的实时需求
  12. 6G 之旅从一声巨响(和一次发射)开始