HTU21D温湿度采集方案 - ThingsPanel接入指南
一般大家都用DHT11,相比之下,HTU21D和DHT11它们在性能和应用场景上有着显著差异。在精度和准确性方面,HTU21D明显优于DHT11。HTU21D的温度测量精度可达到±0.3℃,湿度精度为±2%RH,而DHT11的温度精度只有±2℃,湿度精度为±5%RH。不仅如此,HTU21D的测量结果具有更好的可重复性和稳定性,这使得它更适合需要持续监测的场景。
从测量范围来看,HTU21D也展现出更强的适应性。它可以测量-40℃到+125℃的温度范围,湿度测量范围覆盖0-100%RH。相比之下,DHT11的测量范围相对有限,温度测量范围仅为0℃到50℃,湿度测量范围为20-90%RH。这种差异使得HTU21D更适合工业环境和特殊应用场景。
在通信协议方面,HTU21D采用I2C通信协议,这种协议具有更强的抗干扰能力和更可靠的数据传输特性。而DHT11使用单总线协议,虽然接线简单,但容易受到外部干扰,对时序要求也较高。HTU21D的响应速度也比DHT11快得多,前者约需8秒即可完成一次测量,而后者则需要15-30秒。
一、硬件准备
- NodeMCU ESP8266开发板
- HTU21D温湿度传感器
- 杜邦线若干
- Micro USB数据线
二、接线说明
HTU21D与ESP8266的连接方式:
- VDD → 3.3V
- GND → GND
- SCL → GPIO5 (D1)
- SDA → GPIO4 (D2)
三、软件环境
- Arduino IDE
- 必要的库文件:
- ESP8266WiFi
- PubSubClient
- SparkFunHTU21D
- ArduinoJson
- WiFiManager
- 源代码
注意里面的MQTT信息需要在ThingsPanel平台添加设备后获得。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <WiFiManager.h>
#include "SparkFunHTU21D.h"
#include <ArduinoJson.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
// MQTT设置
const char* mqtt_server = "47.115.210.16";
const int mqtt_port = 1883;
const char* mqtt_username = "0d97c8ad-c34e-8c4d-c28";
const char* mqtt_password = "1ffd8b9";
const char* mqtt_client_id = "mqtt_240df43e-9c4";
const char* mqtt_pub_topic = "devices/telemetry";
const char* mqtt_sub_topic = "devices/telemetry/control/240df43e-9c46-795d-11a2-a71d78a22ae5";
// 创建对象
WiFiClient espClient;
PubSubClient client(espClient);
HTU21D myHumidity;
WiFiManager wifiManager;
// 定义发送间隔时间(毫秒)
const long interval = 30000;
unsigned long previousMillis = 0;
// 数据滤波用变量
float lastTemp = 0;
float lastHum = 0;
bool isFirstReading = true;
// 重置按钮引脚
const int RESET_PIN = 0; // GPIO0, 通常是Flash按钮
// 数据有效性检查
bool isValidReading(float temp, float hum) {
// 温度范围检查(-40到80度是HTU21D的规格范围)
if (temp < -40 || temp > 80) return false;
// 湿度范围检查(0-100%)
if (hum < 0 || hum > 100) return false;
// 检查是否为NaN
if (isnan(temp) || isnan(hum)) return false;
return true;
}
// 简单滤波函数
float filterData(float newValue, float lastValue, bool isFirstReading) {
if (isFirstReading) return newValue;
// 如果新值与上一次值相差太大,可能是异常
if (abs(newValue - lastValue) > 10) {
return lastValue; // 返回上一次的值
}
// 简单平均滤波
return (newValue + lastValue) / 2;
}
void saveConfigCallback () {
Serial.println("Should save config");
}
void checkButton(){
if (digitalRead(RESET_PIN) == LOW) {
delay(50);
if (digitalRead(RESET_PIN) == LOW) {
Serial.println("Button Pressed");
delay(3000);
if (digitalRead(RESET_PIN) == LOW) {
Serial.println("Button Held");
Serial.println("Erasing Config, restarting");
wifiManager.resetSettings();
ESP.restart();
}
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
messageTemp += (char)payload[i];
}
Serial.println();
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, messageTemp);
if (!error) {
if(doc.containsKey("switch")) {
int switchValue = doc["switch"];
Serial.print("Switch value: ");
Serial.println(switchValue);
}
}
}
void reconnect() {
int retries = 0;
while (!client.connected() && retries < 5) { // 最多尝试5次
Serial.print("Attempting MQTT connection...");
if (client.connect(mqtt_client_id, mqtt_username, mqtt_password)) {
Serial.println("connected");
client.subscribe(mqtt_sub_topic);
break;
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" retry in 5 seconds");
retries++;
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(RESET_PIN, INPUT);
// 初始化I2C
Wire.begin(4, 5); // SDA = GPIO4, SCL = GPIO5
Wire.setClock(100000); // 设置I2C频率为100kHz以提高稳定性
// 初始化HTU21D
myHumidity.begin();
delay(1000); // 等待传感器初始化完成
// 测试传感器是否正常工作
float testTemp = myHumidity.readTemperature();
float testHum = myHumidity.readHumidity();
if (isnan(testTemp) || isnan(testHum)) {
Serial.println("HTU21D read failed");
delay(1000);
ESP.restart();
}
Serial.println("HTU21D initialized successfully");
// WiFiManager设置
wifiManager.setConfigPortalTimeout(180);
if(!wifiManager.autoConnect("HTU21D_Setup")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
ESP.restart();
}
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
// 等待传感器稳定
delay(2000);
}
void loop() {
checkButton();
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
// 读取温湿度数据
float rawTemp = myHumidity.readTemperature();
float rawHum = myHumidity.readHumidity();
// 数据有效性检查
if (isValidReading(rawTemp, rawHum)) {
// 应用滤波
float temp = filterData(rawTemp, lastTemp, isFirstReading);
float hum = filterData(rawHum, lastHum, isFirstReading);
// 更新上一次的值
lastTemp = temp;
lastHum = hum;
isFirstReading = false;
// 创建JSON数据 - 保留一位小数
StaticJsonDocument<200> doc;
doc["temperature"] = round(temp * 10) / 10.0; // 保留一位小数
doc["humidity"] = round(hum * 10) / 10.0; // 保留一位小数
char jsonBuffer[200];
serializeJson(doc, jsonBuffer);
// 发布数据
client.publish(mqtt_pub_topic, jsonBuffer);
// 打印到串口
Serial.print("Temperature: ");
Serial.print(temp, 1); // 显示一位小数
Serial.print("C");
Serial.print(" Humidity: ");
Serial.print(hum, 1); // 显示一位小数
Serial.println("%");
} else {
Serial.println("Invalid reading detected");
}
}
}
四、功能特点
自动配网功能
- 首次使用时会生成"HTU21D_Setup"热点
- 连接热点后自动跳转配置页面
- 配置完成后自动保存信息
数据处理优化
- 温湿度数据保留一位小数
- 异常数据过滤
- 简单滤波处理
远程监控
- 实时推送温湿度数据
- 支持远程查看历史数据
- 支持数据可视化展示
五、使用说明
首次使用步骤:
- 给设备上电
- 手机搜索并连接"HTU21D_Setup"热点
- 在配置页面输入WiFi信息
- 等待设备连接到网络
数据查看:
- 登录ThingsPanel平台
- 在设备列表中找到对应设备
- 查看实时数据和历史曲线
注意事项:
- 确保供电稳定,建议使用5V USB供电
- 传感器需要2-3分钟预热时间
- 避免将传感器放置在强气流区域
六、故障排除
设备无法连接网络:
- 检查WiFi密码是否正确
- 长按Flash按钮3秒重置网络设置
- 检查路由器设置
数据异常:
- 检查接线是否牢固
- 确认供电电压稳定
- 避免传感器受外界干扰