你是否曾经想过要实现一个自己的室内温度和湿度检测系统?利用周末的时间完成了这个小目标,我使用了ESP8266和DHT11,并将收集的数据通过WIFI发送到服务端程序,并存储到SQLite数据库中。在后面的介绍中,我将与你分享如何完成这个任务。
首先,我想解释一下我为什么选择了ESP8266和DHT11。ESP8266是一款低成本的Wi-Fi微芯片,具有全栈TCP/IP协议。借助于这款芯片,我们可以轻松的将任何微控制器连接到Wi-Fi网络。DHT11则是一款具有已校准数字输出的温湿度传感器。它的主要优点是精度高、响应速度快、抗干扰能力强,且价格低廉。
在硬件连接方面,ESP8266的3V3和GND分别连接到DHT11的VCC和GND,ESP8266的D4则连接到DHT11的数据端。这样,我们就可以通过ESP8266从DHT11读取温湿度数据了。
接下来是编程部分。首先,我们需要在ESP8266上运行一个程序,这个程序会定期从DHT11读取温度和湿度数据,并通过Wi-Fi将这些数据发送到我们的服务端程序。在这个程序中,我们使用了DHT库和ESP8266WiFi库。DHT库使我们能够方便地从DHT11读取数据,而ESP8266WiFi库则让ESP8266能够连接到Wi-Fi。
服务端程序是运行在服务器上的一个简单的Python脚本,它会监听来自ESP8266的连接,并将接收到的温湿度数据写入SQLite数据库。在这个脚本中,我们使用了WebAPI库来处理网络连接,用sqlite3库来操作SQLite数据库。
完成这个项目后,我不仅可以随时查看室内的温度和湿度,还可以通过分析SQLite数据库中的数据,了解室内温湿度的变化趋势、告警等等。
最后,我想强调的是,虽然我详细介绍了如何使用ESP8266和DHT11实现室内温度和湿度的采集并通过WIFI发送到服务端程序,但这只是其中一种方法。你完全可以根据自己的需求和条件,选择不同的硬件和软件,实现自己的小目标。我希望我的经验能为你提供一些启示。
开发工具:Arduino IDE 2.2.1
硬件:ESP8266 开发板、DHT12 温湿度模块、ST7735 TFT 屏幕
程序首次使用屏幕会显示二维码,支持微信扫码配WIFI
// ##################################################################################
//
// 温、湿度采集客户端
//
// 版本:1.0.01
//
// Create by linjifan 2023-11-11
// ##################################################################################
// 室内适宜 温度:19-26 度 、湿度:20-85 RH%
//
//图片解码库
#include <TJpg_Decoder.h>
//json库,用于网页解析
#include <ArduinoJson.h>
//时间库,用于时钟部分
#include <TimeLib.h>
//wifi库
#include <ESP8266WiFi.h>
//http请求库
#include <ESP8266HTTPClient.h>
//创建wifi的udp服务的库
#include <WiFiUdp.h>
//静态存储区,用于存储一些固定参数
#include <EEPROM.h>
//安信可配网二维码
#include "qr.h"
#include <DHT.h>
#include <SPI.h>
#include "libraries\TFT_eSPI\TFT_eSPI.h"
//配置ESP8266 GPI1口
#define DHTPIN 5
//官方适配有:DHT11,DHT12,DHT21,DHT22,AM2301
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// 引脚请自行配置tft_espi库中的 User_Setup.h文件
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite clk = TFT_eSprite(&tft);
WiFiClient wificlient;
uint32_t targetTime = 0;
byte loadNum = 6;
//上传采集间隔等待时间
const uint32_t sleepTime = 1000 * 60;
//节点名称
const char node[] = "DataCenter";
//---------------修改此处""内的信息,配网无效才需要修改,一般不用动--
//WIFI名称
const char ssid[] = "";
//WIFI密码
const char pass[] = "";
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) {
if (y >= tft.height()) return 0;
tft.pushImage(x, y, w, h, bitmap);
// Return 1 to decode next block
return 1;
}
void setup(void) {
Serial.begin(115200);
Serial.println(F("DHT11 test!"));
//DHT11 模块初始化
dht.begin();
delay(2000);
/* TFT init */
tft.begin();
// 反转所有显示颜色:1反转,0正常
tft.invertDisplay(1);
tft.fillScreen(0xFFFF);
tft.setTextColor(TFT_WHITE, 0xFFFF);
// 设置屏幕显示的旋转角度,参数为:0, 1, 2, 3
// 分别代表 0°、90°、180°、270°
//根据实际需要旋转
tft.setRotation(4);
TJpgDec.setJpgScale(1);
TJpgDec.setSwapBytes(true);
TJpgDec.setCallback(tft_output);
targetTime = millis() + 1000;
Serial.print("正在连接WIFI...");
Serial.println(ssid);
WiFi.begin(WiFi.SSID().c_str(), WiFi.psk().c_str());
TJpgDec.setJpgScale(1);
TJpgDec.setSwapBytes(true);
TJpgDec.setCallback(tft_output);
tft.fillScreen(0xFFFF);
while (WiFi.status() != WL_CONNECTED) {
loading(70);
if (loadNum >= 94) {
SmartConfig();
break;
}
}
delay(10);
// while(loadNum < 94) //让动画走完
// {
// loading(1);
// }
Serial.print("本地IP: ");
Serial.println(WiFi.localIP());
Serial.print("MAC地址: ");
Serial.println(WiFi.macAddress());
tft.fillScreen(0xFFFF);
// 显示检查窗口
clk_check();
delay(5000);
}
//绘制检查窗口
void clk_check() {
clk.createSprite(120, 120);
clk.fillSprite(0xFFFF);
clk.setTextDatum(CL_DATUM);
clk.setTextColor(TFT_GREEN, 0xFFFF);
clk.drawString(" DHT11.....OK", 10, 20, 2);
clk.drawString(" WiFi......OK", 10, 40, 2);
clk.pushSprite(0, 0);
clk.deleteSprite();
}
//绘制进度条
void loading(byte delayTime) {
clk.setColorDepth(8);
// 创建窗口
clk.createSprite(100, 100);
// 填充率
clk.fillSprite(0xFFFF);
// 空心圆角矩形
clk.drawRoundRect(0, 0, 100, 16, 8, 0x0000);
// 实心圆角矩形
clk.fillRoundRect(3, 3, loadNum, 10, 5, 0x0000);
// 设置文本数据
clk.setTextDatum(CC_DATUM);
clk.setTextColor(TFT_GREEN, 0xFFFF);
clk.drawString("Connect WiFi...", 50, 40, 2);
clk.drawString("Ver: 1.0.01", 50, 80, 1);
clk.setTextColor(TFT_WHITE, 0xFFFF);
// 窗口位置
clk.pushSprite(14, 30);
clk.deleteSprite();
loadNum += 1;
delay(delayTime);
}
//微信配网,注意连接2.4g网络
void SmartConfig(void) {
// 设置STA模式
WiFi.mode(WIFI_STA);
//tft.pushImage(0, 0, 240, 240, qr);
//tft.pushImage(0, 0, 240, 240, qr);
TJpgDec.drawJpg(0, 0, qr, sizeof(qr));
// 打印log信息
Serial.println("\r\nWait for Smartconfig...");
// 开始 SmartConfig 等待手机端发出用户名和密码
WiFi.beginSmartConfig();
while (1) {
Serial.print(".");
// wait for a second
delay(100);
// 配网成功,接收到SSID和密码
if (WiFi.smartConfigDone()) {
Serial.println("SmartConfig Success");
Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
break;
}
}
loadNum = 94;
}
//上传温、湿度等信息到服务端
void pushData(String h, String t, String i, String Node) {
String URL = "http://172.168.0.XXX:5000/api/v1/weather/Update?h=" + h + "&t=" + t + "&i=" + i + "&time=" + String(now()) + "&node=" + Node + "&mac=" + WiFi.macAddress();
HTTPClient httpClient;
//配置请求地址。此处也可以不使用端口号和PATH而单纯的
httpClient.begin(wificlient, URL);
//设置请求头中的User-Agent
httpClient.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1");
//httpClient.addHeader("Referer", "http://www.weather.com.cn/");
//启动连接并发送HTTP请求
int httpCode = httpClient.GET();
Serial.print("Send GET request to URL: ");
Serial.println(URL);
//如果服务器响应OK则从服务器获取响应体信息并通过串口输出
if (httpCode == HTTP_CODE_OK) {
String str = httpClient.getString();
Serial.println(str);
} else {
Serial.println("上报数据错误:");
Serial.println(httpCode);
// 显示红色失败状态
drawIndicatorLight(120, 120, TFT_NAVY);
delay(200);
}
//关闭ESP8266与服务器连接
httpClient.end();
}
void loop() {
// 读取温度或湿度大约需要250毫秒!
// 传感器读数也可能高达2秒"旧"(它是一个非常慢的传感器)
float h = dht.readHumidity();
// 以摄氏度读取温度(默认值)
float t = dht.readTemperature();
// 将温度读取为华氏温度(isFahrenheit = true)
float f = dht.readTemperature(true);
// 检查是否有读取失败并提前退出(再试一次)。
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
// 计算华氏热度指数(默认值)
float hif = dht.computeHeatIndex(f, h);
// 以摄氏度计算热指数(isfahrenheit = false)
float hic = dht.computeHeatIndex(t, h, false);
//打印数值(华氏度的注释掉了)
//打印湿度
Serial.print(F("Humidity: "));
Serial.print(h);
//打印温度
Serial.print(F("% Temperature: "));
Serial.print(t);
Serial.print(F("°C "));
//Serial.print(f);
//Serial.println(F("°F"));
//打印热指数
Serial.print(F(" Heat index: "));
Serial.print(hic);
Serial.print(F("°C "));
Serial.println();
clk.createSprite(120, 120);
clk.fillSprite(0xFFFF);
clk.setTextDatum(CL_DATUM);
clk.setTextColor(TFT_BLACK, TFT_WHITE);
clk.drawString("Node : " + String(node), 0, 10, 2);
clk.drawString("Humidity : " + String(h), 0, 30, 2);
clk.drawString("TEMP : " + String(t), 0, 50, 2);
clk.drawString("Heat Index : " + String(hic), 0, 70, 2);
clk.drawString(WiFi.localIP().toString().c_str(), 0, 90, 2);
clk.drawString(WiFi.macAddress(), 0, 110, 2);
clk.pushSprite(0, 0);
clk.deleteSprite();
//上报数据
drawIndicatorLight(120, 120, TFT_BLACK);
pushData(String(h), String(t), String(hic), node);
drawIndicatorLight(120, 120, TFT_WHITE);
delay(sleepTime);
}
void drawIndicatorLight(int x, int y, uint16_t color) {
// Draw a filled circle with radius 5
tft.fillCircle(x, y, 3, color);
}