#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TM1637Display.h>
#include <ESP32Servo.h>
// LCD and TM1637 Setup
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define TM1637_CLK 12
#define TM1637_DIO 13
TM1637Display display(TM1637_CLK, TM1637_DIO);
// Pin Definitions
#define BUTTON_UP 15
#define BUTTON_DOWN 16
#define BUTTON_SELECT 17
#define BUTTON_BACK 23
#define BUZZER_PIN 14
#define RELAY_PIN 2
#define TEMP_SENSOR_PIN A0
#define SERVO_PIN 9
// Menu items
const char* menuItems[] = {"Timer", "Counter", "Mixing", "Recipes"};
const int menuSize = sizeof(menuItems) / sizeof(menuItems[0]);
int currentMenuIndex = 0;
// State variables
bool inSubMenu = false;
Servo mixerServo;
// Custom Characters for Arrows
byte arrowUp[8] = {0b00100, 0b01110, 0b10101, 0b00100, 0b00100, 0b00100, 0b00100, 0b00000};
byte arrowDown[8] = {0b00100, 0b00100, 0b00100, 0b00100, 0b10101, 0b01110, 0b00100, 0b00000};
byte arrowRight[8] = {0b00100, 0b00110, 0b00101, 0b11111, 0b00101, 0b00110, 0b00100, 0b00000};
void setup() {
lcd.begin(16, 2);
lcd.init();
lcd.backlight();
lcd.createChar(0, arrowUp);
lcd.createChar(1, arrowDown);
lcd.createChar(2, arrowRight);
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUTTON_SELECT, INPUT_PULLUP);
pinMode(BUTTON_BACK, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
pinMode(TEMP_SENSOR_PIN, INPUT);
digitalWrite(RELAY_PIN, LOW);
display.setBrightness(0x0f);
mixerServo.attach(SERVO_PIN);
displayStartup();
}
void loop() {
}
void buzz() {
digitalWrite(BUZZER_PIN, HIGH);
delay(50);
digitalWrite(BUZZER_PIN, LOW);
}
void displayStartup() {
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("CK BOT");
lcd.setCursor(15, 0);
lcd.write(byte(2));
while(true){
if (digitalRead(BUTTON_SELECT) == LOW) {
mode();
break;
}
}
}
void mode() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(byte(2));
lcd.print("Manual");
lcd.setCursor(1, 1);
lcd.print("Bluetooth");
int i=0;
delay(1000);
while(true){
if (digitalRead(BUTTON_UP) == LOW) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(byte(2));
lcd.print("Manual");
lcd.setCursor(1, 1);
lcd.print("Bluetooth");
i=0;
}
if (digitalRead(BUTTON_DOWN) == LOW) {
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Manual");
lcd.setCursor(0, 1);
lcd.write(byte(2));
lcd.print("Bluetooth");
i=1;
}
if (digitalRead(BUTTON_SELECT) == LOW) {
switch (i) {
case 0:
Menu();
break;
case 1:
bluetooth();
break;
}
}
}
}
void bluetooth() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Bluetooth");
while(true){
if (digitalRead(BUTTON_BACK) == LOW) {
mode();
break;
}
}
}
void Menu(){
}
void displayMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(byte(0));
lcd.setCursor(15, 0);
lcd.write(byte(2));
lcd.setCursor(1, 0);
lcd.print(menuItems[currentMenuIndex]);
lcd.setCursor(0, 1);
lcd.write(byte(1));
int nextIndex = (currentMenuIndex + 1) % menuSize;
lcd.print(" ");
lcd.print(menuItems[nextIndex]);
}
void navigateMenu(int direction) {
currentMenuIndex += direction;
if (currentMenuIndex < 0) currentMenuIndex = menuSize - 1;
else if (currentMenuIndex >= menuSize) currentMenuIndex = 0;
displayMenu();
}
void selectMenuItem() {
inSubMenu = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Selected:");
lcd.setCursor(0, 1);
lcd.print(menuItems[currentMenuIndex]);
delay(1000);
lcd.clear();
switch (currentMenuIndex) {
case 0:
timerFunction();
break;
case 1:
counterFunction();
break;
case 2:
mixingFunction();
break;
case 3:
recipesFunction();
break;
}
}
void timerFunction() {
int hours = 0, minutes = 0;
int targetTemp = 0;
bool editing = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Edit Timer:");
while (editing) {
lcd.setCursor(0, 1);
lcd.print(formatTime(hours, minutes));
if (digitalRead(BUTTON_DOWN) == LOW) {
minutes = (minutes + 1) % 60;
if (minutes == 0) hours = (hours + 1) % 24;
delay(200);
} else if (digitalRead(BUTTON_UP) == LOW) {
if (minutes == 0) {
minutes = 59;
hours = (hours + 23) % 24;
} else {
minutes--;
}
delay(200);
} else if (digitalRead(BUTTON_SELECT) == LOW) {
editing = false;
delay(200);
}
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Edit Temp:");
editing = true;
while (editing) {
lcd.setCursor(0, 1);
lcd.print(targetTemp);
lcd.setCursor(4, 1);
lcd.print("'C");
if (digitalRead(BUTTON_DOWN) == LOW) {
targetTemp = (targetTemp + 1) % 101;
delay(200);
} else if (digitalRead(BUTTON_UP) == LOW) {
targetTemp = (targetTemp + 100) % 101;
delay(200);
} else if (digitalRead(BUTTON_SELECT) == LOW) {
editing = false;
delay(200);
}
}
countdownTimer(hours, minutes, targetTemp);
}
void countdownTimer(int hours, int minutes, int targetTemp) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Started Timer ");
digitalWrite(RELAY_PIN, HIGH);
while (hours > 0 || minutes > 0) {
int currentTemp = analogRead(TEMP_SENSOR_PIN) / 2;
lcd.setCursor(0, 1);
lcd.print("C: ");
lcd.print(currentTemp);
lcd.print(" T: ");
lcd.print(targetTemp);
display.showNumberDecEx(hours * 100 + minutes, 0x40, true);
if (currentTemp > targetTemp) {
digitalWrite(RELAY_PIN, LOW);
} else {
digitalWrite(RELAY_PIN, HIGH);
}
delay(1000);
if (--minutes < 0) {
minutes = 59;
--hours;
}
}
display.showNumberDecEx(0, 0x40, true);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Complected");
while(true){
if (digitalRead(BUTTON_BACK) == LOW) {
returnToMenu();
break;
}
}
}
void counterFunction() {
int count = 0;
while (true) {
display.showNumberDec(count);
if (digitalRead(BUTTON_UP) == LOW) {
count++;
delay(200);
} else if (digitalRead(BUTTON_BACK) == LOW) {
returnToMenu();
break;
}
}
}
void mixingFunction() {
int hours = 0, minutes = 0;
bool timerSet = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Mix Timer:");
while (!timerSet) {
lcd.setCursor(0, 1);
lcd.print(formatTime(hours, minutes));
if (digitalRead(BUTTON_DOWN) == LOW) {
minutes = (minutes + 1) % 60;
if (minutes == 0) hours = (hours + 1) % 24;
delay(200);
} else if (digitalRead(BUTTON_UP) == LOW) {
if (minutes == 0) {
minutes = 59;
hours = (hours + 23) % 24;
} else {
minutes--;
}
delay(200);
} else if (digitalRead(BUTTON_SELECT) == LOW) {
timerSet = true;
delay(200);
}
}
lcd.clear();
lcd.print("Mixing...");
unsigned long endTime = millis() + ((hours * 3600UL + minutes * 60) * 1000);
while (millis() < endTime) {
mixerServo.write(0);
delay(500);
mixerServo.write(180);
delay(500);
int remainingMinutes = (endTime - millis()) / 60000;
int remainingSeconds = ((endTime - millis()) / 1000) % 60;
display.showNumberDecEx(remainingMinutes * 100 + remainingSeconds, 0x40, true);
}
mixerServo.write(90);
lcd.clear();
lcd.print("Mix Done!");
delay(2000);
}
void recipesFunction() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Selected:");
lcd.setCursor(0, 1);
lcd.print("Recipe");
delay(2000);
}
void returnToMenu() {
inSubMenu = false;
displayMenu();
}
String formatTime(int hh, int mm) {
char buffer[6];
sprintf(buffer, "%02d:%02d", hh, mm);
return String(buffer);
}