DHT11温湿度传感器在智能家居中的实战应用(附Arduino代码)
几年前,我还在为家里的绿植频繁枯萎而烦恼。明明按时浇水,却总也掌握不好分寸。直到我开始接触智能家居DIY,用一块Arduino开发板和一个小小的DHT11传感器,才真正解决了这个问题。这个成本不到20元的小模块,不仅能告诉我房间的温度和湿度,还能通过简单的编程实现自动控制,让我的生活环境变得更加舒适。
对于智能家居爱好者和物联网开发者来说,DHT11就像是一个入门级的“瑞士军刀”——它简单、便宜、可靠,却能解决很多实际问题。无论是监测婴儿房的温湿度,还是控制加湿器自动工作,甚至是搭建一个小型气象站,DHT11都能胜任。更重要的是,它只需要一根数据线就能工作,这让硬件连接变得异常简单。
在这篇文章里,我不会重复那些教科书式的原理讲解,而是想分享一些我在实际项目中积累的经验和技巧。我会带你从硬件连接到代码编写,再到数据上传和可视化,一步步构建一个完整的智能家居环境监测系统。你会发现,即使没有专业的电子工程背景,也能轻松上手。
1. 硬件选型与连接:不只是接三根线那么简单
很多人以为连接DHT11就是接上VCC、GND和DATA三根线,但实际上这里面有不少细节需要注意。我刚开始玩DHT11的时候,就因为忽略了一个小细节,导致传感器读数一直不稳定。
1.1 DHT11模块的选择与识别
市面上常见的DHT11模块主要有两种封装形式:三针直插式和四针带PCB板式。虽然它们核心的传感器芯片相同,但在使用上有些微差别。
| 模块类型 | 引脚数量 | 是否内置上拉电阻 | 推荐使用场景 |
|---|---|---|---|
| 三针直插式 | 3个(VCC、DATA、GND) | 通常没有 | 需要自己设计PCB的项目 |
| 四针PCB模块 | 4个(VCC、DATA、NC、GND) | 通常内置4.7KΩ上拉电阻 | 面包板快速原型开发 |
注意:如果你购买的是四针模块,那个标着“NC”的引脚是空脚,不需要连接。很多新手会误以为需要接地或接电源,其实完全不用管它。
我在实际项目中更推荐使用四针PCB模块,因为它已经内置了上拉电阻,省去了外接电阻的麻烦。而且模块上通常有丝印标注,不容易接错线。
1.2 与Arduino的正确连接方法
连接DHT11到Arduino Uno的步骤看似简单,但有几个关键点容易出错:
// 错误的连接会导致的问题:
// 1. VCC接3.3V:传感器可能工作不稳定,通信距离受限
// 2. 忘记接上拉电阻:DATA线无法拉高,通信失败
// 3. DATA线接错引脚:无法读取数据
// 正确的连接方式:
// DHT11 VCC -> Arduino 5V
// DHT11 DATA -> Arduino Digital Pin 2(或其他数字引脚)
// DHT11 GND -> Arduino GND
// 注意:如果使用三针模块,需要在DATA和VCC之间接4.7KΩ上拉电阻
这里有一个我经常用的实际接线图:
Arduino Uno引脚布局:
┌─────────────────┐
│ USB POWER │
│ [ ] [ ] [ ] [ ]│
│ │
│ D13 A0│
│ D12 A1│
│ D11 A2│
│ D10 A3│
│ D9 A4│
│ D8 A5│
│ │
│ D7 ( ) AREF│
│ D6 UNO GND│
│ D5 ~13│
│ D4 ~12│
│ ~3 ~11│
│ ~2 → ~10│ ← DHT11 DATA接这里
│ TX1 ~9│
│ RX0 ~8│
│ │
│ GND 5V 3V3 VIN│
│ [ ] [ ] [ ] [ ] │
│ ↑ ↑ │
│ GND VCC │
└─────────────────┘
在实际接线时,我习惯用不同颜色的杜邦线来区分功能:
- 红色:VCC(5V电源)
- 黑色:GND(地线)
- 黄色:DATA(数据线)
这种颜色编码能大大减少接错线的概率,特别是在项目复杂、连线众多的时候。
1.3 电源与距离的权衡
DHT11的数据手册上写着“使用5V电源时通信距离可达20米”,但实际使用中我发现这个距离是有条件的:
// 实际测试数据:
// 电源电压 | 可靠通信距离 | 备注
// 5.0V | 15-20米 | 使用质量好的屏蔽线
// 3.3V | 0.5-1米 | 仅适合短距离连接
// 5.0V | 5-8米 | 使用普通杜邦线
// 建议:如果传感器需要远离主控板,务必使用5V供电,并考虑使用双绞线或屏蔽线
我在一个温室监控项目中,需要把传感器放在距离控制箱10米远的地方。最初用了3.3V供电,结果数据时有时无。后来改用5V供电,并换上了带屏蔽的网线(只用其中三芯),问题就解决了。
2. 库的选择与代码优化:避开那些常见的坑
网上能找到的DHT11 Arduino库很多,但质量参差不齐。我试过至少五个不同的库,有些用起来很顺手,有些则隐藏着各种问题。
2.1 主流库的比较与选择
目前最常用的DHT库主要有两个:
- Adafruit DHT Sensor Library
- SimpleDHT
我制作了一个对比表格,帮你快速了解它们的区别:
| 特性 | Adafruit DHT库 | SimpleDHT库 | 我的推荐 |
|---|---|---|---|
| 安装便利性 | 可通过库管理器安装 | 需手动下载 | Adafruit |
| 代码简洁性 | 较简洁 | 非常简洁 | SimpleDHT |
| 错误处理 | 完善的状态返回 | 基本错误处理 | Adafruit |
| 兼容性 | 支持DHT11、DHT22、AM2302 | 支持DHT11、DHT22 | Adafruit |
| 文档完整性 | 文档齐全,示例丰富 | 文档简单 | Adafruit |
| 实际稳定性 | 非常稳定 | 偶尔超时 | Adafruit |
安装Adafruit DHT库的方法很简单,在Arduino IDE中:
- 点击“工具” -> “管理库”
- 搜索“DHT sensor library”
- 找到“DHT sensor library by Adafruit”并安装
2.2 基础读取代码与错误处理
很多教程给的示例代码都太简单,没有考虑实际使用中可能出现的各种问题。下面是我在实际项目中优化过的代码:
#include <DHT.h>
// 定义引脚和传感器类型
#define DHTPIN 2 // 数据引脚连接的数字引脚
#define DHTTYPE DHT11 // 使用DHT11传感器
DHT dht(DHTPIN, DHTTYPE);
// 全局变量存储最后一次有效读数
float lastValidTemp = 0;
float lastValidHumi = 0;
unsigned long lastReadTime = 0;
int readErrorCount = 0;
void setup() {
Serial.begin(9600);
Serial.println("DHT11智能家居监测系统启动");
// 初始化DHT传感器
dht.begin();
// 重要:上电后等待传感器稳定
delay(2000); // DHT11需要1-2秒稳定时间
Serial.println("传感器初始化完成,开始读取数据...");
}
bool readDHTData(float &temperature, float &humidity) {
// 防止读取过于频繁(DHT11需要至少2秒间隔)
if (millis() - lastReadTime < 2000) {
return false;
}
// 尝试读取数据
float h = dht.readHumidity();
float t = dht.readTemperature();
// 检查读取是否成功
if (isnan(h) || isnan(t)) {
readErrorCount++;
Serial.print("读取失败,错误次数:");
Serial.println(readErrorCount);
// 如果连续失败5次,尝试重新初始化
if (readErrorCount >= 5) {
Serial.println("传感器可能异常,尝试重新初始化...");
dht.begin();
readErrorCount = 0;
delay(2000);
}
return false;
}
// 数据有效性检查
if (h < 20 || h > 90 || t < 0 || t > 50) {
Serial.println("数据超出合理范围,丢弃");
return false;
}
// 更新有效数据
temperature = t;
humidity = h;
lastValidTemp = t;
lastValidHumi = h;
lastReadTime = millis();
readErrorCount = 0;
return true;
}
void loop() {
float temperature, humidity;
if (readDHTData(temperature, humidity)) {
// 成功读取到有效数据
Serial.print("温度: ");
Serial.print(temperature);
Serial.print("°C, 湿度: ");
Serial.print(humidity);
Serial.println("%");
// 这里可以添加数据上传或控制逻辑
checkAndControl(temperature, humidity);
} else {
// 使用最后一次有效数据
Serial.print("使用缓存数据 - 温度: ");
Serial.print(lastValidTemp);
Serial.print("°C, 湿度: ");
Serial.print(lastValidHumi);
Serial.println("%");
}
delay(3000); // 每3秒读取一次
}
void checkAndControl(float temp, float humi) {
// 简单的自动控制逻辑示例
if (humi < 40) {
Serial.println("湿度过低,建议开启加湿器");
} else if (humi > 70) {
Serial.println("湿度过高,建议开启除湿器");
}
if (temp > 28) {
Serial.println("温度过高,建议开启空调");
} else if (temp < 18) {
Serial.println("温度过低,建议开启暖气");
}
}
这段代码有几个关键优化点:
- 防抖处理:确保读取间隔不少于2秒,避免传感器忙状态
- 错误累积检测:连续多次失败后尝试重新初始化
- 数据范围验证:丢弃明显不合理的数据
- 数据缓存:读取失败时使用最后一次有效数据
2.3 高级功能:露点温度计算
除了基本的温湿度,我们还可以计算露点温度——这是空气开始结露的温度,对于防潮防霉很有意义。
// 计算露点温度(MAGNO公式)
float calculateDewPoint(float temperature, float humidity) {
// 参数定义
float a = 17.27;
float b = 237.7;
// 计算中间变量
float alpha = ((a * temperature) / (b + temperature)) + log(humidity / 100.0);
// 计算露点
float dewPoint = (b * alpha) / (a - alpha);
return dewPoint;
}
// 在loop函数中添加:
float dewPoint = calculateDewPoint(temperature, humidity);
Serial.print("露点温度: ");
Serial.print(dewPoint);
Serial.println("°C");
// 露点应用:判断是否可能结露
if (dewPoint >= temperature - 2) {
Serial.println("警告:可能结露,请加强通风!");
}
露点温度的实际应用场景:
- 博物馆/档案馆:防止文物发霉
- 电子设备房:防止电路板结露短路
- 地下室:预警潮湿问题
- 汽车:防止车窗起雾
3. 数据上传与云端集成:从本地到物联网
单纯在串口监视器里看数据意义有限,真正的智能家居需要数据能上传到云端,实现远程监控和自动化。
3.1 使用ESP8266连接Wi-Fi
Arduino Uno本身没有Wi-Fi功能,需要搭配ESP8266模块。我推荐使用NodeMCU或Wemos D1 mini,它们内置了ESP8266,使用起来更方便。
接线示意图:
Arduino Uno <-> ESP8266 (NodeMCU)
5V -> VIN
GND -> GND
TX (Pin1) -> RX
RX (Pin0) -> TX
软件上,我们需要使用SoftwareSerial库来实现软串口通信:
#include <SoftwareSerial.h>
// 设置软串口:RX=10, TX=11
SoftwareSerial espSerial(10, 11); // RX, TX
void setup() {
Serial.begin(9600); // 用于调试
espSerial.begin(115200); // ESP8266默认波特率
// 发送AT指令测试连接
delay(1000);
espSerial.println("AT");
waitForResponse("OK", 2000);
}
void waitForResponse(String expected, int timeout) {
unsigned long startTime = millis();
String response = "";
while (millis() - startTime < timeout) {
if (espSerial.available()) {
char c = espSerial.read();
response += c;
if (response.indexOf(expected) != -1) {
Serial.println("收到预期响应: " + expected);
return;
}
}
}
Serial.println("等待响应超时");
}
// 连接Wi-Fi的函数
bool connectWiFi(const char* ssid, const char* password) {
Serial.println("连接Wi-Fi...");
espSerial.println("AT+CWMODE=1"); // 设置为STA模式
delay(1000);
String cmd = "AT+CWJAP=\"";
cmd += ssid;
cmd += "\",\"";
cmd += password;
cmd += "\"";
espSerial.println(cmd);
// 等待连接,最多30秒
unsigned long startTime = millis();
while (millis() - startTime < 30000) {
if (espSerial.available()) {
String response = espSerial.readString();
Serial.println(response);
if (response.indexOf("WIFI CONNECTED") != -1) {
Serial.println("Wi-Fi连接成功");
return true;
}
if (response.indexOf("FAIL") != -1) {
Serial.println("Wi-Fi连接失败");
return false;
}
}
}
Serial.println("连接超时");
return false;
}
3.2 数据上传到MQTT服务器
MQTT是物联网最常用的轻量级消息协议。这里以免费的公共MQTT服务器为例:
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
// WiFi配置
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
// MQTT配置
const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
const char* mqtt_topic = "home/sensor/dht11";
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("连接WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi连接成功");
Serial.print("IP地址: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
while (!client.connected()) {
Serial.print("尝试MQTT连接...");
// 生成客户端ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str())) {
Serial.println("连接成功");
} else {
Serial.print("失败,rc=");
Serial.print(client.state());
Serial.println(" 5秒后重试");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
// 初始化DHT传感器
dht.begin();
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// 读取DHT数据
float h = dht.readHumidity();
float t = dht.readTemperature();
if (!isnan(h) && !isnan(t)) {
// 创建JSON格式的数据
String payload = "{";
payload += "\"temperature\":" + String(t, 1);
payload += ",\"humidity\":" + String(h, 1);
payload += ",\"device_id\":\"living_room\"";
payload += ",\"timestamp\":" + String(millis());
payload += "}";
// 发布到MQTT
if (client.publish(mqtt_topic, payload.c_str())) {
Serial.println("数据发布成功");
} else {
Serial.println("数据发布失败");
}
}
delay(10000); // 每10秒上传一次
}
3.3 集成Home Assistant实现可视化
Home Assistant是当前最流行的开源智能家居平台。将DHT11数据接入Home Assistant后,可以创建漂亮的仪表盘。
首先,在Home Assistant的configuration.yaml中添加:
mqtt:
sensor:
- name: "客厅温度"
state_topic: "home/sensor/dht11"
unit_of_measurement: "°C"
value_template: "{{ value_json.temperature }}"
device_class: temperature
- name: "客厅湿度"
state_topic: "home/sensor/dht11"
unit_of_measurement: "%"
value_template: "{{ value_json.humidity }}"
device_class: humidity
然后,创建自动化规则,比如当湿度过低时自动打开加湿器:
automation:
- alias: "湿度过低时打开加湿器"
trigger:
platform: numeric_state
entity_id: sensor.living_room_humidity
below: 40
action:
service: switch.turn_on
entity_id: switch.humidifier
- alias: "湿度过高时关闭加湿器"
trigger:
platform: numeric_state
entity_id: sensor.living_room_humidity
above: 60
action:
service: switch.turn_off
entity_id: switch.humidifier
在Home Assistant的Lovelace界面中,可以创建这样的仪表盘卡片:
type: gauge
entity: sensor.living_room_temperature
name: 温度
unit: °C
min: 0
max: 50
severity:
green: 20
yellow: 25
red: 30
type: gauge
entity: sensor.living_room_humidity
name: 湿度
unit: '%'
min: 0
max: 100
severity:
green: 40
yellow: 60
red: 80
4. 实际项目案例:智能花盆监测系统
让我分享一个真实的项目案例——我为家里的绿植打造的智能花盆监测系统。这个系统不仅能监测环境温湿度,还能根据数据自动控制补光和浇水。
4.1 系统架构设计
整个系统由以下几个部分组成:
┌─────────────────────────────────────────────┐
│ 云端监控平台 │
│ (Home Assistant + 手机APP) │
└───────────────┬─────────────────────────────┘
│ MQTT/HTTP
┌───────────────▼─────────────────────────────┐
│ ESP8266网关 │
│ (负责数据汇总和上传) │
└──────┬──────────────┬──────────────┬───────┘
│ │ │
┌──────▼─────┐ ┌────▼──────┐ ┌────▼──────┐
│ 花盆节点1 │ │ 花盆节点2 │ │ 花盆节点3 │
│ DHT11+土壤 │ │ DHT11+土壤│ │ DHT11+土壤│
│ 湿度传感器 │ │ 湿度传感器│ │ 湿度传感器│
└────────────┘ └───────────┘ └───────────┘
每个花盆节点使用Arduino Pro Mini(低功耗)搭配DHT11和土壤湿度传感器,通过nRF24L01无线模块与ESP8266网关通信。
4.2 节点端完整代码
// 花盆节点代码 - Arduino Pro Mini + DHT11 + nRF24L01
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <DHT.h>
#include <LowPower.h>
// 引脚定义
#define DHTPIN 4
#define SOIL_MOISTURE_PIN A0
#define DHTTYPE DHT11
#define LED_PIN 3
// 无线模块配置
RF24 radio(9, 10); // CE, CSN
const byte address[6] = "00001";
// 传感器对象
DHT dht(DHTPIN, DHTTYPE);
// 数据结构
struct SensorData {
uint16_t nodeId;
float temperature;
float humidity;
uint16_t soilMoisture;
uint16_t batteryLevel;
uint32_t timestamp;
};
SensorData data;
void setup() {
Serial.begin(9600);
// 初始化传感器
dht.begin();
pinMode(SOIL_MOISTURE_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
// 初始化无线模块
if (!radio.begin()) {
Serial.println("nRF24L01初始化失败");
while (1);
}
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_LOW);
radio.stopListening();
// 设置节点ID(通过跳线设置)
data.nodeId = readNodeId();
Serial.print("节点");
Serial.print(data.nodeId);
Serial.println("初始化完成");
}
uint16_t readNodeId() {
// 通过A1-A3引脚的电平组合确定节点ID
uint8_t id = 0;
id |= (analogRead(A1) > 512) ? 0 : 1;
id |= (analogRead(A2) > 512) ? 0 : 2;
id |= (analogRead(A3) > 512) ? 0 : 4;
return id + 1; // ID从1开始
}
void readSensors() {
// 读取DHT11
data.humidity = dht.readHumidity();
data.temperature = dht.readTemperature();
// 读取土壤湿度(0-1023,值越小越湿)
data.soilMoisture = analogRead(SOIL_MOISTURE_PIN);
// 读取电池电压(通过分压电路)
int raw = analogRead(A7);
data.batteryLevel = map(raw, 0, 1023, 0, 100);
data.timestamp = millis();
// 数据验证
if (isnan(data.humidity) || isnan(data.temperature)) {
data.humidity = 0;
data.temperature = 0;
}
}
void sendData() {
digitalWrite(LED_PIN, HIGH);
// 尝试发送数据
bool success = radio.write(&data, sizeof(data));
if (success) {
Serial.println("数据发送成功");
} else {
Serial.println("数据发送失败");
// 失败重试机制
for (int i = 0; i < 3; i++) {
delay(100);
if (radio.write(&data, sizeof(data))) {
Serial.println("重试成功");
break;
}
}
}
digitalWrite(LED_PIN, LOW);
}
void loop() {
// 唤醒后读取传感器
readSensors();
// 打印调试信息
Serial.print("温度: ");
Serial.print(data.temperature);
Serial.print("°C, 湿度: ");
Serial.print(data.humidity);
Serial.print("%, 土壤湿度: ");
Serial.println(data.soilMoisture);
// 发送数据
sendData();
// 根据土壤湿度决定是否本地报警
if (data.soilMoisture > 800) { // 土壤太干
blinkLED(3, 200);
}
// 进入深度睡眠(8秒)
Serial.println("进入睡眠...");
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
void blinkLED(int times, int interval) {
for (int i = 0; i < times; i++) {
digitalWrite(LED_PIN, HIGH);
delay(interval);
digitalWrite(LED_PIN, LOW);
delay(interval);
}
}
4.3 网关端代码(ESP8266)
// 网关代码 - NodeMCU接收数据并上传
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// WiFi配置
const char* ssid = "你的WiFi";
const char* password = "你的密码";
// MQTT配置
const char* mqtt_server = "broker.hivemq.com";
const char* mqtt_user = "";
const char* mqtt_password = "";
// 无线模块
RF24 radio(D4, D8); // CE, CSN
const byte address[6] = "00001";
WiFiClient espClient;
PubSubClient client(espClient);
// 存储各节点数据
struct NodeData {
float temperature;
float humidity;
uint16_t soilMoisture;
uint32_t lastUpdate;
} nodes[4];
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("连接WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi连接成功");
Serial.print("IP地址: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
while (!client.connected()) {
Serial.print("尝试MQTT连接...");
String clientId = "PlantMonitorGateway-";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
Serial.println("连接成功");
} else {
Serial.print("失败,rc=");
Serial.print(client.state());
Serial.println(" 5秒后重试");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
// 初始化无线接收
if (!radio.begin()) {
Serial.println("nRF24L01初始化失败");
while (1);
}
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_LOW);
radio.startListening();
// 连接WiFi和MQTT
setup_wifi();
client.setServer(mqtt_server, 1883);
Serial.println("网关启动完成");
}
void processIncomingData() {
if (radio.available()) {
SensorData receivedData;
radio.read(&receivedData, sizeof(receivedData));
// 更新节点数据
uint8_t nodeIndex = receivedData.nodeId - 1;
if (nodeIndex < 4) {
nodes[nodeIndex].temperature = receivedData.temperature;
nodes[nodeIndex].humidity = receivedData.humidity;
nodes[nodeIndex].soilMoisture = receivedData.soilMoisture;
nodes[nodeIndex].lastUpdate = millis();
// 发布到MQTT
publishToMQTT(receivedData);
// 本地显示
Serial.print("节点");
Serial.print(receivedData.nodeId);
Serial.print(": 温度=");
Serial.print(receivedData.temperature);
Serial.print("°C, 湿度=");
Serial.print(receivedData.humidity);
Serial.print("%, 土壤=");
Serial.println(receivedData.soilMoisture);
}
}
}
void publishToMQTT(SensorData &data) {
// 创建JSON文档
StaticJsonDocument<200> doc;
doc["node_id"] = data.nodeId;
doc["temperature"] = data.temperature;
doc["humidity"] = data.humidity;
doc["soil_moisture"] = data.soilMoisture;
doc["battery"] = data.batteryLevel;
doc["timestamp"] = data.timestamp;
// 序列化JSON
char buffer[256];
size_t n = serializeJson(doc, buffer);
// 构建主题
String topic = "home/plants/node";
topic += data.nodeId;
topic += "/data";
// 发布
client.publish(topic.c_str(), buffer, n);
// 同时发布到汇总主题
String summaryTopic = "home/plants/summary";
client.publish(summaryTopic.c_str(), buffer, n);
}
void checkNodeStatus() {
unsigned long currentTime = millis();
for (int i = 0; i < 4; i++) {
if (nodes[i].lastUpdate > 0 &&
currentTime - nodes[i].lastUpdate > 120000) { // 2分钟无更新
Serial.print("警告:节点");
Serial.print(i + 1);
Serial.println("离线");
// 发布离线状态
String topic = "home/plants/node";
topic += (i + 1);
topic += "/status";
client.publish(topic.c_str(), "offline");
}
}
}
void loop() {
// 保持MQTT连接
if (!client.connected()) {
reconnect();
}
client.loop();
// 处理接收到的数据
processIncomingData();
// 定期检查节点状态
static unsigned long lastCheck = 0;
if (millis() - lastCheck > 30000) { // 每30秒检查一次
checkNodeStatus();
lastCheck = millis();
}
delay(10);
}
4.4 系统优化与维护建议
这个系统我实际运行了半年多,期间遇到并解决了不少问题。以下是一些经验总结:
-
电源管理:
- 节点使用18650锂电池供电,配合TP4056充电模块
- 添加0.1μF和10μF电容滤除电源噪声
- 睡眠模式下整机电流约20μA,电池可续航3个月
-
数据可靠性:
// 添加数据平滑滤波 #define SAMPLE_SIZE 5 float temperatureSamples[SAMPLE_SIZE]; int sampleIndex = 0; float getFilteredTemperature(float newSample) { temperatureSamples[sampleIndex] = newSample; sampleIndex = (sampleIndex + 1) % SAMPLE_SIZE; float sum = 0; for (int i = 0; i < SAMPLE_SIZE; i++) { sum += temperatureSamples[i]; } return sum / SAMPLE_SIZE; } -
故障诊断:
- 在节点上添加状态LED,不同闪烁模式表示不同状态
- 实现OTA(空中升级)功能,方便远程更新固件
- 记录运行日志,可通过串口或网络查看
-
成本控制:
- 单个节点总成本约35元(含外壳)
- 批量生产可降至25元以下
- 使用3D打印外壳,美观且防水
这个智能花盆系统不仅解决了我的绿植养护问题,还成为了朋友间的热门话题。后来我甚至接到了几个小批量生产的订单,帮助其他植物爱好者实现了类似的功能。
通过这个完整的项目案例,你可以看到DHT11虽然是个简单的传感器,但结合适当的硬件设计和软件编程,就能构建出真正实用的智能家居系统。关键不在于传感器的精度有多高,而在于如何将数据转化为有价值的行动。
&spm=1001.2101.3001.5002&articleId=155049385&d=1&t=3&u=63d55ba1b8c541f68af5a7c06a6b8059)
3789

被折叠的 条评论
为什么被折叠?



