#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include "DHT.h"
#include <WiFi.h>
//#define DHTPIN 2
//#define DHTTYPE DHT22
//DHT dht(DHTPIN, DHTTYPE);
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define ON HIGH
#define OFF LOW
const int buttonSelect = 12; // button1 / Time push select >>> (buttonPlus++) (buttonMinus--) >>> hold 2sec >>> break;
const int buttonTimeAdjust = 13; // button2 / push select >>> (buttonPlus++) (buttonMinus--) >>> (buttonSelect) break out;
const int buttonPlus = 14; // button3 / push select >>> (buttonMinus ON) >>> (buttonSelect) break out;
const int buttonMinus = 27; // button4 / ปุ่มลดค่า / กดดู ค่าความชื้น และกดค้าง 2วิ เพื่อกลับเมนูหลัก
// กำหนดขาอนาล็อกสำหรับเซ็นเซอร์ทั้ง 3 ตัว วัดความชื้น
const int sensor1Pin = 34; // บรรทัดที่ 338 กำหนดขาของ ตัววัดความชื้น
const int sensor2Pin = 33;
//const int sensor3Pin = A7;
// ค่าช่วงอนาล็อกจากเซ็นเซอร์ (ปรับตามความเหมาะสม)
const int analogMin = 0; // ค่าต่ำสุด (แห้งมาก)
const int analogMax = 1023; // ค่าสูงสุด (เปียกมาก)
const int tankSw1 = 25; // รีเลย์ขา D3
const int tankSw2 = 32; // รีเลย์ขา D3
const int relayPinD5 = 4; // รีเลย์ขา D5
const int relayPinD6 = 5; // รีเลย์ขา D6
const int relayPinD7 = 15; // รีเลย์ขา D7
const int relayPinD8 = 16; // รีเลย์ขา D8
const int relayPinD9 = 17; // รีเลย์ขา D9
const int relayPinD10 = 18; // รีเลย์ขา D10
const int relayPinD11 = 19; // รีเลย์ขา D11
const int relayPinD12 = 23; // รีเลย์ขา D12
//const int relayPinD13 = 13; // รีเลย์ขา D13
const char* daysOfTheWeek[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
bool settingMode = false; // โหมดตั้งเวลา
int year = 2025, month = 1, day = 1, hour = 0, minute = 0, second = 0;
int currentStep = 0;
// กำหนดค่าเวลาของแต่ละรีเลย์ relayTime
unsigned long relayTime5 = 60000; // คนสาร
unsigned long relayTime6 = 15000; // ใส่สาร
unsigned long relayTime7 = 15000; // ใส่สาร
unsigned long relayTime8 = 15000; // ใส่สาร
unsigned long relayTime9 = 15000; // ผสมสาร
unsigned long relayTime10 = 15000; // รดน้ำ
unsigned long relayTime11 = 15000; // รดน้ำ
unsigned long relayTime12 = 15000; // รดน้ำ
//unsigned long relayTime13 = 15000; // รดน้ำ
unsigned long tankTime = 15000; // เวลาทำงานของ relay ในหน่วยมิลลิวินาที (10 วินาที)
// time start**********************************************************ถ้าปรับตรงนี้ ให้ปรับ relayTime ให้สัมพันธ์กันด้วย
int D6Day = 1 , D7Day = 3 , D8Day = 5 ; // วันที่ทำการใส่สาร
int D5Time1H = 8 , D5Time1M = 58 ; // กำหนดคนสารก่อนเติม ปุ๋ย (ถ้าจะตั้งต้องตั้งให้ลดไปข้างหน้าปรับตั้งไปข้างหลังจะกวน เติมสารจริง)
int D5Time2H = 15 , D5Time2M = 58 ; // น้ำส้มควันไม้
int D5Time3H = 8 , D5Time3M = 58 ; // EM
int D6StartH = 9 ; // เติม ปุ๋ย
int D7StartH = 16 ; // เติม น้ำส้มควันไม้
int D8StartH = 9 ; // เติม EM
//***********************************************************************
unsigned long lastRelayTimeD5 = 0; // กำหนดชื่อ
unsigned long lastRelayTimeD6 = 0;
unsigned long lastRelayTimeD7 = 0;
unsigned long lastRelayTimeD8 = 0;
unsigned long lastRelayTimeD9 = 0;
unsigned long lastRelayTimeD10 = 0;
unsigned long lastRelayTimeD11 = 0;
unsigned long lastRelayTimeD12 = 0;
//unsigned long lastRelayTimeD13 = 0;
unsigned long lastTankTime = 0;
bool relayD5State = false;
bool relayD6State = false;
bool relayD7State = false;
bool relayD8State = false;
bool relayD9State = false;
bool relayD10State = false;
bool relayD11State = false;
bool relayD12State = false;
//bool relayD13State = false;
bool tankState1 = false;
bool tankState2 = false;
float tempMin = 25.00, tempMax = 32.00;
float humiMin = 50.00, humiMax = 70.00;
float averagePercent = 0; // เปอร์เซ็นต์ ความชื้น
bool inSoilData = false;// เพิ่มเข้าไปในลูป soilData (วัดความชื้นในดิน)
bool buttonState = false; // ตัวแปรที่เก็บสถานะของปุ่ม (กด = true, ปล่อย = false)
bool inAdjustTimeMode = false; // สถานะโหมดปรับเวลา
int currentRelay2 = 5; // เริ่มต้นที่ Relay D5
bool inManualMode = false; // สถานะการอยู่ในโหมด Manual
// ตั้งค่าตัวแปรเวลา
int startM = 8, endM = 11; // เริ่มต้นเวลา และ หยุด ตอนเช้า
int startE = 15, endE = 18;// เวลาเริ่ม และหยุดตอนบ่าย
int tankOn = 0; // กำหนดการทำงานของ valve tank ใหญ่
//---------------------------------------------------------------------------------------------
void setup() {
Wire.begin();
Serial.begin(9600);
rtc.begin();
lcd.begin(16, 2);
//dht.begin();
lcd.backlight();
pinMode(buttonSelect, INPUT_PULLUP);
pinMode(buttonPlus, INPUT_PULLUP);
pinMode(buttonMinus, INPUT_PULLUP);
pinMode(buttonTimeAdjust, INPUT_PULLUP);
pinMode(tankSw1, OUTPUT);
pinMode(tankSw2, OUTPUT);
pinMode(relayPinD5, OUTPUT);
pinMode(relayPinD6, OUTPUT);
pinMode(relayPinD7, OUTPUT);
pinMode(relayPinD8, OUTPUT);
pinMode(relayPinD9, OUTPUT);
pinMode(relayPinD10, OUTPUT);
pinMode(relayPinD11, OUTPUT);
pinMode(relayPinD12, OUTPUT);
//pinMode(relayPinD13, OUTPUT);
digitalWrite(tankSw1,OFF);
digitalWrite(tankSw2,OFF);
digitalWrite(relayPinD5,OFF);
digitalWrite(relayPinD6,OFF);
digitalWrite(relayPinD7,OFF);
digitalWrite(relayPinD8,OFF);
digitalWrite(relayPinD9,OFF);
digitalWrite(relayPinD10,OFF);
digitalWrite(relayPinD11,OFF);
digitalWrite(relayPinD12,OFF);
//digitalWrite(relayPinD13,OFF);
// ปิด Wi-Fi
WiFi.mode(WIFI_OFF);
WiFi.disconnect(true); // ตัดการเชื่อมต่อทั้งหมดและล้างค่า
// ปิด Bluetooth
btStop();
lcd.print("RTC & LCD OK!");
delay(1500);
lcd.clear();
lcd.noBacklight();
}
//---------------------------------------------------------------------------------------------
void loop() {
DateTime now = rtc.now(); // รับเวลาปัจจุบันจาก RTC
// ตรวจสอบเวลาปัจจุบัน
int currentHour = now.hour();
int currentMinute = now.minute();
//---------------------------------------------
if (digitalRead(buttonMinus) == LOW) {
delay(200); // debounce
inSoilData = true; // เข้าสู่โหมด soilData
}
if (inSoilData) {
soilData();
}
//---------------------------------------------
if (digitalRead(buttonPlus) == LOW) {
delay(200); // debounce
inManualMode = true; // เข้าสู่โหมด Manual
currentRelay2 = 5; // เริ่มต้นที่ relay D5
}
if (inManualMode) {
Manual();
}
//---------------------------------------------
if (digitalRead(buttonTimeAdjust) == LOW) {
delay(200);
buttonState = true; // เปลี่ยนสถานะปุ่มเป็น true เมื่อกด
//delay(200);
}
if (buttonState) {
adjustRelayTime(); // เรียกฟังก์ชันปรับเวลารีเลย์เมื่อปุ่มถูกกด
}
//---------------------------------------------
if (inAdjustTimeMode) { // เช็คอยู่ในโหมดตั้งเวลาไหม ถ้าใช่ ให้เข้า adjustTime(); ถ้าไม่ใช่ (ถ้าเวลาตรงที่ตั้งไว้ ให้ใส่ on ถ้าไม่ให้ใส่ Sleep)
adjustTime();
} else {
displayTime();
if ((currentHour >= startM && currentHour < endM ) || (currentHour >= startE && currentHour < endE )) {
// ถ้าอยู่ในช่วงเวลาที่กำหนด ให้ทำการควบคุมรีเลย์
controlRelays();
lcd.setCursor(9, 1);lcd.print(" ON");
}else {lcd.setCursor(9, 1);lcd.print(" Sleep");}
}
}
//---------------------------------------------------------------------------------------------
void displayTime() {
DateTime now = rtc.now();
// แสดงวันในสัปดาห์
lcd.setCursor(0, 0);
// แสดงเวลา
if (now.hour() < 10) lcd.print("0"); // เติม 0 ถ้าน้อยกว่า 10
lcd.print(now.hour());
lcd.print(":");
if (now.minute() < 10) lcd.print("0"); // เติม 0 ถ้าน้อยกว่า 10
lcd.print(now.minute());
lcd.print(":");
if (now.second() < 10) lcd.print("0"); // เติม 0 ถ้าน้อยกว่า 10
lcd.print(now.second());
lcd.print(" ");
lcd.setCursor(0, 1);
// แสดงวันที่
if (now.month() < 10) lcd.print("0"); // เติม 0 ถ้าน้อยกว่า 10
lcd.print(now.month());
lcd.print("/");
if (now.day() < 10) lcd.print("0"); // เติม 0 ถ้าน้อยกว่า 10
lcd.print(now.day());
lcd.print(" ");
lcd.print(daysOfTheWeek[now.dayOfTheWeek()]); // ดึงค่าจาก RTC
if (digitalRead(buttonSelect) == LOW) {
delay(200);
inAdjustTimeMode = true; // กดเพื่อเข้าสู่โหมด adjustTime()
year = now.year();
month = now.month();
day = now.day();
hour = now.hour();
minute = now.minute();
second = now.second();
lcd.clear();
}
}
//---------------------------------------------------------------------------------------------
void adjustTime() {
lcd.clear();
inAdjustTimeMode = true; // เข้าสู่โหมดปรับเวลา
lcd.backlight();
while (inAdjustTimeMode) {
lcd.setCursor(0, 1);
// แสดงข้อมูลตามขั้นตอน
switch (currentStep) {
case 0: lcd.print("Year : "); lcd.print(year); lcd.print(" ");break;
case 1: lcd.print("Month : "); lcd.print(month); lcd.print(" "); break;
case 2: lcd.print("Day : "); lcd.print(day); lcd.print(" "); break;
case 3: lcd.print("Hour : "); lcd.print(hour); lcd.print(" "); break;
case 4: lcd.print("Minute: "); lcd.print(minute); lcd.print(" "); break;
case 5: lcd.print("Second: "); lcd.print(second); lcd.print(" "); break;
}
// ตรวจสอบปุ่ม Select สำหรับเปลี่ยนขั้นตอน
if (digitalRead(buttonSelect) == LOW) {
delay(200); // debounce
currentStep = (currentStep + 1) % 6;
lcd.clear();
}
// ปุ่ม Plus เพื่อเพิ่มค่า
if (digitalRead(buttonPlus) == LOW) {
incrementTime();
lcd.print(" "); // เคลียร์ตัวเลขเก่าที่เหลือ
delay(200); // debounce
}
// ปุ่ม Minus เพื่อลดค่า
if (digitalRead(buttonMinus) == LOW) {
decrementTime();
lcd.print(" "); // เคลียร์ตัวเลขเก่าที่เหลือ
delay(200); // debounce
}
// ปุ่ม Select กดค้างเพื่อยืนยันและบันทึกเวลา
if (digitalRead(buttonSelect) == LOW) {
unsigned long startTime = millis();
while (digitalRead(buttonSelect) == LOW) { // รอจนกว่าปุ่มจะปล่อย
if (millis() - startTime > 2000) { // ตรวจจับการกดค้าง 2 วินาที เพื่อออกจากโหมดนี้
rtc.adjust(DateTime(year, month, day, hour, minute, second)); // ตั้งค่าด้วย RTC
//lcd.clear();
lcd.print("Time Set!");
delay(1500);
inAdjustTimeMode = false; // ออกจากโหมดปรับเวลา
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Exit");
delay(500); // แสดงข้อความก่อนออกจากลูป
lcd.clear();
lcd.noBacklight();
}
}
}
}
}
//---------------------------------------------------------------------------------------------
void incrementTime() { // กำหนดช่วง ต่างๆของเวลา
switch (currentStep) {
case 0: year++; break;
case 1: month = (month % 12) + 1; break;
case 2: day = (day % 31) + 1; break;
case 3: hour = (hour + 1) % 24; break;
case 4: minute = (minute + 1) % 60; break;
case 5: second = (second + 1) % 60; break;
}
}
void decrementTime() { // กำหนดช่วง ต่างๆของเวลา
switch (currentStep) {
case 0: year--; break;
case 1: month = (month > 1) ? month - 1 : 12; break;
case 2: day = (day > 1) ? day - 1 : 31; break;
case 3: hour = (hour > 0) ? hour - 1 : 23; break;
case 4: minute = (minute > 0) ? minute - 1 : 59; break;
case 5: second = (second > 0) ? second - 1 : 59; break;
}
}
//###################################################################################################
void controlRelays() { // ควบคุมรีเลย์
DateTime now = rtc.now();
int currentDay = now.dayOfTheWeek();
int currentHour = now.hour();
int currentMinute = now.minute();
int currentSecond = now.second();
int ZoneRun = 0;
//************************************************************************************************************
if((currentHour == D5Time1H && currentMinute == D5Time1M && currentSecond < 2 ) ||
(currentHour == D5Time2H && currentMinute == D5Time2M && currentSecond < 2 )){
// อ่านค่าจากเซ็นเซอร์ทั้ง 3 ตัว
int sensor1Value = analogRead(sensor1Pin); //อ่านค่าจาก ตัววัดความชื้นของแต่ละตัว
int sensor2Value = analogRead(sensor2Pin);
//int sensor3Value = analogRead(sensor3Pin);
// แปลงค่าเป็นเปอร์เซ็นต์ (0% - 100%)
int sensor1Percent = map(sensor1Value, analogMin, analogMax, 0, 100); // เปอร์เซ็นของแต่ละตัว
int sensor2Percent = map(sensor2Value, analogMin, analogMax, 0, 100);
//int sensor3Percent = map(sensor3Value, analogMin, analogMax, 0, 100);
// คำนวณค่าเฉลี่ย (เปอร์เซ็นต์) //หาค่าเฉลี่ย ของตัววัดความชื้นทั้งหมด
//float averagePercent = (sensor1Percent );
averagePercent = (sensor1Percent + sensor2Percent) / 2.0;
//float averagePercent = (sensor1Percent + sensor2Percent + sensor3Percent) / 3.0;
lcd.setCursor(9, 0);lcd.print("H:");
lcd.print(averagePercent);
}
//************************************************************************************************************
// Relay ALL: LLLLLLLL ถ้าไม่ได้เติมสารให้เช็คเวลาและ ความชื้นอยู่ในเกณฑ์ที่กำหนดไหม ถ้าใช่ ให้รดน้ำ ไล่จาก zone1 ไปเลย LLLLLLLLLLLLLLLLLLLLLLLL
if ((digitalRead(relayPinD6) == OFF && digitalRead(relayPinD7) == OFF && digitalRead(relayPinD8) == OFF ) &&
((currentHour == D6StartH && currentMinute == 0 && currentSecond ==5 ) ||
(currentHour == D7StartH && currentMinute == 0 && currentSecond ==5 )) ) {
if( averagePercent >= humiMin && averagePercent <= humiMax ){
lcd.setCursor(9, 0);lcd.print("H:");
lcd.print(averagePercent);
ZoneRun = 2;
}
}
// Relay D5: 55555555555555555555555555555555555555555555555555555555 คนถังสารก่อนที่จะสูบลงถึงใหญ่ 5555555555555555555555555555555555
if ((currentDay == D6Day && currentHour == D5Time1H && currentMinute == D5Time1M && currentSecond < 2 ) || // ปุ๋ย 6
(currentDay == D7Day && currentHour == D5Time2H && currentMinute == D5Time2M && currentSecond < 2 ) || // น้ำส้มควันไม้ 7
(currentDay == D8Day && currentHour == D5Time3H && currentMinute == D5Time3M && currentSecond < 2 )){ // EM 8
if (!relayD5State) {
relayD5State = true;
digitalWrite(relayPinD5, ON);
lastRelayTimeD5 = millis();
}
} else if (digitalRead(relayPinD5) == ON && (unsigned long)(millis() - lastRelayTimeD5) >= relayTime5) {
relayD5State = false;
digitalWrite(relayPinD5, OFF);
}
// Relay D6: 666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 // ปุ๋ย
if (currentDay == 1 && currentHour == D6StartH && currentMinute == 0 && currentSecond == 0) {
if (!relayD6State) {
relayD6State = true;
digitalWrite(relayPinD6, ON);
lastRelayTimeD6 = millis();
}
} else if (digitalRead(relayPinD6) == ON && (unsigned long)(millis() - lastRelayTimeD6) >= relayTime6) {
relayD6State = false;
digitalWrite(relayPinD6, OFF);
ZoneRun = 1;
}
// Relay D7: 777777777777777777777777777777777777777777777777777777777777777777777777777777777777777 // น้ำส้มควันไม้
if (currentDay == 3 && currentHour == D7StartH && currentMinute == 0 && currentSecond == 0) {
if (!relayD7State) {
relayD7State = true;
digitalWrite(relayPinD7, ON);
lastRelayTimeD7 = millis();
}
} else if (digitalRead(relayPinD7) == ON && (unsigned long)(millis() - lastRelayTimeD7) >= relayTime7) {
relayD7State = false;
digitalWrite(relayPinD7, OFF);
ZoneRun = 1;
}
// Relay D8: 888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 // EM
if (currentDay == 5 && currentHour == D8StartH && currentMinute == 0 && currentSecond == 0) {
if (!relayD8State) {
relayD8State = true;
digitalWrite(relayPinD8, ON);
lastRelayTimeD8 = millis();
}
} else if (digitalRead(relayPinD8) == ON && (unsigned long)(millis() - lastRelayTimeD8) >= relayTime8) {
relayD8State = false;
digitalWrite(relayPinD8, OFF);
ZoneRun = 1;
}
// Relay D9: 9999999999999999999999999999999999 คนสารในถึงใหญ่ 9999999999999999999999999999999999999999999999999999999999
if ( ZoneRun == 1 ) {
if (!relayD9State) {
relayD9State = true;
digitalWrite(relayPinD9, ON);
lastRelayTimeD9 = millis();
}
} else if (digitalRead(relayPinD9) == ON && (unsigned long)(millis() - lastRelayTimeD9) >= relayTime9) {
relayD9State = false;
digitalWrite(relayPinD9, OFF);
ZoneRun = 2;
}
// Relay D10: 100000000000000000000000000000 รดน้ำ Zone 1 00000000000000000000000000000000000000000000000000000000
if ( ZoneRun == 2 ) {
if (!relayD10State) {
relayD10State = true;
digitalWrite(relayPinD10, ON);
lastRelayTimeD10 = millis();
tankOn = 1; // เมื่อเริ่มรดน้ำในแทงค์ใหญ่ ให้ปิดไม่ให้เติมน้ำลงแทงค์
}
} else if (digitalRead(relayPinD10) == ON && (unsigned long)(millis() - lastRelayTimeD10) >= relayTime10) {
relayD10State = false;
digitalWrite(relayPinD10, OFF);
}
// Relay D11: 111111111111111111111111111111 รดน้ำ Zone 2 111111111111111111111111111111111111111111111111111111111
if ( digitalRead(relayPinD10) == ON && (unsigned long)(millis() - lastRelayTimeD10) >= (relayTime10 - 5000) ) {
if (!relayD11State) {
relayD11State = true;
digitalWrite(relayPinD11, ON);
lastRelayTimeD11 = millis();
}
} else if (digitalRead(relayPinD11) == ON && (unsigned long)(millis() - lastRelayTimeD11) >= relayTime11) {
relayD11State = false;
digitalWrite(relayPinD11, OFF);
}
// Relay D12: 122222222222222222222222222222 รดน้ำ Zone 3 222222222222222222222222222222222222222222222222222222222
if ( digitalRead(relayPinD11) == ON && (unsigned long)(millis() - lastRelayTimeD11) >= (relayTime11 - 5000) ) {
if (!relayD12State) {
relayD12State = true;
digitalWrite(relayPinD12, ON);
lastRelayTimeD12 = millis();
}
} else if (digitalRead(relayPinD12) == ON && (unsigned long)(millis() - lastRelayTimeD12) >= relayTime12) {
relayD12State = false;
digitalWrite(relayPinD12, OFF);
ZoneRun = 0;
tankOn = 2; // เปิดป่๊มเติมแท้งค์ใหญ่
}
/*/ Relay D13: 13333333333333333333333333333 รดน้ำ Zone 4 33333333333333333333333333333333333333333333333333333333333
if ( digitalRead(relayPinD12) == ON && (unsigned long)(millis() - lastRelayTimeD12) >= (relayTime12 - 5000) ) {
if (!relayD13State) {
relayD13State = true;
digitalWrite(relayPinD13, ON);
lastRelayTimeD13 = millis();
}
} else if (digitalRead(relayPinD13) == ON && (unsigned long)(millis() - lastRelayTimeD13) >= relayTime13) {
relayD13State = false;
digitalWrite(relayPinD13, OFF);
ZoneRun = 0;
tankOn = 2; // เปิดป่๊มเติมแท้งค์ใหญ่
}*/
// Tank On / Off เวลารดน้ำ
if(tankOn == 1 && digitalRead(tankSw1) == OFF) { // ปิดน้ำเข้าแทงค์เวลา รดน้ำ
//if (!tankState1) {
//tankState1 = true;
digitalWrite(tankSw1, ON);
lastTankTime = millis();
//}
}else if (digitalRead(tankSw1) == ON && (unsigned long)(millis() - lastTankTime) >= tankTime) {
//tankState1 = false;
digitalWrite(tankSw1, OFF);
tankOn = 0; // เปิดป่๊มเติมแท้งค์ใหญ่
}
if(tankOn == 2 && digitalRead(tankSw2) == OFF) { // เปิดน้ำเข้าแทงค์เวลารดน้ำเสร็จ
//if (!tankState2) {
//tankState2 = true;
digitalWrite(tankSw2, ON);
lastTankTime = millis();
//}
}else if (digitalRead(tankSw2) == ON && (unsigned long)(millis() - lastTankTime) >= tankTime) {
//tankState2 = false;
digitalWrite(tankSw2, OFF);
tankOn = 0; // เปิดป่๊มเติมแท้งค์ใหญ่
}
}
//###################################################################################################
void adjustRelayTime() { // ปรับเวลา รีเลย์เพื่อให้ทำงานตามที่ต้องการ
static int currentRelay = 0; // ตัวแปรสำหรับเก็บสถานะรีเลย์ปัจจุบัน (0 = D5, 1 = D6, ..., 8 = D13)
unsigned long *relayTimes[] = {&relayTime5, &relayTime6, &relayTime7, &relayTime8, &relayTime9, &relayTime10,
&relayTime11, &relayTime12/*, &relayTime13*/}; // อาร์เรย์ของ pointer
lcd.backlight();
lcd.clear();
while (true) { // แสดงข้อมูลของรีเลย์ปัจจุบัน
lcd.setCursor(0, 0);
// แสดงชื่อของรีเลย์ที่กำลังปรับ
lcd.print("Relay: D");
lcd.print(5 + currentRelay); // D5 ถึง D13
lcd.print(" ");
// แสดงเวลาที่ปรับได้สำหรับรีเลย์ที่เลือก
lcd.setCursor(0, 1);
lcd.print("Time: ");
lcd.print(*relayTimes[currentRelay] / 1000); // แสดงเวลาเป็นวินาที
lcd.print(" sec ");
// ตรวจจับปุ่ม + เพิ่มเวลา
if (digitalRead(buttonPlus) == LOW) {
*relayTimes[currentRelay] += 1000; // เพิ่มเวลา 1 วินาที
delay(200); // debounce
}
// ตรวจจับปุ่ม - ลดเวลา
if (digitalRead(buttonMinus) == LOW) {
if (*relayTimes[currentRelay] > 1000) { // ลดเวลา 1 วินาที แต่ไม่ต่ำกว่า 1 วินาที
*relayTimes[currentRelay] -= 1000;
}
delay(200); // debounce
}
// ตรวจจับปุ่ม Select เพื่อเปลี่ยนรีเลย์ที่ต้องการตั้งค่า
if (digitalRead(buttonTimeAdjust) == LOW) {
currentRelay = (currentRelay + 1) % 8; // หมุนวนระหว่าง D5 ถึง D13
delay(200);
}
// ปุ่ม Exit เพื่อออกจากโหมด
if (digitalRead(buttonSelect) == LOW) {
delay(200); // debounce
buttonState = false; // เปลี่ยนสถานะปุ่มเป็น false เมื่อกด
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Exit");
delay(500); // แสดงข้อความก่อนออกจากลูป
lcd.clear();
lcd.noBacklight();
break; // ออกจากลูป while
}
}
}
//---------------------------------------------------------------------------------------------
// ฟังก์ชันนับเวลาถอยหลัง
void countdownTimer(int relayPin, int durationInSeconds) {
for (int i = durationInSeconds; i >= 0; i--) {
lcd.setCursor(0, 1);
lcd.print("Time: ");
lcd.print(i);
lcd.print(" sec ");
delay(1000);
}
digitalWrite(relayPin, OFF); // ปิด relay หลังจากหมดเวลา
lcd.setCursor(0, 1);
lcd.print("Status: OFF ");
}
// เวลาถอยหลังสำหรับแต่ละ relay (กำหนดเวลาเป็นวินาที)
int relayTime[15] = {0, 0, 0, 0, 0, relayTime5/1000, relayTime6/1000, relayTime7/1000,
relayTime8/1000, relayTime9/1000, relayTime10/1000, relayTime11/1000, relayTime12/1000/*, relayTime13/1000*/
, tankSw1/1000, tankSw2/1000};
//**********************************************************************************************************************
// แก้ไขการใช้ relayTime เป็น pointer แบบเดียวกับ adjustRelayTime()
void Manual() {
lcd.clear();
lcd.backlight();
unsigned long *relayTimes[] = {&relayTime5, &relayTime6, &relayTime7, &relayTime8, &relayTime9, &relayTime10,
&relayTime11, &relayTime12, /*&relayTime13 ,*/&tankTime ,&tankTime}; // อาร์เรย์ของ pointer
while (true) { // วนอยู่ในโหมด Manual ตลอดเวลา
// แสดงตำแหน่งของ relay ปัจจุบันบน LCD
lcd.setCursor(0, 0);
if(currentRelay2 ==13 ){ // sw tank 1
lcd.print("Relay: D" + String(currentRelay2));
lcd.print(" Sw1"); // แสดงเลข relay ที่กำลังควบคุม
}else if(currentRelay2 ==14 ){ // sw tank 2
lcd.print("Relay: D" + String(currentRelay2));
lcd.print(" Sw2"); // แสดงเลข relay ที่กำลังควบคุม
}else{lcd.print("Relay: D" + String(currentRelay2));
} // แสดงเลข relay ที่กำลังควบคุม}
lcd.print(" ");
// ตรวจสอบปุ่ม Minus เพื่อเปิด/ปิด relay พร้อมเริ่มนับเวลาถอยหลัง
if (digitalRead(buttonMinus) == LOW) {
delay(200); // debounce
// สลับสถานะของ relay ที่เลือก
switch (currentRelay2) {
case 5:
digitalWrite(relayPinD5, ON);
countdownTimer(relayPinD5, *relayTimes[0]/1000); // ใช้ relayTimes[0] เพื่ออ้างอิงค่า relayTime5
break;
case 6:
digitalWrite(relayPinD6, ON);
countdownTimer(relayPinD6, *relayTimes[1]/1000); // ใช้ relayTimes[1] เพื่ออ้างอิงค่า relayTime6
break;
case 7:
digitalWrite(relayPinD7, ON);
countdownTimer(relayPinD7, *relayTimes[2]/1000); // ใช้ relayTimes[2] เพื่ออ้างอิงค่า relayTime7
break;
case 8:
digitalWrite(relayPinD8, ON);
countdownTimer(relayPinD8, *relayTimes[3]/1000); // ใช้ relayTimes[3] เพื่ออ้างอิงค่า relayTime8
break;
case 9:
digitalWrite(relayPinD9, ON);
countdownTimer(relayPinD9, *relayTimes[4]/1000); // ใช้ relayTimes[4] เพื่ออ้างอิงค่า relayTime9
break;
case 10:
digitalWrite(relayPinD10, ON);
countdownTimer(relayPinD10, *relayTimes[5]/1000); // ใช้ relayTimes[5] เพื่ออ้างอิงค่า relayTime10
break;
case 11:
digitalWrite(relayPinD11, ON);
countdownTimer(relayPinD11, *relayTimes[6]/1000); // ใช้ relayTimes[6] เพื่ออ้างอิงค่า relayTime11
break;
case 12:
digitalWrite(relayPinD12, ON);
countdownTimer(relayPinD12, *relayTimes[7]/1000); // ใช้ relayTimes[7] เพื่ออ้างอิงค่า relayTime12
break;
/*case 13:
digitalWrite(relayPinD13, ON);
countdownTimer(relayPinD13, *relayTimes[8]/1000); // ใช้ relayTimes[8] เพื่ออ้างอิงค่า relayTime13
break;*/
case 13:
digitalWrite(tankSw1, ON);
countdownTimer(tankSw1, *relayTimes[9]/1000); // ใช้ relayTimes[8] เพื่ออ้างอิงค่า relayTime13
break;
case 14:
digitalWrite(tankSw2, ON);
countdownTimer(tankSw2, *relayTimes[10]/1000); // ใช้ relayTimes[8] เพื่ออ้างอิงค่า relayTime13
break;
}
}
// ถ้ากดปุ่ม Plus เพื่อเปลี่ยนหน้า relay
if (digitalRead(buttonPlus) == LOW) {
delay(200); // debounce
currentRelay2++; // ไปยัง relay ถัดไป
if (currentRelay2 > 14) {
currentRelay2 = 5; // กลับไปที่ D5 เมื่อถึง D13
}
}
// ตรวจสอบปุ่มเพื่อออกจากโหมด Manual
if (digitalRead(buttonSelect) == LOW) {
delay(200); // debounce
inManualMode = false; // ออกจากโหมด Manual
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Exit");
delay(1000); // แสดงข้อความ 1 วินาที
lcd.clear();
lcd.noBacklight();
break; // ออกจากลูป while
}
// ใช้ delay(100) เพื่อให้โปรแกรมไม่ทำงานอย่างรวดเร็วเกินไป
delay(100); // รอ 100ms ก่อนทำงานใหม่
}
}
//-------------------------------------------------------------------------------------------
void soilData() {
lcd.clear();
inSoilData = true; // เข้าสู่โหมดปรับเวลา
lcd.backlight();
while (inSoilData) {
// อ่านค่าจากเซ็นเซอร์ทั้ง 3 ตัว
int sensor1Value = analogRead(sensor1Pin);
int sensor2Value = analogRead(sensor2Pin);
//int sensor3Value = analogRead(sensor3Pin);
// แปลงค่าเป็นเปอร์เซ็นต์ (0% - 100%)
int sensor1Percent = map(sensor1Value, analogMin, analogMax, 0, 100);
int sensor2Percent = map(sensor2Value, analogMin, analogMax, 0, 100);
//int sensor3Percent = map(sensor3Value, analogMin, analogMax, 0, 100);
// คำนวณค่าเฉลี่ย (เปอร์เซ็นต์)
//float averagePercent = (sensor1Percent );
averagePercent = (sensor1Percent + sensor2Percent) / 2.0;
//float averagePercent = (sensor1Percent + sensor2Percent + sensor3Percent) / 3.0;
lcd.setCursor(0, 0);
lcd.print("S1>");
lcd.print(sensor1Percent);
lcd.print("%");
lcd.setCursor(9, 0);
lcd.print("S2>");
lcd.print(sensor2Percent);
lcd.print("%");
/*lcd.setCursor(0, 1);
lcd.print("S3>");
lcd.print(" ");
lcd.print("%");*/
lcd.blink();
lcd.setCursor(3, 1);
lcd.print("AV:");
lcd.print(averagePercent);
delay(1000);
// ปุ่ม Exit เพื่อออกจากโหมดปรับเวลา
if (digitalRead(buttonMinus) == LOW) {
delay(200); // debounce
unsigned long startTime = millis();
while (digitalRead(buttonMinus) == LOW) { // รอจนกว่าปุ่มจะปล่อย
if (millis() - startTime > 2000) { // ตรวจจับการกดค้าง 2 วินาที
inSoilData = false; // ออกจากโหมดปรับเวลา
lcd.clear();
lcd.noBlink(); // ปิดการกระพริบ
lcd.setCursor(6, 0);
lcd.print("Exit");
delay(2000); // แสดงข้อความก่อนออกจากลูป
lcd.clear();
lcd.setCursor(9, 0);lcd.print("H:");
lcd.print(averagePercent);
lcd.noBacklight();
}
}
}
}
}
//---------------------------------------------------------------------------------------------Loading
esp32-devkit-c-v4
esp32-devkit-c-v4