#define BLYNK_TEMPLATE_ID "TMPL6stBsu1Gs"
#define BLYNK_TEMPLATE_NAME "Watering"
#define BLYNK_AUTH_TOKEN "Gf65yv1pGjWpXlgFjkZRy49Gh-8xxSMp"
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
/* กำหนดค่า DHT Sensor */
#define DHTTYPE DHT22
#define DHT_READ_PIN 15
DHT dht(DHT_READ_PIN, DHTTYPE);
BlynkTimer timer;
WidgetRTC server_rtc;
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
char auth[] = BLYNK_AUTH_TOKEN; // เพิ่มตัวแปร auth ที่ขาดไป
/* กำหนด Pin */
#define VALVE_1_OUT 2 // Relay 1 (D2)
#define VALVE_2_OUT 4 // เพิ่มการกำหนดขา Relay 2 (เช่น D4)
#define MOISURE_READ 34 // Potentiometer (D34)
// กำหนดสถานะ Relay (ปกติ Relay Module มักจะเป็น Active Low)
#define VALVE_ON 1
#define VALVE_OFF 0
/* กำหนด Virtual Pin */
#define BLYNK_TEMP V0
#define BLYNK_RH V1
#define BLYNK_SOIL_MOISTURE V2
#define BLYNK_VALVE_1 V3
#define BLYNK_VALVE_2 V4 // เพิ่ม V-Pin สำหรับ Valve 2
#define BLYNK_TIMER_1 V5 // ตรวจสอบให้ตรงกับใน App
#define BLYNK_TIMER_2 V6
// ตัวแปรต่างๆ
int soil_moisture;
long rtc_sec_server;
unsigned char weekday_server;
unsigned char start_time_hour_1, start_time_min_1, stop_time_hour_1, stop_time_min_1, day_timer_1;
bool flag_timer1_en, flag_timer_on_valve_1;
unsigned char start_time_hour_2, start_time_min_2, stop_time_hour_2, stop_time_min_2, day_timer_2;
bool flag_timer2_en, flag_timer_on_valve_2;
bool flag_valve_1_set, flag_valve_2_set;
bool flag_valve_1_status, flag_valve_2_status;
bool flag_blynk_valve_1_update, flag_blynk_valve_2_update;
BLYNK_CONNECTED() {
Blynk.syncAll();
server_rtc.begin();
}
// รับค่าจากปุ่ม Valve 1
BLYNK_WRITE (BLYNK_VALVE_1) {
flag_valve_1_set = param.asInt();
Serial.print("Valve 1 Manual Clicked: "); Serial.println(flag_valve_1_set);
}
// รับค่าจากปุ่ม Valve 2
BLYNK_WRITE (BLYNK_VALVE_2) {
flag_valve_2_set = param.asInt();
Serial.print("Valve 2 Manual Clicked: "); Serial.println(flag_valve_2_set);
}
// รับค่าจาก Time Input 1
BLYNK_WRITE(BLYNK_TIMER_1) {
TimeInputParam t(param);
if (t.hasStartTime() && t.hasStopTime()) {
start_time_hour_1 = t.getStartHour();
start_time_min_1 = t.getStartMinute();
stop_time_hour_1 = t.getStopHour();
stop_time_min_1 = t.getStopMinute();
day_timer_1 = 0;
for (int i = 1; i <= 7; i++) {
if (t.isWeekdaySelected(i)) day_timer_1 |= (0x01 << (i-1));
}
flag_timer1_en = 1;
} else {
flag_timer1_en = 0;
}
}
void fn_valve_mng (void) {
long start_timer_sec, stop_timer_sec;
bool time_set_overflow;
// --- Logic Valve 1 ---
start_timer_sec = start_time_hour_1*3600 + start_time_min_1*60;
stop_timer_sec = stop_time_hour_1*3600 + stop_time_min_1*60;
time_set_overflow = (stop_timer_sec < start_timer_sec);
if (flag_timer1_en && (((time_set_overflow == 0 && (rtc_sec_server >= start_timer_sec) && (rtc_sec_server < stop_timer_sec)) ||
(time_set_overflow && ((rtc_sec_server >= start_timer_sec) || (rtc_sec_server < stop_timer_sec)))) &&
(day_timer_1 == 0x00 || (day_timer_1 & (0x01 << (weekday_server - 1))))))
{
flag_timer_on_valve_1 = 1;
} else {
flag_timer_on_valve_1 = 0;
}
// รวมสถานะ: ถ้าตั้งเวลาเปิดอยู่ หรือ กดปุ่ม Manual ไว้ ให้ Relay ทำงาน
bool new_status_1 = flag_timer_on_valve_1 || flag_valve_1_set;
if(new_status_1 != flag_valve_1_status) {
flag_valve_1_status = new_status_1;
flag_blynk_valve_1_update = 1; // ส่งสถานะกลับไปบอก App
}
// ควบคุม Hardware (Active Low)
digitalWrite(VALVE_1_OUT, flag_valve_1_status ? VALVE_ON : VALVE_OFF);
digitalWrite(VALVE_2_OUT, flag_valve_2_set ? VALVE_ON : VALVE_OFF); // คุมง่ายๆ สำหรับตัวที่ 2
}
void RTC_mng(void) {
if (year() != 1970) { // ตรวจสอบว่าเวลาถูก sync แล้ว
weekday_server = weekday();
if (weekday_server == 1) weekday_server = 7; // ปรับให้จันทร์=1 อาทิตย์=7 ตาม logic เดิม
else weekday_server -= 1;
rtc_sec_server = (hour()*3600) + (minute()*60) + second();
}
}
void update_blynk_data(void) {
float h = dht.readHumidity();
float t = dht.readTemperature();
// อ่านค่าดิบจาก Analog Pin (ESP32 มีความละเอียด 12-bit หรือ 0-4095)
int raw_moisture = analogRead(MOISURE_READ);
// แก้ไขบรรทัดนี้: เปลี่ยนจาก 0, 100 เป็น 0, 1023
int prc_moisture = map(raw_moisture, 0, 4095, 0, 1023);
Blynk.virtualWrite(BLYNK_TEMP, t);
Blynk.virtualWrite(BLYNK_RH, h);
Blynk.virtualWrite(BLYNK_SOIL_MOISTURE, prc_moisture);
if (flag_blynk_valve_1_update) {
Blynk.virtualWrite(BLYNK_VALVE_1, flag_valve_1_status);
flag_blynk_valve_1_update = 0;
}
}
void setup() {
Serial.begin(115200);
Blynk.begin(auth, ssid, pass);
dht.begin();
pinMode(VALVE_1_OUT, OUTPUT);
pinMode(VALVE_2_OUT, OUTPUT);
digitalWrite(VALVE_1_OUT, VALVE_OFF);
digitalWrite(VALVE_2_OUT, VALVE_OFF);
timer.setInterval(1000L, RTC_mng);
timer.setInterval(1000L, fn_valve_mng);
timer.setInterval(2000L, update_blynk_data);
}
void loop() {
Blynk.run();
timer.run();
}