// --- Cấu hình các thư viện cần thiết ---
#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
#include <BlynkSimpleEsp32.h>
#include <FirebaseESP32.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
// --- Thông tin mạng WiFi ---
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// --- Blynk ---
#define BLYNK_TEMPLATE_ID "TMPL6vTZ3uUW8"
#define BLYNK_TEMPLATE_NAME "tuoicay"
#define BLYNK_AUTH_TOKEN "px9iSj2o_dGgxPDUr3_rUR5ax8mOuY9d" // Thay bằng token thật
// --- Firebase ---
#define FIREBASE_HOST "https://tuoicay-429c3-default-rtdb.asia-southeast1.firebasedatabase.app/"
#define FIREBASE_AUTH "YFmDGfUGFf5pRKRxo7Ok12A2i8icWlEoGJBSWwIx" // Thay bằng Firebase secret
FirebaseData fbdo;
FirebaseConfig config;
FirebaseAuth auth;
// --- Cảm biến ---
#define DHTPIN 25
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#define SOIL_MOISTURE_PIN 34
// --- Relay tưới ---
#define RELAY_PIN 13
// --- Time API ---
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 7 * 3600, 60000); // GMT+7
// --- OpenWeather API ---
String weatherApiKey = "7bd25a0b9c36259584d79274b99fba71";
String city = "Hanoi";
String weatherUrl = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "&appid=" + weatherApiKey + "&units=metric";
// --- Biến điều khiển ---
bool manualMode = false;
bool watering = false;
// --- Blynk control ---
BLYNK_WRITE(V0) {
manualMode = param.asInt();
if (manualMode) {
digitalWrite(RELAY_PIN, LOW);
watering = true;
delay(5000);
digitalWrite(RELAY_PIN, HIGH);
watering = false;
}
}
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH);
dht.begin();
WiFi.begin(ssid, password);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password);
config.api_key = FIREBASE_AUTH;
config.database_url = FIREBASE_HOST;
Firebase.begin(&config, &auth);
Firebase.reconnectWiFi(true);
timeClient.begin();
}
bool isRaining() {
HTTPClient http;
http.begin(weatherUrl);
int httpCode = http.GET();
bool rain = false;
if (httpCode == 200) {
String payload = http.getString();
if (payload.indexOf("rain") > 0) {
rain = true;
}
}
http.end();
return rain;
}
void logToFirebase(float temp, float hum, int soil) {
String path = "/log/" + String(millis());
Firebase.setFloat(fbdo, path + "/temp", temp);
Firebase.setFloat(fbdo, path + "/hum", hum);
Firebase.setInt(fbdo, path + "/soil", soil);
Firebase.setString(fbdo, path + "/time", timeClient.getFormattedTime());
}
void loop() {
Blynk.run();
timeClient.update();
float temp = dht.readTemperature();
float hum = dht.readHumidity();
int soil = analogRead(SOIL_MOISTURE_PIN);
bool rain = isRaining();
int hour = timeClient.getHours();
// Tự động tưới nếu đất khô và không mưa
if (soil > 3000 && !rain && !watering) {
digitalWrite(RELAY_PIN, LOW);
watering = true;
delay(5000);
digitalWrite(RELAY_PIN, HIGH);
watering = false;
logToFirebase(temp, hum, soil);
}
// Tưới theo lịch: 6h hoặc 18h mỗi ngày
if ((hour == 6 || hour == 18) && !watering) {
digitalWrite(RELAY_PIN, LOW);
watering = true;
delay(5000);
digitalWrite(RELAY_PIN, HIGH);
watering = false;
logToFirebase(temp, hum, soil);
}
delay(10000); // Lặp mỗi 10s
}