#define BLYNK_TEMPLATE_ID "TMPL6YU7qPUiH"
#define BLYNK_TEMPLATE_NAME "nongtraiCopyCopy"
#define BLYNK_AUTH_TOKEN "4A8ryPnQdxTvHZgz4H-FtZm419Zpjh2d"
#define DOAMDAT A0
#include <DHT.h>
#include <Wire.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <HTTPClient.h>
#include <WiFiClient.h>
#include <Adafruit_GFX.h>
#include <BlynkSimpleEsp32.h>
#include <Adafruit_SSD1306.h>
char auth[] = "4A8ryPnQdxTvHZgz4H-FtZm419Zpjh2d";
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
String Web_App_URL = "https://script.google.com/macros/s/AKfycby8Uv2cdQhvYDqSvpAYLSCRQN1vFz_th9fXyT7hqHSJ5Dzj-G6wEsBcOwgdR9R7Af5SjQ/execs";
#define On_Board_LED_PIN 2
#define DHTPIN 4
#define DHTTYPE DHT11 // DHT 11
#define DOAMDAT 36 // Cảm biến độ ẩm đất LM393
DHT dht(DHTPIN, DHTTYPE);
#define SCREEN_WIDTH 128 // OLED display width
#define SCREEN_HEIGHT 64 // OLED display height
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int button_chedo = 26;
int button_bomtuoi = 27;
int button_den = 14;
int button_ra = 12;
int button_vao = 13;
int relay_bomtuoi = 19;
int relay_den = 18;
int relay_ra = 5;
int relay_vao = 15;
#define NHIETDO V0
#define DOAM V1
#define CHEDO V2
#define RELAY V3
#define DOAM_BAT V4
#define DOAM_TAT V5
#define RELAY_RA V6
#define RELAY_VAO V7
#define DEN V9
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 7 * 60 * 60); // UTC+7, giờ Việt Nam
int autoOnHour = 18;
int autoOnMinute = 0;
int autoOffHour = 10;
int autoOffMinute = 30;
float tempHigh = 36.0; // Giá trị nhiệt độ cao để bật relay_ra
float tempLow = 33.0; // Giá trị nhiệt độ thấp để bật relay_vao
int doam_bat = 30; // Giá trị độ ẩm đất để bắt đầu tưới
int doam_tat = 80; // Giá trị độ ẩm đất để dừng tưới
boolean chedo_hoatdong = false;
int autoModeState = 0;
int relay_bomtuoi_State = LOW;
int relay_ra_State = LOW; // Trạng thái ban đầu của relay_ra
int relay_vao_State = LOW; // Trạng thái ban đầu của relay_vao
int relay_den_State = LOW;
String Status_Read_Sensor = "";
String Maiche_State = "";
String Den_State = "";
String Bom_State = "";
float Temp;
int Humd;
BLYNK_WRITE(V9) {
if (chedo_hoatdong) {
relay_den_State = param.asInt();
digitalWrite(relay_den, relay_den_State);
Serial.println("Chế độ Thủ công: Đang " + String(relay_den_State ? "BẬT" : "TẮT") + " đèn");
}
}
BLYNK_WRITE(V7) {
if (chedo_hoatdong) {
relay_vao_State = param.asInt();
if (relay_vao_State == HIGH) { // Khi relay_vao bật thì relay_ra sẽ tắt
relay_ra_State = LOW;
digitalWrite(relay_ra, relay_ra_State);
Blynk.virtualWrite(V6, relay_ra_State); // Đồng bộ trạng thái của relay_ra với V6 trên Blynk
}
digitalWrite(relay_vao, relay_vao_State);
Serial.println("Chế độ Thủ công: Đang " + String(relay_vao_State ? "BẬT" : "TẮT") + " relay_vao");
}
}
BLYNK_WRITE(V6) {
if (chedo_hoatdong) {
relay_ra_State = param.asInt();
if (relay_ra_State == HIGH) { // Khi relay_ra bật thì relay_vao sẽ tắt
relay_vao_State = LOW;
digitalWrite(relay_vao, relay_vao_State);
Blynk.virtualWrite(V7, relay_vao_State); // Đồng bộ trạng thái của relay_vao với V7 trên Blynk
}
digitalWrite(relay_ra, relay_ra_State);
Serial.println("Chế độ Thủ công: Đang " + String(relay_ra_State ? "BẬT" : "TẮT") + " relay_ra");
}
}
BLYNK_WRITE(V3) {
if (chedo_hoatdong) {
relay_bomtuoi_State = param.asInt();
digitalWrite(relay_bomtuoi, relay_bomtuoi_State);
Serial.println("Chế độ Thủ công: Đang " + String(relay_bomtuoi_State ? "BẬT" : "TẮT") + " bom tưới");
} else {
Blynk.virtualWrite(V3, relay_bomtuoi_State); // Cập nhật trạng thái của relay_bomtuoi trên Blynk
}
}
BLYNK_WRITE(V2) {
autoModeState = param.asInt();
Blynk.virtualWrite(CHEDO, autoModeState); // Cập nhật trạng thái của nút chế độ trên Blynk
Serial.println("Nút V2 được nhấn! Chế độ Tự động: " + String(autoModeState));
if (autoModeState == 0) {
chedo_hoatdong = false;
Serial.println("Chế độ hoạt động: Tự động");
} else {
chedo_hoatdong = true;
Serial.println("Chế độ hoạt động: Thủ công");
Serial.println("Trạng thái đèn: " + String(relay_den_State ? "BẬT" : "TẮT")); // Hiển thị trạng thái đèn
}
}
BLYNK_WRITE(DOAM_BAT){
doam_bat = param.asInt();
Serial.println("Độ ẩm MIN: " + String(doam_bat) + "%");
}
BLYNK_WRITE(DOAM_TAT){
doam_tat = param.asInt();
Serial.println("Độ ẩm MAX: " + String(doam_tat) + "%");
}
BLYNK_CONNECTED() {
Blynk.virtualWrite(V2, autoModeState);
Blynk.virtualWrite(V3, relay_bomtuoi_State);
Blynk.virtualWrite(V6, relay_ra_State);
Blynk.virtualWrite(V7, relay_vao_State);
Blynk.virtualWrite(V9, relay_den_State);
}
void setup() {
Serial.begin(115200);
Serial.println();
delay(1000);
Blynk.begin(auth, ssid, pass);
//----------------------------------------Set Wifi to STA mode
Serial.println();
Serial.println("-------------");
Serial.println("WIFI mode : STA");
WiFi.mode(WIFI_STA);
Serial.println("-------------");
Serial.println();
Serial.println("------------");
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, pass);
int connecting_process_timed_out = 20; //--> 20 = 20 seconds.
connecting_process_timed_out = connecting_process_timed_out * 2;
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
digitalWrite(On_Board_LED_PIN, HIGH);
delay(250);
digitalWrite(On_Board_LED_PIN, LOW);
delay(250);
if (connecting_process_timed_out > 0) connecting_process_timed_out--;
if (connecting_process_timed_out == 0) {
delay(1000);
ESP.restart();
}
}
digitalWrite(On_Board_LED_PIN, LOW);
Serial.println();
Serial.println("WiFi connected");
Serial.println("------------");
delay(100);
pinMode(DOAMDAT, INPUT); // Khai báo DOAMDAT là INPUT
pinMode(relay_bomtuoi, OUTPUT); // Khai báo relay_bomtuoi là OUTPUT
pinMode(relay_ra, OUTPUT); // Khai báo relay_ra là OUTPUT
pinMode(relay_vao, OUTPUT); // Khai báo relay_vao là OUTPUT
pinMode(relay_den, OUTPUT);
pinMode(On_Board_LED_PIN, OUTPUT);
pinMode(button_chedo, INPUT_PULLUP);
pinMode(button_bomtuoi, INPUT_PULLUP); // Khai báo button_bomtuoi là nút nhấn
pinMode(button_ra, INPUT_PULLUP); // Khai báo button_ra là nút nhấn
pinMode(button_vao, INPUT_PULLUP); // Khai báo button_vao là nút nhấn
pinMode(button_den, INPUT_PULLUP); // Khai báo button_den là nút nhấn
// Bắt đầu ở chế độ auto
chedo_hoatdong = false;
Blynk.virtualWrite(CHEDO, autoModeState); // Cập nhật trạng thái của nút chế độ trên Blynk
Blynk.virtualWrite(V2, autoModeState); // Cập nhật trạng thái chế độ trên Blynk
Blynk.virtualWrite(V3, relay_bomtuoi_State); // Cập nhật trạng thái của relay_bomtuoi trên Blynk
timeClient.begin();
// Khởi tạo màn hình OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Địa chỉ I2C 0x3C
Serial.println(F("SH1106 allocation failed"));
for(;;);
}
delay(1000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Đang thử kết nối lại WiFi...");
Blynk.connectWiFi(ssid, pass);
}
if (!Blynk.connected()) {
Serial.println("Đang thử kết nối lại Blynk...");
Blynk.connect();
}
Blynk.run();
timeClient.update();
float t = dht.readTemperature();
Blynk.virtualWrite(V0, t); // Gửi giá trị nhiệt độ lên chân V0 trên Blynk
Serial.println("Nhiệt độ hiện tại: " + String(t) + " °C"); // Hiển thị nhiệt độ lên Serial Monitor
int doamdat = analogRead(DOAMDAT); // Đọc giá trị độ ẩm đất từ cảm biến LM393
doamdat = constrain(doamdat, 0, 4095);
int percent = map(doamdat, 0, 4095, 100, 0); // Chuyển đổi giá trị đọc được thành phần trăm
Blynk.virtualWrite(V1, percent); // Gửi giá trị độ ẩm đất lên chân V1 trên Blynk
Serial.println("Độ ẩm đất hiện tại: " + String(percent) + " %"); // Hiển thị độ ẩm đất lên Serial Monitor
int hours = timeClient.getHours();
int minutes = timeClient.getMinutes();
int seconds = timeClient.getSeconds();
Temp = digitalRead(t);
Humd = digitalRead(percent);
//________________________________________________________________________________
if (isnan(percent) || isnan(t)) {
Serial.println();
Serial.println(F("Failed to read from DHT sensor!"));
Serial.println();
Status_Read_Sensor = "Failed";
t = 0.00;
percent = 0;
} else {
Status_Read_Sensor = "Success";
}
if (digitalRead(relay_bomtuoi_State) == LOW) Bom_State = "Tắt";
if (digitalRead(relay_bomtuoi_State) == HIGH) Bom_State = "Bật";
if (digitalRead(relay_den_State) == LOW) Den_State = "Tắt";
if (digitalRead(relay_den_State) == HIGH) Den_State = "Bật";
if (relay_ra_State == HIGH && relay_vao_State == LOW) {
Maiche_State = "Ra";
} else if (relay_ra_State == LOW && relay_vao_State == HIGH) {
Maiche_State = "Vào";
} else if (relay_ra_State == LOW && relay_vao_State == LOW) {
Maiche_State = "Dừng";
}
//________________________________________________________________________________
if (WiFi.status() == WL_CONNECTED) {
digitalWrite(On_Board_LED_PIN, HIGH);
String Send_Data_URL = Web_App_URL + "?sts=write";
Send_Data_URL += "&srs=" + Status_Read_Sensor;
Send_Data_URL += "&temp=" + String(Temp);
Send_Data_URL += "&humd=" + String(Humd);
Send_Data_URL += "&bom=" + Bom_State;
Send_Data_URL += "&den=" + Den_State;
Send_Data_URL += "&maiche=" + Maiche_State;
Serial.println();
Serial.println("-------------");
Serial.println("Send data to Google Spreadsheet...");
Serial.print("URL : ");
Serial.println(Send_Data_URL);
delay(1000);
HTTPClient http;
http.begin(Send_Data_URL.c_str());
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
int httpCode = http.GET();
Serial.print("HTTP Status Code : ");
Serial.println(httpCode);
String payload;
if (httpCode > 0) {
payload = http.getString();
Serial.println("Payload : " + payload);
}
http.end();
digitalWrite(On_Board_LED_PIN, LOW);
Serial.println("-------------");
}
//----------------------------------------
delay(1000);
//________________________________________________________________________________
display.clearDisplay();
// Hiển thị thời gian thực
display.setCursor(42, 0);
char buffer[9];
sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
display.println(buffer);
// Hiển thị thông tin cá nhân
display.setCursor(10, 9); // Đặt con trỏ tại vị trí ngay dưới thời gian
display.println("PHAM NGOC TUAN K18");
// Hiển thị trạng thái các relay
display.setCursor(16, 21); // Đặt con trỏ tại vị trí dòng đầu tiên
display.println("Che do: " + String(chedo_hoatdong ? "THU CONG" : "TU DONG"));
display.setCursor(6, 32);
relay_bomtuoi_State = digitalRead(relay_bomtuoi);
display.println("Bom: " + String(relay_bomtuoi_State ? "ON" : "OFF"));
display.setCursor(61, 32);
relay_den_State = digitalRead(relay_den);
display.println("- Den: " + String(relay_den_State ? "ON" : "OFF"));
if (relay_ra_State == HIGH && relay_vao_State == LOW) {
display.setCursor(17, 42);
display.println(" Mai che [ RA ]");
} else if (relay_ra_State == LOW && relay_vao_State == HIGH) {
display.setCursor(17, 42);
display.println(" Mai che [ VAO ]");
} else if (relay_ra_State == LOW && relay_vao_State == LOW) {
display.setCursor(15, 42);
display.println("Mai che [ DUNG ]");
}
display.setCursor(0,54);
display.println("T: " + String(t) + " *C");
display.setCursor(68,54);
display.println("- H: " + String(percent) + " %");
display.display();
if (digitalRead(button_chedo) == LOW) {
changeMode();
}
if (chedo_hoatdong && digitalRead(button_den) == LOW) {
relay_den_State = !relay_den_State; // Đảo trạng thái của relay_den
digitalWrite(relay_den, relay_den_State); // Cập nhật trạng thái của relay_den
Blynk.virtualWrite(V9, relay_den_State); // Cập nhật trạng thái của V9 trên Blynk
}
if (chedo_hoatdong && digitalRead(button_bomtuoi) == LOW) {
relay_bomtuoi_State = !relay_bomtuoi_State; // Đảo trạng thái của relay_bomtuoi
digitalWrite(relay_bomtuoi, relay_bomtuoi_State); // Cập nhật trạng thái của relay_bomtuoi
Blynk.virtualWrite(V3, relay_bomtuoi_State); // Cập nhật trạng thái của relay_bomtuoi trên Blynk
}
if (!chedo_hoatdong) {
int currentHour = timeClient.getHours();
int currentMinute = timeClient.getMinutes();
/*if ((currentHour > autoOnHour || (currentHour == autoOnHour && currentMinute >= autoOnMinute)) &&
(currentHour < autoOffHour || (currentHour == autoOffHour && currentMinute < autoOffMinute))) { // cùng giờ khác phút*/
if ((currentHour >= autoOnHour && currentMinute >= autoOnMinute) ||
(currentHour < autoOffHour || (currentHour == autoOffHour && currentMinute < autoOffMinute))) {// khác giờ khác phút
digitalWrite(relay_den, HIGH);
Blynk.virtualWrite(V9, 1);
} else {
digitalWrite(relay_den, LOW);
Blynk.virtualWrite(V9, 0);
}
}
if (chedo_hoatdong) {
if (digitalRead(button_ra) == LOW) {
relay_ra_State = !relay_ra_State;
relay_vao_State = LOW;
digitalWrite(relay_ra, relay_ra_State);
digitalWrite(relay_vao, relay_vao_State);
Blynk.virtualWrite(V6, relay_ra_State);
Blynk.virtualWrite(V7, relay_vao_State);
}
if (digitalRead(button_vao) == LOW) {
relay_vao_State = !relay_vao_State;
relay_ra_State = LOW;
digitalWrite(relay_vao, relay_vao_State);
digitalWrite(relay_ra, relay_ra_State);
Blynk.virtualWrite(V7, relay_vao_State);
Blynk.virtualWrite(V6, relay_ra_State);
}
}
// Kiểm tra nhiệt độ và điều khiển relay
if (!chedo_hoatdong) { // Chỉ kiểm tra nhiệt độ khi ở chế độ tự động
if (t > tempHigh) {
relay_ra_State = HIGH; // Bật relay_ra
relay_vao_State = LOW; // Tắt relay_vao
digitalWrite(relay_ra, relay_ra_State); // Cập nhật trạng thái của relay_ra
digitalWrite(relay_vao, relay_vao_State); // Cập nhật trạng thái của relay_vao
Blynk.virtualWrite(V6, relay_ra_State); // Cập nhật trạng thái của relay_ra trên Blynk
Blynk.virtualWrite(V7, relay_vao_State); // Cập nhật trạng thái của relay_vao trên Blynk
} else if (t <= tempLow) {
relay_ra_State = LOW; // Tắt relay_ra
relay_vao_State = HIGH; // Bật relay_vao
digitalWrite(relay_ra, relay_ra_State); // Cập nhật trạng thái của relay_ra
digitalWrite(relay_vao, relay_vao_State); // Cập nhật trạng thái của relay_vao
Blynk.virtualWrite(V6, relay_ra_State); // Cập nhật trạng thái của relay_ra trên Blynk
Blynk.virtualWrite(V7, relay_vao_State); // Cập nhật trạng thái của relay_vao trên Blynk
}
}
if (!chedo_hoatdong) { // Chỉ kiểm tra độ ẩm đất khi ở chế độ tự động
if (percent <= doam_bat && ((hours >= 17 && minutes >= 0 && seconds >= 0) || (hours <= 8 && minutes <= 0 && seconds <= 0))) {
relay_bomtuoi_State = HIGH; // Bật relay_bomtuoi
digitalWrite(relay_bomtuoi, relay_bomtuoi_State); // Cập nhật trạng thái của relay_bomtuoi
Blynk.virtualWrite(V3, relay_bomtuoi_State); // Cập nhật trạng thái của relay_bomtuoi trên Blynk
} else if (percent >= doam_tat) {
relay_bomtuoi_State = LOW; // Tắt relay_bomtuoi
digitalWrite(relay_bomtuoi, relay_bomtuoi_State); // Cập nhật trạng thái của relay_bomtuoi
Blynk.virtualWrite(V3, relay_bomtuoi_State); // Cập nhật trạng thái của relay_bomtuoi trên Blynk
}
}
}
void connectToWiFi() {
while (WiFi.status() != WL_CONNECTED) {
WiFi.begin(ssid, pass);
Serial.print("Attempting to connect to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
}
}
void checkWiFiConnection() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi connection lost. Reconnecting...");
connectToWiFi(); // Gọi hàm kết nối Wi-Fi của bạn ở đây
// Nếu sau một thời gian mà vẫn không kết nối được, thực hiện reset ESP32
unsigned long currentMillis = millis();
static unsigned long previousMillis = 0;
if (currentMillis - previousMillis >= 30000) { // Reset sau mỗi 30 giây (có thể điều chỉnh)
ESP.restart();
}
}
}
//________________________________________________________________________________
//________________________________________________________________________________
void checkBlynkConnection() {
if (!Blynk.connected()) {
Serial.println("Blynk connection lost. Reconnecting...");
Blynk.connect(); // Cố gắng kết nối lại Blynk
}
}
void changeMode() {
chedo_hoatdong = !chedo_hoatdong;
Blynk.virtualWrite(CHEDO, chedo_hoatdong ? 1 : 0);
Blynk.virtualWrite(V2, chedo_hoatdong ? 1 : 0);
Serial.println("Nút chế độ được nhấn! Chế độ hoạt động: " + String(chedo_hoatdong ? "Thủ công" : "Tự động"));
}