#include <WiFi.h>
#include <PubSubClient.h>
#include <HTTPClient.h>
#include <DHTesp.h>
// ===== B3. Wi-Fi =====
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
// ===== B4. DHT =====
#define DHT_PIN 15
DHTesp dht;
// ===== B7. MQTT =====
// chọn 1 broker
const char* MQTT_HOST = "broker.hivemq.com";
// const char* MQTT_HOST = "test.mosquitto.org";
const uint16_t MQTT_PORT = 1883;
const char* LOP = "k41";
const char* NHOM = "g01";
String topicTemp = String("iot/") + LOP + "/" + NHOM + "/temp";
String topicHum = String("iot/") + LOP + "/" + NHOM + "/hum";
WiFiClient espClient;
PubSubClient mqtt(espClient);
// ===== B8. ThingSpeak =====
const char* TS_API_KEY = "YZULAONJ2HRNMNMM";
const char* TS_URL = "http://api.thingspeak.com/update";
// ===== Chu kỳ =====
const unsigned long INTERVAL_READ = 2000; // 2s đọc sensor
const unsigned long INTERVAL_TS = 20000; // ≥20s gửi ThingSpeak
// ===== Biến toàn cục =====
float tempBuffer[5] = {NAN, NAN, NAN, NAN, NAN};
int tempIdx = 0;
int tempCount = 0;
unsigned long lastRead = 0;
unsigned long lastTS = 0;
// ===== Hàm phụ =====
float movingAverage(float val) {
if (!isnan(val)) {
tempBuffer[tempIdx] = val;
tempIdx = (tempIdx + 1) % 5;
if (tempCount < 5) tempCount++;
}
if (tempCount == 0) return NAN;
float sum = 0; int n = 0;
for (int i=0;i<5;i++) if (!isnan(tempBuffer[i])) { sum += tempBuffer[i]; n++; }
return n>0 ? sum/n : NAN;
}
void connectWiFi() {
if (WiFi.status() == WL_CONNECTED) return;
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
}
void connectMQTT() {
while (!mqtt.connected()) {
String cid = "esp32-" + String(random(0xffff), HEX);
if (mqtt.connect(cid.c_str())) {
Serial.println("MQTT connected");
} else {
delay(1000);
}
}
}
void sendThingSpeak(float t, float h) {
if (millis() - lastTS < INTERVAL_TS) return;
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
String url = String(TS_URL) + "?api_key=" + TS_API_KEY +
"&field1=" + String(t, 2) +
"&field2=" + String(h, 2);
http.begin(url);
int code = http.GET();
if (code == 200) {
Serial.println("ThingSpeak: OK");
lastTS = millis();
} else {
Serial.println("ThingSpeak: ERR");
}
http.end();
}
// ===== Setup =====
void setup() {
Serial.begin(115200);
dht.setup(DHT_PIN, DHTesp::DHT22); // đổi thành DHT11 nếu cần
connectWiFi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
connectMQTT();
}
// ===== Loop =====
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWiFi();
if (!mqtt.connected()) connectMQTT();
mqtt.loop();
unsigned long now = millis();
if (now - lastRead >= INTERVAL_READ) {
lastRead = now;
TempAndHumidity data = dht.getTempAndHumidity();
float temp = movingAverage(data.temperature);
float hum = data.humidity;
if (!isnan(temp) && !isnan(hum)) {
// B6. Cảnh báo
if (temp > 35) Serial.println("ALERT: HOT!");
// B7. Publish MQTT
mqtt.publish(topicTemp.c_str(), String(temp,2).c_str());
mqtt.publish(topicHum.c_str(), String(hum,2).c_str());
// B8. ThingSpeak
sendThingSpeak(temp, hum);
Serial.printf("PUB temp=%.2f hum=%.2f | WiFi:%s | MQTT:%s\n",
temp, hum,
WiFi.status()==WL_CONNECTED ? "connected":"disconnected",
mqtt.connected() ? "connected":"disconnected"
);
}
}
}