项目介绍
本期 Funpack 活动包含多项任务,其基本要求是使用 FireBeetle EPS32-E 开发板作为主控,并搭配额外传感器、显示、控制模块实现具体功能。其中任务一,渔业养殖水质监控系统的具体任务要求为:
用FireBeetle ESP32-E开发板作为控制单元,观察养殖水质参数(温度/浊度/tds/pH值/电位/溶解氧中两项指标以上)的变化,并能把数据上传到IoT网站上,可实时动态显示监测水质的变化情况。
建议搭配:防水温度计/浊度计/tds传感器/pH计/溶氧传感器等两个及以上传感器配合完成。
本次活动期间内对任务一的变体进行了实现,将养殖水质参数更换为常见的温湿度参数,并搭配显示模块。数据上传的IoT 网站更换为自编 Flask 项目,以实现温湿度数据的完全自我管理。
使用器件如下:
- FireBeetle ESP32-E 主控板
- DFROBOT SEN0414 humidity & temperature sensor SHTC3 温湿度传感器
- SSD1306 OLED 显示屏
开发平台介绍
FireBeetle ESP32-E是一款基于ESP-WROOM-32E双核芯片的主控板,它专为IoT设计。
支持WIFI和蓝牙双模通信并具有体积小巧、超低功耗、板载充电电路、接口易用等特性。可灵活的用于家庭物联网改装、工业物联网改装、可穿戴设备等等。
- Type-C: USB接口:75v-5.5v
- 0锂电池接口:3.5-4.2v
- 2/D9 LED灯:使用2/09号脚控制的LED灯
- 充电指示灯:指示充电方式的红色LED,通过三种方式指示充电状态:1充满电或末充电时熄灭2、充电时常亮3、USB供电,末连接锂电池时高频闪烁
- RST复位引脚:单击复位按钮,将程序复位
- 5/D8 WS2812指示灯:使用5/D8引脚控制的WS2812RGB灯珠
- 低功耗焊盘:此焊盈专为低功耗设计,默认为连接状态,使用小刀轻轻刮粉中间的细线即可断开,断开后可降低500u4静态功耗,通过程序控制主控进入睡眠模式后可将功耗降低至131A。注意:焊盘断开后仅UsE方式供电可驱动RGE灯
- GD显示接口:DFRobot专用显示屏接口
- ESP32模组:乐鑫公司推出的ESP32-E模组
- 按钮:连接27/D4的按钮
更多参数及上手指南可参考链接:
https://wiki.dfrobot.com.cn/SKUDFR0654FireBeetleBoardESP32E
设计思路
项目整体可分为边缘设备端和服务器端两部分:边缘端采集环境数据,本地显示数值并上传到服务端。服务端负责数据的存储、查询以及可视化。
具体结构如下图所示,服务器端以 Flask 作为开发框架,数据使用 SQLite 存储,可视化使用 ECHARTS 库实现。
设计要点
SHTC3 传感器官方提供了具体的数据获取代码,ESP32 联网和显示数据也是比较常见的功能,因此整个项目实现起来难度不高。这里对实践过程中遇到的一些问题进行了记录:
双 I2C 设备
SHTC3 和 SSD1306 都使用 I2C 协议进行通信,但 FireBeetle 默认只配置了 21 和 20 两个引脚作为 I2C 端口。通过查阅文档发现,ESP32 芯片包含两个 I2C 控制器,且可以被配置到任意 I/O 口具体方法为:引入 <Wire.h> 库后,在调用 Wire1.begin(); 时传入自定义的 SDA 和 SCL 端口号即可。
ESP32有两个I2C控制器(也称为端口),负责处理两条I2C总线上的通信。每个I2C控制器都可以作为主机或从机运行。引脚21 默认的SDA, 引脚22是默认的SCL
https://wiki.dfrobot.com.cn/SKUDFR0654FireBeetleBoardESP32E
配置 GPIO 12 为 I2C 端口后无法开机
首次编程时将 GPIO 12 引脚配置后发现程序下载后无法开机,经过搜索后发现该引脚实际上是 ESP32 的 Strapping 引脚,与芯片系统的复位相关,12 必须在开机时保证低电平。将引脚进行调整后程序成功执行。
ESP32 共有5 个Strapping 管脚。
- MTDI/GPIO12:内部下拉
- GPIO0:内部上拉
- GPIO2:内部下拉
- MTDO/GPIO15:内部上拉
- GPIO5:内部上拉
ESP32 发送 POST 请求
封装后的函数如下,首先需要确保联网,之后定义 http 客户端,添加 header,并使用 & 拼接需要发送的变量。最后调用 http.POST() 发送具体的网络请求数据。
// Use the post method to send sensor data
void sendData() {
if(WiFi.status() == WL_CONNECTED){
WiFiClient client;
HTTPClient http;
http.begin(client, serverName);
// If you need Node-RED/server authentication, insert user and password below
//http.setAuthorization("REPLACE_WITH_SERVER_USERNAME", "REPLACE_WITH_SERVER_PASSWORD");
// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
// Data to send with HTTP POST
String httpRequestData = "secret=esp32";
httpRequestData = httpRequestData + "&temperature=" + T + "&humidity=" + RH;
// Send HTTP POST request
int httpResponseCode = http.POST(httpRequestData);
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
// Free resources
http.end();
}
else{
Serial.println("WiFi Disconnected");
}
}
网站设计
网站的功能主要是接收来自硬件平台的数据并进行存储,并且能够渲染温湿度变化曲线并展示。本项目中选用的 Web 开发框架为 Flask,由于数据存储需求不高直接使用 SQLite 存储数据。网站主要的实现步骤为:
- 明确网站功能需求
- 定义数据模型
- 编写数据查询及存储路由函数
- 前端实现数据绘制
数据查询和存储均为 POST 请求,具体参数可以参照源码。
数据模型定义
主要包含温度和湿度两个模型。
class Temperature(db.Model):
__tablename__ = 'temperature'
id = db.Column(db.Integer, primary_key=True)
temperature = db.Column(db.Float)
time = db.Column(db.DateTime)
def __init__(self, temperature, time):
self.temperature = temperature
self.time = time
def __repr__(self):
return '<Temperature %r>' % self.temperature
class Humidity(db.Model):
__tablename__ = 'humidity'
id = db.Column(db.Integer, primary_key=True)
humidity = db.Column(db.Float)
time = db.Column(db.DateTime)
def __init__(self, humidity, time):
self.humidity = humidity
self.time = time
def __repr__(self):
return '<Humidity %r>' % self.humidity
绘图
作图主要使用 Echarts 库,使用 Ajax 发起请求获得数据后进行解析并绘图。
var dom = document.getElementById('container');
var myChart = echarts.init(dom, null, {
renderer: 'canvas',
useDirtyRect: false
});
var app = {};
var option;
var data = {};
var settings = {
"url": "get-ht-data",
"method": "POST",
"timeout": 0,
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"data": {
"secret": "esp32"
}
};
$.ajax(settings).done(function (response) {
data = response;
option = {
title: {
text: 'Echarts'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['Humidity', 'Temperature']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: data['time'],
axisLabel: {
formatter: function (value) {
return value.split(' ')[4].substr(0, 5);
}
}
},
yAxis: {
type: 'value'
},
series: [
{
name: 'Temperature',
type: 'line',
data: data['temperature']
},
{
name: 'Humidity',
type: 'line',
data: data['humidity']
}
]
};
if (option && typeof option === 'object') {
myChart.setOption(option);
}
window.addEventListener('resize', myChart.resize);
});
总结
- 感谢 Funpack 活动提供的开发板和器件支持
- 自己搭建网站需要花费更多的时间,且功能大概率不完整,但能够拥有对数据和服务端显示、接口等内容的完全自主权。