#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#define TFT_CS D3
#define TFT_DC D5
#define TFT_RST D4
#define POT_PIN D0
int buzzer = D2;
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define FRAME_DELAY 15
#define FRAME_WIDTH 64
#define FRAME_HEIGHT 64
#define HEART_WIDTH 16
#define HEART_HEIGHT 16
#define SELECTION_TIMEOUT 5000
Adafruit_ILI9341 screen = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
const char* ssid = "Wokwi-GUEST";
const char* password = "";
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 7 * 3600);
int iMinutes = 0;
long LSeconds = 0;
unsigned long LLFocusStartTime = 0;
unsigned long LLSetElapsedTime = 0;
unsigned long LLPrevSetElapsedTime = 0;
unsigned long LLInputTimeoutStart = 0;
bool bInputTimeoutStarted = false;
bool bFocusStart = false;
bool bShowTime = true;
const byte PROGMEM frames[][512] = {
{ }, { }, { }
};
const uint8_t heartBitmap[] PROGMEM = {
0b00001100, 0b00110000,
0b00011110, 0b01111000,
0b00111111, 0b11111100,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b11111111, 0b11111111,
0b11111111, 0b11111111,
0b01111111, 0b11111110,
0b01111111, 0b11111110,
0b00111111, 0b11111100,
0b00011111, 0b11111000,
0b00001111, 0b11110000,
0b00000111, 0b11100000,
0b00000011, 0b11000000,
0b00000001, 0b10000000,
0b00000000, 0b00000000
};
String weekDays[7] = {"SUNDAY","MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY"};
String months[12] = {"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};
unsigned long previousMillis = 0;
int currentFrame = 0;
String meridiem;
void setup() {
Serial.begin(115200);
analogReadResolution(10);
screen.begin();
screen.setRotation(3);
screen.fillScreen(ILI9341_BLACK);
screen.setTextSize(2);
screen.setCursor(90, 90);
screen.setTextColor(ILI9341_WHITE);
screen.println("FOCUS");
screen.drawBitmap(70, 90, heartBitmap, HEART_WIDTH, HEART_HEIGHT, ILI9341_WHITE);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
screen.drawRect(30, 120, 250, 20, ILI9341_WHITE);
int x = map(currentFrame, 0, 100, 0, 100);
screen.fillRect(35, 125, x, 10, ILI9341_WHITE);
currentFrame = (currentFrame + 5) % 105;
delay(500);
}
timeClient.begin();
delay(100);
timeClient.update();
bShowTime = true;
pinMode(buzzer, OUTPUT);
}
void loop() {
if (!bFocusStart && bShowTime) {
timeClient.update();
fetchDateTime();
setting();
} else if (!bFocusStart && !bShowTime) {
settingScreen();
setting();
} else {
focusScreen();
focusElapse();
}
delay(50);
}
void fetchDateTime() {
screen.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
screen.setTextSize(2);
int hours = timeClient.getHours();
int minutes = timeClient.getMinutes();
meridiem = (hours >= 12) ? "PM" : "AM";
if (hours > 12) hours = map(hours, 13, 24, 1, 12);
time_t epochTime = timeClient.getEpochTime();
struct tm *ptm = gmtime(&epochTime);
String currentMonthName = months[ptm->tm_mon];
String currentDay = weekDays[timeClient.getDay()];
screen.setTextSize(4);
screen.setCursor(30, 120);
screen.println(currentDay);
screen.setTextSize(3);
screen.setCursor(30, 160);
screen.println(currentMonthName);
screen.setTextSize(8);
screen.setCursor(30, 50);
screen.println(padZero(hours) + ":" + padZero(minutes));
screen.setTextSize(2);
screen.setCursor(270, 50);
screen.println(meridiem);
}
void setting() {
int raw = analogRead(POT_PIN);
int minutes = 0;
if (raw >= 20) {
minutes = map(raw, 20, 1023, 1, 90);
minutes = constrain(minutes, 0, 90);
}
LLSetElapsedTime = (unsigned long)minutes * 60UL * 1000UL;
convertToTime(LLSetElapsedTime);
if (LLSetElapsedTime != 0 && bShowTime) {
bShowTime = false;
screen.fillScreen(ILI9341_BLACK);
}
if (LLSetElapsedTime != LLPrevSetElapsedTime) {
bInputTimeoutStarted = false;
LLInputTimeoutStart = 0;
}
if (LLSetElapsedTime != 0 && !bInputTimeoutStarted) {
bInputTimeoutStarted = true;
LLInputTimeoutStart = millis();
}
if (bInputTimeoutStarted && (millis() - LLInputTimeoutStart >= SELECTION_TIMEOUT)) {
LLFocusStartTime = millis();
bFocusStart = true;
screen.fillScreen(ILI9341_BLACK);
}
if (LLSetElapsedTime <= 0) {
if (!bShowTime) {
bShowTime = true;
screen.fillScreen(ILI9341_BLACK);
}
bInputTimeoutStarted = false;
LLInputTimeoutStart = 0;
}
LLPrevSetElapsedTime = LLSetElapsedTime;
}
void settingScreen() {
screen.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
screen.setTextSize(3);
screen.setCursor(130, 20);
screen.println("M");
screen.setCursor(260, 100);
screen.println("S");
screen.setTextSize(12);
screen.setCursor(30, 50);
screen.println(padZero(iMinutes));
screen.setTextSize(10);
screen.setCursor(170, 130);
screen.println(padZero(LSeconds));
screen.setTextSize(2);
screen.setCursor(30, 180);
if (bInputTimeoutStarted && LLInputTimeoutStart != 0) {
screen.println(padZero((SELECTION_TIMEOUT - (millis() - LLInputTimeoutStart)) / 1000));
} else {
screen.fillRect(30, 180, 40, 40, ILI9341_BLACK);
}
}
void focusElapse() {
unsigned long elapsed = (LLSetElapsedTime > elapseSec()) ? (LLSetElapsedTime - elapseSec()) : 0;
int raw = analogRead(POT_PIN);
int minutes = (raw >= 20) ? map(raw, 20, 1023, 1, 90) : 0;
if (minutes == 0) {
bFocusStart = false;
LLFocusStartTime = 0;
LLInputTimeoutStart = millis();
screen.fillScreen(ILI9341_BLACK);
}
if (elapsed <= 500) {
alarm();
} else {
convertToTime(elapsed);
}
}
void focusScreen() {
screen.setTextSize(3);
screen.setCursor(130, 20);
screen.println("M");
screen.setCursor(260, 100);
screen.println("S");
screen.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
screen.setTextSize(12);
screen.setCursor(30, 50);
screen.println(padZero(iMinutes));
screen.setTextSize(10);
screen.setCursor(170, 130);
screen.println(padZero(LSeconds));
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= FRAME_DELAY) {
previousMillis = currentMillis;
int frameCount = sizeof(frames) / sizeof(frames[0]);
screen.drawBitmap(60, 150, frames[currentFrame], FRAME_WIDTH, FRAME_HEIGHT, ILI9341_WHITE, ILI9341_BLACK);
currentFrame = (currentFrame + 1) % frameCount;
}
}
void alarm() {
screen.fillScreen(ILI9341_BLACK);
screen.setTextSize(2);
screen.setCursor(90, 60);
screen.println(padZero((LLSetElapsedTime / 1000) / 60) + " MINUTE(s)");
screen.setTextSize(3);
screen.setCursor(40, 100);
screen.println("YOU DID GREAT!");
int raw = 0, minutes = 0;
do {
tone(buzzer, 1500, 1000);
raw = analogRead(POT_PIN);
minutes = (raw >= 20) ? map(raw, 20, 1023, 1, 90) : 0;
} while (minutes != 0);
noTone(buzzer);
bFocusStart = false;
LLFocusStartTime = 0;
LLInputTimeoutStart = millis();
screen.fillScreen(ILI9341_BLACK);
}
unsigned long elapseSec() {
return (millis() - LLFocusStartTime);
}
void convertToTime(unsigned long ms) {
LSeconds = (ms / 1000) % 60;
iMinutes = (ms / 1000) / 60;
}
String padZero(int number) {
if (number < 10) return "0" + String(number);
return String(number);
}
Loading
xiao-esp32-c3
xiao-esp32-c3