#include <WiFi.h>
#include <time.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Arduino.h>
#include <ESP32Time.h>
#include "AudioTools.h"
#include "AudioLibs/AudioSourceSDFAT.h"
#include "AudioCodecs/CodecMP3Helix.h"
// OLED display width and height, for a typical SSD1306 OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define buzzerPin 26
#define LEDPin 5 //16
#define RPin 3
#define GPin 17
#define BPin 16
// Replace with your network credentials
const char* ssid = "IrishJs-2.4g";
const char* password = "11IrishJs";
const char *startFilePath = "/";
const char* ext = "mp3";
const int touchPins[] = {T4, T6, T0, T5, T3};
const int OLEDAddress = 0x3C; // I2C address for oled display
// Daylight saving offset (in seconds)
const int daylightOffset_sec = 3600;
// Timezone offset in seconds (e.g., -5 * 3600 for EST)
const long gmtOffset_sec = 0;
volatile bool update = true; //flag for updateing oled
volatile int counter = 0; //counter so it connects to the internet every 10 mins
bool wifiStatus = false;
bool ledOn = true;
bool alarmOn = false; //wether the alarm is sounding or not
bool alarmSet = true; //wether the alarm is set or not
bool changing = false; //flag for stopping the time from blinking while you increase or decrease the mins or hours
bool twelveHour = false; //wether twelve hour mode or not
String mode = "time"; //mode of display ("time" for normal mode or "alarm" to set the alarm)
int screenMode = 0; //which submode you are on
//default times
int Dsec = 0;
int Dmin = 0;
int Dhour = 0;
int Dday = 1;
int Dmonth = 1;
int Dyear = 2024;
//alarm times
int alarmHour = 7;
int alarmMin = 0;
//colours
int RShade = 0;
int GShade = 0;
int BShade = 0;
//volume (not currently used)
float volume = 1.00;
AudioSourceSDFAT source(startFilePath, ext);
I2SStream i2s;
MP3DecoderHelix decoder;
AudioPlayer player(source, i2s, decoder);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
hw_timer_t *timer = NULL; // Timer object
//ESP32Time rtc;
ESP32Time rtc(0);
void printMetaData(MetaDataType type, const char* str, int len) {
Serial.print("==> ");
Serial.print(toStr(type));
Serial.print(": ");
Serial.println(str);
}
//called twice every second
void IRAM_ATTR onTimer() {
update = true;
++counter;
}
//updates time variables
void updateTimes() {
Dsec = rtc.getSecond();
Dmin = rtc.getMinute();
Dhour = rtc.getHour(true);
Dday = rtc.getDay();
Dmonth = rtc.getMonth() + 1;
Dyear = rtc.getYear();
}
//updates led
void updateLed() {
// if (ledOn) {
// analogWrite(RPin, RShade);
// analogWrite(GPin, GShade);
// analogWrite(BPin, BShade);
// } else {
// analogWrite(RPin, 0);
// analogWrite(GPin, 0);
// analogWrite(BPin, 0);
// }
}
//updates display
void updateOLED() {
//print time and date
Serial.println(rtc.getTimeDate(true));
//clear the display
display.clearDisplay();
//display on time mode
if (mode == "time") {
display.setCursor(0, 0);
display.setTextSize(2);
if (!(int(millis() / 500) % 2 == 0 && screenMode == 1) || changing) {
updateTimes();
if (twelveHour) {
display.print(rtc.getTime("%I"));
} else {
display.print(rtc.getTime("%H"));
}
} else {
display.print(" ");
}
display.print(":");
if (!(int(millis() / 500) % 2 == 0 && screenMode == 2) || changing) {
display.print(rtc.getTime("%M"));
} else {
display.print(" ");
}
display.print(":");
if (!(int(millis() / 500) % 2 == 0 && screenMode == 3) || changing) {
display.print(rtc.getTime("%S"));
} else {
display.print(" ");
}
if (twelveHour) {
display.print(rtc.getAmPm(true));
}
display.setCursor(0, 30);
display.setTextSize(2);
if (screenMode != 6) {
display.print(rtc.getTime("%a "));
}
if ((!(int(millis() / 500) % 2 == 0 && screenMode == 4) || changing) && screenMode != 6) {
display.print(rtc.getTime("%b "));
} else {
display.print(" ");
}
if ((!(int(millis() / 500) % 2 == 0 && screenMode == 5) || changing) && screenMode != 6) {
display.print(rtc.getDay());
}
if ((!(int(millis() / 500) % 2 == 0 && screenMode == 6) || changing) && screenMode == 6) {
display.setCursor(0, 30);
display.setTextSize(2);
display.print(rtc.getYear());
}
}
//display on alarm mode
else if (mode == "alarm") {
display.setCursor(0, 0);
display.setTextSize(3);
if (!(int(millis() / 500) % 2 == 0 && screenMode == 1) || changing) {
if (alarmHour < 10) {
display.print("0");
display.print(alarmHour);
} else {
display.print(alarmHour);
}
} else {
display.setCursor(36, 0);
}
display.print(":");
if (!(int(millis() / 500) % 2 == 0 && screenMode == 2) || changing) {
if (alarmMin < 10) {
display.print("0");
display.print(alarmMin);
} else {
display.print(alarmMin);
}
}
}
//display on led mode
else if (mode == "led") {
if (screenMode == 0) {
display.setCursor(0, 0);
display.setTextSize(2);
display.print("R:");
display.println(RShade);
display.print("G:");
display.println(GShade);
display.print("B:");
display.println(BShade);
}
if (screenMode == 1) {
display.setCursor(0, 0);
display.setTextSize(4);
display.print("R:");
display.println(RShade);
}
if (screenMode == 2) {
display.setCursor(0, 0);
display.setTextSize(4);
display.print("G:");
display.println(GShade);
}
if (screenMode == 3) {
display.setCursor(0, 0);
display.setTextSize(4);
display.print("B:");
display.println(BShade);
}
}
//display A if alarm set
if (alarmSet) {
display.setTextSize(1);
display.setCursor(0, 50);
display.print("A");
}
//display LED if led on
if (ledOn) {
display.setTextSize(1);
display.setCursor(10, 50);
display.print("LED ");
}
//display WiFi if WiFi connected
if (wifiStatus) {
display.setTextSize(1);
display.setCursor(40, 50);
display.print("WiFi");
}
//show the changes
display.display();
//turn buzzer on if time
if (rtc.getHour(true) == alarmHour && rtc.getMinute() == alarmMin && !rtc.getSecond() && alarmSet && !alarmOn) {
alarmOn = true;
player.play();
}
}
void setup() {
Serial.begin(115200);
// Initialize OLED display
if (!display.begin(SSD1306_SWITCHCAPVCC, OLEDAddress)) { // Check your OLED address, usually 0x3C or 0x3D
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
for (int i = 0; i < 20; ++i) {
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi connected.");
wifiStatus = true;
break;
}
delay(500);
Serial.print(".");
}
if (!wifiStatus) {
Serial.println("could not connect to wifi.");
WiFi.disconnect();
rtc.setTime(Dsec, Dmin, Dhour, Dday, Dmonth, Dyear); // 17th Jan 2021 15:24:30
}
// Init and get the time
if (wifiStatus) {
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org", "time.nist.gov");
}
// Wait for time to be set
delay(2000);
pinMode(buzzerPin, OUTPUT);
pinMode(RPin, OUTPUT);
pinMode(BPin, OUTPUT);
pinMode(GPin, OUTPUT);
analogReadResolution(12);
timer = timerBegin(0, 80, true); // Use timer 0, prescaler 80, counting up
timerAttachInterrupt(timer, &onTimer, true); // Attach the interrupt
timerAlarmWrite(timer, 500000, true); // Set the alarm for 1 minute (60,000,000 microseconds)
timerAlarmEnable(timer); // Enable the timer alarm
//start audio
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = i2s.defaultConfig(TX_MODE);
cfg.pin_bck = 26;
cfg.pin_ws = 25;
cfg.pin_data = 17;
i2s.begin(cfg);
player.setMetadataCallback(printMetaData);
player.begin();
player.stop();
}
void loop() {
//change time modes
if (touchRead(touchPins[2]) <= 40 && mode == "time") {
++screenMode;
//reset screenMode if greater than 6
if (screenMode >= 6) {
screenMode = 0;
}
while (touchRead(touchPins[2]) <= 40);
}
//change alarm modes
if (touchRead(touchPins[2]) <= 40 && mode == "alarm") {
++screenMode;
//reset screenMode if greater than 2
if (screenMode > 2) {
screenMode = 0;
}
while (touchRead(touchPins[2]) <= 40);
}
//change led modes
if (touchRead(touchPins[2]) <= 40 && mode == "led") {
++screenMode;
//reset screenMode if greater than 3
if (screenMode >= 3) {
screenMode = 0;
}
while (touchRead(touchPins[2]) <= 40);
}
//increase led brightness
if (touchRead(touchPins[3]) <= 40 && mode == "led") {
changing = false;
while (touchRead(touchPins[3]) <= 40) {
if (RShade < 255 && screenMode == 1) {
++RShade;
}
if (GShade < 255 && screenMode == 2) {
++GShade;
}
if (BShade < 255 && screenMode == 3) {
++BShade;
}
updateLed();
updateOLED();
if (!changing) {
delay(1000);
changing = true;
}
}
}
//decrease led brightness
if (touchRead(touchPins[4]) <= 40 && mode == "led") {
changing = false;
while (touchRead(touchPins[4]) <= 40) {
if (RShade > 0 && screenMode == 1) {
--RShade;
}
if (GShade > 0 && screenMode == 2) {
--GShade;
}
if (BShade > 0 && screenMode == 3) {
--BShade;
}
updateLed();
updateOLED();
if (!changing) {
delay(1000);
changing = true;
}
}
}
//increase alarm time
if (touchRead(touchPins[3]) <= 40 && mode == "alarm") {
if (alarmMin < 59 && screenMode == 2) {
++alarmMin;
}
if (alarmHour < 23 && screenMode == 1) {
++alarmHour;
}
changing = true;
updateOLED();
changing = false;
for (int i = 0; i < 100; ++i) {
if (touchPins[3] > 40) {
break;
}
delay(10);
}
while (touchRead(touchPins[3]) <= 40) {
if (alarmMin < 59 && screenMode == 2) {
++alarmMin;
}
if (alarmHour < 23 && screenMode == 1) {
++alarmHour;
}
changing = true;
updateOLED();
changing = false;
delay(100);
}
}
//decrease alarm time
if (touchRead(touchPins[4]) <= 40 && mode == "alarm") {
if (alarmMin > 0 && screenMode == 2) {
--alarmMin;
}
if (alarmHour > 0 && screenMode == 1) {
--alarmHour;
}
changing = true;
updateOLED();
changing = false;
for (int i = 0; i < 100; ++i) {
delay(10);
if (touchPins[4] > 40) {
break;
}
}
while (touchRead(touchPins[4]) <= 40) {
if (alarmMin > 0 && screenMode == 2) {
--alarmMin;
}
if (alarmHour > 0 && screenMode == 1) {
--alarmHour;
}
changing = true;
updateOLED();
changing = false;
delay(100);
}
}
//increase time
if (touchRead(touchPins[3]) <= 40 && mode == "time" && screenMode) {
updateTimes();
if (screenMode == 3) {
Dsec = 0;
} else if (Dmin < 59 && screenMode == 2) {
++Dmin;
} else if (Dhour < 23 && screenMode == 1) {
++Dhour;
} else if (Dday < 31 && screenMode == 5) {
++Dday;
} else if (Dmonth < 12 && screenMode == 4) {
++Dmonth;
} else if (Dyear < 2104 && screenMode == 6) {
++Dyear;
}
rtc.setTime(Dsec, Dmin, Dhour, Dday, Dmonth, Dyear);
changing = true;
updateOLED();
changing = false;
for (int i = 0; i < 100; ++i) {
if (touchPins[3] > 40) {
break;
}
delay(10);
}
while (touchRead(touchPins[3]) <= 40) {
updateTimes();
if (screenMode == 3) {
Dsec = 0;
}
else if (Dmin < 59 && screenMode == 2) {
++Dmin;
}
else if (Dhour < 23 && screenMode == 1) {
++Dhour;
}
else if (Dday < 31 && screenMode == 5) {
++Dday;
}
else if (Dmonth < 12 && screenMode == 4) {
++Dmonth;
}
else if (Dyear < 2104 && screenMode == 6) {
++Dyear;
}
rtc.setTime(Dsec, Dmin, Dhour, Dday, Dmonth, Dyear);
changing = true;
updateOLED();
changing = false;
delay(100);
}
}
//decrease time
if (touchRead(touchPins[4]) <= 40 && mode == "time" && screenMode) {
updateTimes();
if (Dmin > 0 && screenMode == 2) {
--Dmin;
} else if (Dhour > 0 && screenMode == 1) {
--Dhour;
} else if (Dday > 0 && screenMode == 5) {
--Dday;
} else if (Dmonth > 0 && screenMode == 4) {
--Dmonth;
} else if (Dyear > 0 && screenMode == 6) {
--Dyear;
}
rtc.setTime(Dsec, Dmin, Dhour, Dday, Dmonth, Dyear);
changing = true;
updateOLED();
changing = false;
for (int i = 0; i < 100; ++i) {
delay(10);
if (touchPins[4] > 40) {
break;
}
}
while (touchRead(touchPins[4]) <= 40) {
updateTimes();
if (Dmin > 0 && screenMode == 2) {
--Dmin;
} else if (Dhour > 0 && screenMode == 1) {
--Dhour;
} else if (Dday > 0 && screenMode == 5) {
--Dday;
} else if (Dmonth > 0 && screenMode == 4) {
--Dmonth;
} else if (Dyear > 1968 && screenMode == 6) {
--Dyear;
}
rtc.setTime(Dsec, Dmin, Dhour, Dday, Dmonth, Dyear);
changing = true;
updateOLED();
changing = false;
delay(100);
}
}
//toggle alarm
if (touchRead(touchPins[0]) <= 40) {
alarmOn = false;
player.stop();
if (mode == "alarm" || mode == "time") {
alarmSet = !alarmSet;
} else if (mode == "led") {
ledOn = !ledOn;
}
while (touchRead(touchPins[0]) <= 40);
}
//toggle twelve hour time
if (touchRead(touchPins[3]) <= 40 && mode == "time" && screenMode == 0) {
twelveHour = !twelveHour;
while (touchRead(touchPins[3]) <= 40);
}
//change modes
if (touchRead(touchPins[1]) <= 40) {
if (mode == "time") {
mode = "alarm";
} else if (mode == "alarm") {
mode = "led";
} else if (mode == "led") {
mode = "time";
}
screenMode = 0;
while (touchRead(touchPins[1]) <= 40);
}
//reset time every 10mins
if (update && counter > 1200) {
// Init and get the time
if (wifiStatus) {
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org", "time.nist.gov");
Serial.print("updated time to ");
} else {
WiFi.begin(ssid, password);
for (int i = 0; i < 5; ++i) {
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi connected.");
wifiStatus = true;
break;
}
delay(500);
Serial.print(".");
}
if (!wifiStatus) {
Serial.print("could not connect to wifi.");
WiFi.disconnect();
}
// Init and get the time
if (wifiStatus) {
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org", "time.nist.gov");
Serial.print("updated time to ");
}
}
update = false;
counter = 0;
}
//update OLED twice every sec
if (update) {
updateOLED();
update = false;
}
updateLed();
//play song if time
if (alarmOn && alarmSet) {
player.copy();
}
}//~640~ & 83% && 1096933, 1096877