#include <Wire.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width
#define SCREEN_HEIGHT 64 // OLED display height
#define OLED_RESET -1 // No reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RTC_DS3231 rtc;
const int pwmPin1 = 19;
const int ledcChannel1 = 0;
const int pwmPin2 = 18; // New PWM pin
const int ledcChannel2 = 1; // New LEDC channel
const int freq = 5000;
const int resolution = 8;
int start_time_hour = 6;
int start_time_minute = 0;
int end_time_hour = 1;
int end_time_minute = 0;
int end_time2_hour = 17; // New end time 2
int end_time2_minute = 50;
int fade_duration = 15; // in minutes
int pwm_delay = 5; // Delay for the second PWM, in minutes
int time_shorten = 60; // Time shorten duration in minutes
const int switchPin = 25; // GPIO pin for the switch
bool switchState = false;
bool lastSwitchState = false;
bool adjustmentMade = false;
DateTime lastAdjustmentDay;
DateTime original_end_time;
void setup() {
Serial.begin(9600);
Wire.begin(23, 22); // SDA, SCL
rtc.begin();
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.display();
delay(2000);
pinMode(switchPin, INPUT_PULLUP); // Initialize the switch pin
lastAdjustmentDay = rtc.now();
original_end_time = DateTime(lastAdjustmentDay.year(), lastAdjustmentDay.month(), lastAdjustmentDay.day(), end_time_hour, end_time_minute, 0);
ledcSetup(ledcChannel1, freq, resolution);
ledcAttachPin(pwmPin1, ledcChannel1);
ledcWrite(ledcChannel1, 255);
ledcSetup(ledcChannel2, freq, resolution);
ledcAttachPin(pwmPin2, ledcChannel2);
ledcWrite(ledcChannel2, 255);
}
void loop() {
DateTime now = rtc.now();
DateTime start_time = DateTime(now.year(), now.month(), now.day(), start_time_hour, start_time_minute, 0);
static DateTime end_time = DateTime(now.year(), now.month(), now.day(), end_time_hour, end_time_minute, 0);
DateTime end_time2 = DateTime(now.year(), now.month(), now.day(), end_time2_hour, end_time2_minute, 0);
// Read the switch state
switchState = digitalRead(switchPin);
// Check if it's the start time of the day and if adjustment hasn't been made yet
if (now >= start_time && !adjustmentMade) {
if (switchState && !lastSwitchState) {
// Decrease end time by 1 hour each day until it reaches end_time2
if (end_time - TimeSpan(1, 0, 0, 0) >= end_time2) {
end_time = end_time - TimeSpan(1, 0, 0, 0); // Decrease by 1 hour
} else {
end_time = end_time2; // Set to end_time2 if it's less than an hour away
}
adjustmentMade = true;
} else {
// Reset end_time to original value if switch is not toggled
end_time = original_end_time;
}
}
// Reset adjustment flag at the end of the day
if (now.hour() == 23 && now.minute() == 59) {
adjustmentMade = false;
}
lastSwitchState = switchState; // Update the last switch state
// PWM and OLED update logic
int pwm_value1 = calculatePWM1(now.unixtime(), start_time.unixtime(), end_time.unixtime(), fade_duration * 60);
ledcWrite(ledcChannel1, pwm_value1);
int pwm_value2 = calculatePWM2(now.unixtime(), start_time.unixtime(), end_time.unixtime(), fade_duration * 60, pwm_delay * 60);
ledcWrite(ledcChannel2, pwm_value2);
updateOLED(now, start_time_hour, start_time_minute, end_time, fade_duration, pwm_delay, pwm_value1, pwm_value2, switchState, time_shorten, end_time2);
delay(1000);
}
int calculatePWM1(long current, long start, long end, long duration) {
if (current >= start && current < start + duration) {
return map(current - start, 0, duration, 255, 0);
} else if (current >= end - duration && current < end) {
return map(current - (end - duration), 0, duration, 0, 255);
} else if (current >= start + duration && current < end - duration) {
return 0;
}
return 255;
}
int calculatePWM2(long current, long start, long end, long duration, long delay) {
if (current >= start + delay && current < start + duration + delay) {
return map(current - start - delay, 0, duration, 255, 0);
} else if (current >= end - duration - delay && current < end - delay) {
return map(current - (end - duration - delay), 0, duration, 0, 255);
} else if (current >= start + duration + delay && current < end - duration - delay) {
return 0;
}
return 255;
}
void updateOLED(const DateTime& now, int startHour, int startMinute, const DateTime& currentEndTime, int fadeDuration, int led2Delay, int pwm1, int pwm2, bool switchState, int timeShorten, const DateTime& end_time2) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.print("Time: ");
display.print(now.hour());
display.print(":");
display.println(now.minute());
display.print("Start: ");
display.print(startHour);
display.print(":");
display.println(startMinute);
display.print("End: ");
display.print(currentEndTime.hour());
display.print(":");
display.println(currentEndTime.minute());
display.print("Fade:");
display.print(fadeDuration);
display.print("min ");
display.print("Delay:");
display.print(led2Delay);
display.println("min");
display.print("PWM1: ");
display.print(pwm1);
display.print(" ");
display.print("PWM2: ");
display.println(pwm2);
display.print("Switch: ");
display.println(switchState ? "Veg" : "Flow");
display.print("Shorten: ");
display.print(timeShorten);
display.println("min");
DateTime nextDayEndTime = currentEndTime;
if (switchState) {
if (nextDayEndTime - TimeSpan(1, 0, 0, 0) >= end_time2) {
nextDayEndTime = nextDayEndTime - TimeSpan(1, 0, 0, 0); // Decrease by 1 hour
} else {
nextDayEndTime = end_time2; // Set to end_time2 if it's less than an hour away
}
}
display.print("Next End: ");
display.print(nextDayEndTime.hour());
display.print(":");
display.println(nextDayEndTime.minute());
display.display();
}