#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
// --- 配置信息 ---
const char* ssid = "Wokwi-GUEST"; // Wokwi 固定 WiFi
const char* password = "";
const char* mqtt_server = "thingsboard.cloud";
const char* access_token = "ty9j7x7nfy2su4srxqct"; // 粘贴你刚才获取的 Token
// --- 硬件定义 ---
#define DHTPIN 15
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
float lastTemp = -999.0; // 初始值设为一个不可能的数
const float FIRE_THRESHOLD = 2.0; // 5秒内升温超过2度视为火警
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
Serial.begin(115200);
pinMode(2, OUTPUT); // 确保 GPIO 2 (LED) 是输出模式
dht.begin();
setup_wifi();
client.setServer(mqtt_server, 1883);
}
void setup_wifi() {
delay(10);
Serial.print("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("Connected!");
}
void reconnect() {
while (!client.connected()) {
Serial.print("Connecting to ThingsBoard MQTT...");
// 使用 Access Token 作为用户名
if (client.connect("ESP32_Residential", access_token, NULL)) {
Serial.println("Connected!");
} else {
delay(5000);
}
}
}
void loop() {
if (!client.connected()) reconnect();
client.loop();
// 1. 读取传感器数据
float h = dht.readHumidity();
float t = dht.readTemperature();
// 2. 异常检测 (Anomaly Detection)
// 逻辑:如果数据不是数字,或者超出了 DHT22 的正常量程,判定为异常
bool isAnomaly = false;
if (isnan(h) || isnan(t) || t > 80.0 || t < -40.0 || h > 100.0 || h < 0.0) {
isAnomaly = true;
Serial.println("!! Data Anomaly Detected !!");
}
// 3. 火灾预警 (Fire Alarm / Slope Detection)
bool fireAlarm = false;
if (!isAnomaly && lastTemp != -999.0) {
float slope = t - lastTemp; // 计算温度变化率
if (slope >= FIRE_THRESHOLD) {
fireAlarm = true;
Serial.println("!! FIRE ALARM: Rapid Temperature Rise !!");
}
}
// 只有在数据正常时才更新“记忆”
if (!isAnomaly) lastTemp = t;
// 4. 执行器控制逻辑 (Actuator Control)
String fanStatus;
if (fireAlarm) {
fanStatus = "ON (EMERGENCY)";
// 紧急状态:LED 快速闪烁
for(int i=0; i<3; i++) {
digitalWrite(2, HIGH); delay(100);
digitalWrite(2, LOW); delay(100);
}
} else if (t > 28.0) {
digitalWrite(2, HIGH);
fanStatus = "ON";
} else {
digitalWrite(2, LOW);
fanStatus = "OFF";
}
// 5. 构建 JSON 数据包 (加上新字段)
String payload = "{";
payload += "\"temperature\":" + String(t) + ",";
payload += "\"humidity\":" + String(h) + ",";
payload += "\"fanStatus\":\"" + fanStatus + "\",";
payload += "\"fireAlarm\":" + String(fireAlarm ? "true" : "false") + ",";
payload += "\"isAnomaly\":" + String(isAnomaly ? "true" : "false");
payload += "}";
// 6. 发送数据
Serial.print("Sending: ");
Serial.println(payload);
client.publish("v1/devices/me/telemetry", payload.c_str());
delay(5000); // 每 5 秒检测并发送一次
}