#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define START_BUTTON_PIN 2
#define LED_PIN 4
#define START_BUTTON_PIN_2 5
#define LED_PIN_2 18
#define SCREEN_ADDRESS_1 0x3C
#define SCREEN_ADDRESS_2 0x3D
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RTC_DS3231 rtc;
class GrowSystem {
public:
DateTime endTime;
TimeSpan countdownDuration;
bool countdownStarted;
bool countdownOver;
DateTime lastUpdateTime;
DateTime ledStartTime;
bool ledOn;
TimeSpan ledOnDuration;
TimeSpan ledOffDuration;
int startButtonPin;
int ledPin;
Adafruit_SSD1306* display;
String itemName;
String floorName;
GrowSystem(TimeSpan countdown, TimeSpan ledOn, TimeSpan ledOff, int startPin, int ledPinNum, Adafruit_SSD1306* disp, String item, String floor)
: countdownDuration(countdown), ledOnDuration(ledOn), ledOffDuration(ledOff),
startButtonPin(startPin), ledPin(ledPinNum), display(disp), itemName(item), floorName(floor) {
countdownStarted = false;
countdownOver = false;
ledOn = false;
}
void startCountdown() {
countdownStarted = true;
countdownOver = false;
DateTime now = rtc.now();
endTime = now + countdownDuration;
ledStartTime = now;
ledOn = true;
digitalWrite(ledPin, HIGH);
display->clearDisplay();
display->setCursor(0, 0);
display->println("Countdown started!");
display->display();
Serial.println("Countdown started!");
delay(1000);
}
void updateOLEDDisplay() {
DateTime now = rtc.now();
TimeSpan timeLeft = endTime - now;
int days = timeLeft.days();
int hours = timeLeft.hours();
int minutes = timeLeft.minutes();
int seconds = timeLeft.seconds();
display->clearDisplay();
display->setTextSize(1);
display->setCursor(0, 0);
display->println(itemName + " can eat in:");
display->setTextSize(2);
display->setCursor(0, 16);
display->printf("%02d:%02d", minutes, seconds);
display->setTextSize(1);
display->setCursor(0, 40);
display->printf("Total: %02dD %02dH", days, hours);
display->setCursor(0, 56);
display->println(floorName);
display->display();
Serial.printf("%s: %02d:%02d Total: %02dD %02dH\n", itemName.c_str(), minutes, seconds, days, hours);
}
void updateLED() {
DateTime now = rtc.now();
TimeSpan elapsedTime = now - ledStartTime;
if (ledOn && elapsedTime.totalseconds() >= ledOnDuration.totalseconds()) {
digitalWrite(ledPin, LOW);
ledOn = false;
ledStartTime = now;
Serial.println("LED turned off");
} else if (!ledOn && elapsedTime.totalseconds() >= ledOffDuration.totalseconds()) {
digitalWrite(ledPin, HIGH);
ledOn = true;
ledStartTime = now;
Serial.println("LED turned on");
}
}
void finishCountdown() {
countdownStarted = false;
countdownOver = true;
digitalWrite(ledPin, LOW);
display->clearDisplay();
display->setTextSize(2);
display->setCursor(0, 0);
display->println("Time's up!");
display->setTextSize(1);
display->setCursor(0, 24);
display->println(itemName + " is ready");
display->setCursor(0, 40);
display->println("Press to restart");
display->display();
Serial.println("Countdown finished. Time's up!");
}
void resetSystem() {
countdownStarted = false;
countdownOver = false;
digitalWrite(ledPin, LOW);
display->clearDisplay();
display->setTextSize(1);
display->setCursor(0, 0);
display->println(floorName + ":");
display->setTextSize(2);
display->setCursor(0, 16);
display->println("What to");
display->setCursor(0, 32);
display->println("grow?");
display->setTextSize(1);
display->setCursor(0, 56);
display->println("Press to start");
display->display();
Serial.println("System reset");
}
bool debounceButton(int pin) {
if (digitalRead(pin) == LOW) {
delay(50);
if (digitalRead(pin) == LOW) {
return true;
}
}
return false;
}
};
GrowSystem system1(TimeSpan(45, 0, 0, 0), TimeSpan(0, 12, 0, 0), TimeSpan(0, 12, 0, 0), START_BUTTON_PIN, LED_PIN, &display, "Tomato", "Floor 1"); //ใส่ข้อมูลผักชั้น 1 OLED นับเวลถอยหลัง 45 วัน , LED สว่าง 12 ชั่วโมง , ดับ 12 ชั่วโมง
GrowSystem system2(TimeSpan(45, 0, 0, 0), TimeSpan(0, 12, 0, 0), TimeSpan(0, 12, 0, 0), START_BUTTON_PIN_2, LED_PIN_2, &display2, "Egg", "Floor 2"); //ใส่ข้อมูลผักชั้น 2 OLED นับเวลถอยหลัง 45 วัน , LED สว่าง 12 ชั่วโมง , ดับ 12 ชั่วโมง
const TimeSpan updateInterval = TimeSpan(0, 0, 0, 1); // Update every 1 second
void setup() {
Serial.begin(115200);
pinMode(START_BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
pinMode(START_BUTTON_PIN_2, INPUT_PULLUP);
pinMode(LED_PIN_2, OUTPUT);
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, lets set the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS_1)) {
Serial.println(F("SSD1306 #1 allocation failed"));
for(;;);
}
if(!display2.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS_2)) {
Serial.println(F("SSD1306 #2 allocation failed"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display2.clearDisplay();
display2.setTextSize(1);
display2.setTextColor(SSD1306_WHITE);
system1.resetSystem();
system2.resetSystem();
}
void loop() {
if (!system1.countdownStarted && !system1.countdownOver && system1.debounceButton(system1.startButtonPin)) {
system1.startCountdown();
}
if (!system2.countdownStarted && !system2.countdownOver && system2.debounceButton(system2.startButtonPin)) {
system2.startCountdown();
}
DateTime now = rtc.now();
if (system1.countdownStarted) {
if ((now - system1.lastUpdateTime).totalseconds() >= updateInterval.totalseconds()) {
system1.updateOLEDDisplay();
system1.lastUpdateTime = now;
}
system1.updateLED();
if (now >= system1.endTime) {
system1.finishCountdown();
}
} else if (system1.countdownOver && system1.debounceButton(system1.startButtonPin)) {
system1.resetSystem();
}
if (system2.countdownStarted) {
if ((now - system2.lastUpdateTime).totalseconds() >= updateInterval.totalseconds()) {
system2.updateOLEDDisplay();
system2.lastUpdateTime = now;
}
system2.updateLED();
if (now >= system2.endTime) {
system2.finishCountdown();
}
} else if (system2.countdownOver && system2.debounceButton(system2.startButtonPin)) {
system2.resetSystem();
}
}