#define BLYNK_TEMPLATE_ID "TMPL6sCEZP0m_"
#define BLYNK_TEMPLATE_NAME "Quickstart Template"
#define BLYNK_AUTH_TOKEN "A7OYlDmWKKliPzzFmu6PUGFeUw9jWyCX"
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// WiFi
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
// DHT22
#define DHTPIN 15
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// LCD
LiquidCrystal_I2C lcd(0x27,16,2);
// Button
#define BUTTON_PIN 14
// LDR
#define LDR_PIN 34
// LED & Buzzer
#define LEDPIN 2
#define BUZZER_PIN 16
bool ledStateManual = false; // สถานะ LED จาก Blynk
// Blynk Timer
BlynkTimer timer;
// ค่าเก็บสถิติวันนี้
float tempMin = 100;
float tempMax = -100;
float tempSum = 0;
int tempCount = 0;
float tempNow = 0;
// สถานะการรดน้ำ
bool watering = false;
unsigned long wateringStart = 0;
const unsigned long wateringDuration = 5000; // 5 วินาที
// === ฟังก์ชันเตือนด้วย LED/Buzzer และ LCD ===
void alarmCheck(float temp) {
static bool ledState = false;
static unsigned long lastToggle = 0;
if (temp > 30) {
if (millis() - lastToggle >= 500) {
ledState = !ledState;
digitalWrite(LEDPIN, ledState || ledStateManual);
lastToggle = millis();
}
digitalWrite(BUZZER_PIN, HIGH);
if (!watering) {
lcd.setCursor(0, 1);
lcd.print("Watering too high!!");
}
// --- ระบบรดน้ำอัตโนมัติถ้า temp > 40 ---
if (temp > 40 && !watering) {
watering = true;
wateringStart = millis();
lcd.setCursor(0, 1);
lcd.print("Watering... ");
Blynk.virtualWrite(V5, 1); // เปิดปุ่ม Blynk ให้ ON
}
} else {
digitalWrite(LEDPIN, ledStateManual ? HIGH : LOW);
digitalWrite(BUZZER_PIN, LOW);
// ปุ่ม Blynk ปิดเองเมื่ออุณหภูมิปกติ ≤40
if (watering == false) {
Blynk.virtualWrite(V5, 0);
}
if (!watering) {
lcd.setCursor(0, 1);
lcd.print("Temperature good");
}
}
}
// === อ่านค่าเซ็นเซอร์และอัปเดตสถิติ ===
void readSensor() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
int light = analogRead(LDR_PIN);
if (isnan(temp) || isnan(hum)) {
Serial.println("❌ DHT error!");
return;
}
if (temp < tempMin) tempMin = temp;
if (temp > tempMax) tempMax = temp;
tempSum += temp;
tempCount++;
tempNow = temp;
float tempAvg = tempSum / tempCount;
if (!watering && temp <= 30) {
lcd.setCursor(0, 0);
lcd.print("T:"); lcd.print(tempNow,1); lcd.print("C Now");
lcd.setCursor(0, 1);
lcd.print("Min:"); lcd.print(tempMin,0);
lcd.print(" Max:"); lcd.print(tempMax,0);
}
alarmCheck(tempNow);
Blynk.virtualWrite(V4, digitalRead(LEDPIN)); // LED
Blynk.virtualWrite(V8, temp);
Blynk.virtualWrite(V9, hum);
Blynk.virtualWrite(V10, light);
Blynk.virtualWrite(V21, light); // LDR
Serial.print("Temp:"); Serial.print(temp);
Serial.print(" Hum:"); Serial.print(hum);
Serial.print(" LDR:"); Serial.println(light);
}
// === ปุ่มกด ESP32 ===
void checkButton() {
static int lastState = HIGH;
int state = digitalRead(BUTTON_PIN);
if (lastState == HIGH && state == LOW) {
watering = true;
wateringStart = millis();
lcd.setCursor(0, 1);
lcd.print("Watering... ");
}
lastState = state;
}
// === อัปเดตสถานะการรดน้ำ ===
void updateWatering() {
if (watering && millis() - wateringStart >= wateringDuration) {
watering = false;
// ปิดปุ่ม Blynk V5 อัตโนมัติหลังรดน้ำเสร็จ
Blynk.virtualWrite(V5, 0);
}
}
// === Blynk LED Handler ===
BLYNK_WRITE(V4) {
int val = param.asInt();
digitalWrite(LEDPIN, val);
ledStateManual = val;
}
// === Blynk Button Handler V5 ===
BLYNK_WRITE(V5) {
int val = param.asInt();
if (val == 1) { // กดปุ่ม
watering = true;
wateringStart = millis();
lcd.setCursor(0, 1);
lcd.print("Watering... ");
}
}
void setup() {
Serial.begin(115200);
dht.begin();
pinMode(LEDPIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
lcd.init();
lcd.backlight();
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
readSensor(); // อ่านค่าทันทีตอนเริ่ม
timer.setInterval(5000L, readSensor);
timer.setInterval(200L, checkButton);
timer.setInterval(200L, updateWatering);
}
void loop() {
Blynk.run();
timer.run();
}