#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "DHT.h"
// ================= 网络与云平台配置 =================
const char* ssid = "Wokwi-GUEST"; // Wokwi 默认的虚拟 WiFi,不要改
const char* password = ""; // Wokwi 虚拟 WiFi 没有密码,不要改
const char* mqtt_server = "bemfa.com"; // 巴法云 MQTT 服务器地址
const int mqtt_port = 9501; // 巴法云 MQTT 端口号
const char* client_id = "79ac2469ffbc41019518463ec32ced08"; // 替换成你控制台里的 UID!
const char* topic = "WaterMonitor"; // 替换成你在巴法云新建的主题名字!
WiFiClient espClient;
PubSubClient client(espClient);
// ================= 硬件引脚定义 =================
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
const int potPin = 34;
const int ledPin = 2;
const int buzzerPin = 5;
// ================= 状态追踪变量 =================
unsigned long flowStartTime = 0;
float baselineHumidity = 0.0;
bool isTracking = false;
bool isAlarming = false;
unsigned long lastMsgTime = 0; // 上次发送 MQTT 消息的时间
// 连接 WiFi 的函数
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("\nWiFi 连接成功!");
}
// 连接 MQTT 服务器的函数
void reconnect() {
while (!client.connected()) {
Serial.print("尝试连接 MQTT 云端...");
if (client.connect(client_id)) {
Serial.println("连接成功!");
} else {
Serial.print("失败,状态码=");
Serial.print(client.state());
Serial.println(",5秒后重试");
delay(5000);
}
}
}
void setup() {
Serial.begin(9600);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
dht.begin();
pinMode(ledPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
digitalWrite(ledPin, LOW);
digitalWrite(buzzerPin, LOW);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop(); // 保持 MQTT 底层心跳机制
unsigned long currentMillis = millis();
// 1. 读取传感器 (ESP32 的 ADC 是 12 位的,最大值 4095)
int potValue = analogRead(potPin);
float currentFlow = (potValue / 4095.0) * 5.0;
float currentHumidity = dht.readHumidity();
if (isnan(currentHumidity)) {
return; // 读取失败暂不处理,防止程序崩溃
}
// 2. 核心状态机逻辑 (完全保留阶段一的判断)
if (currentFlow > 0.2) {
if (!isTracking) {
isTracking = true;
flowStartTime = currentMillis;
baselineHumidity = currentHumidity;
} else {
unsigned long elapsed = currentMillis - flowStartTime;
float deltaHumidity = currentHumidity - baselineHumidity;
if (!isAlarming) {
if (elapsed >= 5000) {
if (elapsed <= 10000) {
if (deltaHumidity >= 10.0) {
isAlarming = true; // 触发漏水报警!
}
} else {
flowStartTime = currentMillis;
baselineHumidity = currentHumidity;
}
}
}
}
} else {
isTracking = false;
isAlarming = false;
}
// 执行声光报警动作
if (isAlarming) {
if ((currentMillis % 200) < 100) {
digitalWrite(ledPin, HIGH);
digitalWrite(buzzerPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
digitalWrite(buzzerPin, LOW);
}
} else {
digitalWrite(ledPin, LOW);
digitalWrite(buzzerPin, LOW);
}
// 3. 每隔 1 秒,将数据打包成 JSON 推送到云端
if (currentMillis - lastMsgTime > 1000) {
lastMsgTime = currentMillis;
// 创建 JSON 对象
StaticJsonDocument<200> doc;
doc["flow"] = currentFlow;
doc["humidity"] = currentHumidity;
doc["alarm"] = isAlarming;
// 将 JSON 序列化为字符串
char jsonBuffer[256];
serializeJson(doc, jsonBuffer);
// 通过 MQTT 发布出去
client.publish(topic, jsonBuffer);
Serial.print("[MQTT 发送] ");
Serial.println(jsonBuffer);
}
}