#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
Adafruit_SSD1306 display(128, 64, &Wire, -1);
#define left_button 6 // Red button for Left/Down
#define right_button 5 // Green button for Right/Up
#define ok_button 3 // Yellow button for Select/OK
#define relay_pin 13
bool paused = false;
bool blinking = false;
bool showCursor = true;
bool timer_active = false;
bool last_ok_button = HIGH;
bool last_left_button = HIGH;
bool last_right_button = HIGH;
byte page_index = 0;
byte _x, _y, _z = 0;
byte cursor_index = 0;
byte cursor_row_pos = 0;
byte max_cursor_index = 1;
byte jam = 0 ;
byte menit = 0;
byte detik = 0;
byte _time[2];
byte temp_time = 0;
const byte HOUR_ADDRESS = 10;
const byte MINUTE_ADDRESS = 12;
const byte SECOND_ADDRESS = 14;
unsigned long last_blink_time = 0;
unsigned long last_millis_timer = 0;
unsigned long last_time_button_release = 0;
int elapsed_time = 0;
const unsigned char Semar [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xff, 0xc0, 0x03, 0xff, 0x3f, 0xf1, 0xff, 0xfc, 0x7f, 0xe1, 0xff, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xfe, 0x00, 0x07, 0xfe, 0x7f, 0xf3, 0xff, 0xfc, 0x3f, 0xe7, 0xfe, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xf8, 0x00, 0x0e, 0x00, 0x60, 0x33, 0x06, 0x0c, 0x00, 0x67, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xc0, 0x00, 0x0e, 0x00, 0xc0, 0x67, 0x0c, 0x1c, 0x00, 0xce, 0x00, 0x00, 0x00,
0x00, 0x01, 0xff, 0x00, 0x00, 0x0f, 0xf9, 0xff, 0xce, 0x1c, 0x39, 0xff, 0xdc, 0x00, 0x00, 0x00,
0x00, 0x03, 0xfc, 0x00, 0x00, 0x07, 0xf9, 0xff, 0x8c, 0x18, 0x33, 0xff, 0x98, 0x00, 0x00, 0x00,
0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x3b, 0x80, 0x1c, 0x30, 0x67, 0x03, 0x38, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x73, 0x80, 0x18, 0x70, 0x6e, 0x06, 0x70, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xc0, 0x00, 0x00, 0xff, 0xe7, 0xff, 0x38, 0x60, 0xcf, 0xfe, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x0f, 0xf0, 0x00, 0x00, 0xff, 0xc3, 0xfe, 0x70, 0xc1, 0xc7, 0xfc, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x07, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
void setup() {
pinMode(left_button, INPUT_PULLUP);
pinMode(right_button, INPUT_PULLUP);
pinMode(ok_button, INPUT_PULLUP);
pinMode(relay_pin, OUTPUT);
digitalWrite(relay_pin, LOW);
readTimeFromEEPROM();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.cp437(true);
display.setTextWrap(false);
display.drawBitmap(0, 0, Semar, 128, 64, 1);
display.display();
delay(1500);
display.clearDisplay();
}
void loop() {
showMenu();
bool left_button_state = digitalRead(left_button);
bool right_button_state = digitalRead(right_button);
bool ok_button_state = digitalRead(ok_button);
bool ok_button_pressed = checkButtonState(ok_button_state, last_ok_button);
bool left_button_pressed = checkButtonState(left_button_state, last_left_button);
bool right_button_pressed = checkButtonState(right_button_state, last_right_button);
if (left_button_state == 1 && right_button_state == 1 && ok_button_state == 1) {
last_time_button_release = millis();
}
if (right_button_pressed) {
if (blinking) {
byte max_value = 99;
if (cursor_index > 0) max_value = 59;
temp_time++;
if (temp_time > max_value) temp_time = 0;
_time[cursor_index] = temp_time;
delay(50);
}
else {
cursor_index++;
if (cursor_index > max_cursor_index) cursor_index = 0;
delay(50);
}
}
else if (left_button_pressed) {
if (blinking) {
byte max_value = 99;
if (cursor_index > 0) max_value = 59;
temp_time--;
if (temp_time > max_value) temp_time = max_value;
else if (temp_time < 0) temp_time = max_value;
_time[cursor_index] = temp_time;
delay(50);
}
else {
cursor_index--;
if (cursor_index < 0 || cursor_index > max_cursor_index) cursor_index = max_cursor_index;
delay(50);
}
}
else if (ok_button_pressed) {
if (timer_active) {
if (cursor_index == 0) {
if (paused) {
paused = false;
last_millis_timer = millis();
delay(50);
}
else
paused = true;
}
else
timer_active = false;
}
else {
if (page_index == 0) {
if (cursor_index == 0)
page_index++;
else {
timer_active = true;
readTime();
last_millis_timer = millis();
cursor_index = 0;
delay(50);
}
}
else {
if (cursor_index == 3 || cursor_index == 4) {
bool valid = false;
readTime();
if (jam > 0 || menit > 0 || detik > 0 || cursor_index == 4) valid = true;
if (valid) {
if (cursor_index == 3) {
EEPROM.write(HOUR_ADDRESS, jam);
EEPROM.write(MINUTE_ADDRESS, menit);
EEPROM.write(SECOND_ADDRESS, detik);
}
else
readTimeFromEEPROM();
page_index--;
cursor_index = 0;
}
delay(50);
}
else {
if (!blinking) {
temp_time = _time[cursor_index];
blinking = true;
delay(50);
}
else
blinking = false;
}
}
}
}
}
void readTimeFromEEPROM() {
_time[0] = EEPROM.read(HOUR_ADDRESS);
_time[1] = EEPROM.read(MINUTE_ADDRESS);
_time[2] = EEPROM.read(SECOND_ADDRESS);
}
void drawRectangleCursor(byte row_pos, byte x, byte y, byte z) {
for (byte i = 0; i < y - x; i++) {
display.drawPixel(x + i, row_pos, SSD1306_WHITE);
display.drawPixel(x + i, z, SSD1306_WHITE);
if (i < (z - row_pos)) {
display.drawPixel(x, row_pos + i, SSD1306_WHITE);
display.drawPixel(y, row_pos + i, SSD1306_WHITE);
}
}
}
void updateCursorPos() {
if (paused || timer_active && !paused) {
cursor_row_pos = 37;
if (cursor_index == 0) {
_x = 17;
_y = 60;
_z = 51;
}
else {
_x = 64;
_y = 97;
_z = 51;
}
}
else if (paused == false && timer_active == false) {
if (page_index == 0) {
if (cursor_index == 0) cursor_row_pos = 0;
else
cursor_row_pos = 18;
}
else {
cursor_row_pos = 12;
switch (cursor_index) {
case 0:
_x = 12;
_y = 39;
_z = 31;
break;
case 1:
_x = 47;
_y = 76;
_z = 31;
break;
case 2:
_x = 83;
_y = 111;
_z = 31;
break;
case 3:
cursor_row_pos = 38;
_x = 20;
_y = 49;
_z = 50;
break;
default:
cursor_row_pos = 38;
_x = 65;
_y = 108;
_z = 50;
}
}
}
}
void printText(bool clear_display, int col, int row, char *message, bool visible) {
if (clear_display) display.clearDisplay();
display.setCursor(col, row);
display.print(message);
if (visible) display.display();
}
void showPageOneMenu() {
max_cursor_index = 1;
printText(true, 15, 0, "SETUP", false);
printText(false, 15, 18, "START", false);
printText(false, 0, cursor_row_pos, ">", true);
}
void showPageTwoMenu() {
max_cursor_index = 4;
setMenu("save", "cancel");
}
void setMenu(char *left_option, char *right_option) {
updateAndShowTimer();
display.setTextSize(1);
printText(false, 23, 40, left_option, false);
printText(false, 70, 40, right_option, false);
display.setTextSize(2);
}
void runAndShowTimer() {
display.clearDisplay();
max_cursor_index = 1;
drawRectangleCursor(cursor_row_pos, _x, _y, _z);
setMenu("pause", "stop");
display.display();
}
void showPausedMenu() {
display.clearDisplay();
max_cursor_index = 1;
drawRectangleCursor(cursor_row_pos, _x, _y, _z);
setMenu("resume", "stop");
display.display();
}
void readTime() {
jam = _time[0];
menit = _time[1];
detik = _time[2];
}
void updateAndShowTimer() {
char timer_char[6];
if (!timer_active) {
readTime();
}
else {
if (millis() - last_millis_timer >= 1000) {
if (!paused) {
elapsed_time = (millis() - last_millis_timer) - 1000;
if (detik <= 0) {
detik = 60;
if (menit > 0)
menit--;
else if (menit <= 0 && jam > 0) {
jam--;
menit = 59;
}
}
detik--;
last_millis_timer = millis() - elapsed_time;
if (jam <= 0 && menit <= 0 && detik <= 0) timer_active = false;
}
}
}
sprintf_P(timer_char, PSTR("%02d:%02d:%02d"), jam, menit, detik);
printText(false, 15, 15, timer_char, false);
}
void showMenu() {
updateCursorPos();
if (timer_active) {
if (paused) {
showPausedMenu();
digitalWrite(relay_pin, LOW);
}
else {
runAndShowTimer();
tone(relay_pin, 100, 1000);
digitalWrite(relay_pin, HIGH);
}
}
else {
paused = false;
digitalWrite(relay_pin, LOW);
if (page_index == 0) {
showPageOneMenu();
blinking = false;
}
else {
display.clearDisplay();
showPageTwoMenu();
if (blinking && millis() - last_blink_time >= 300) {
showCursor = !showCursor;
last_blink_time = millis();
}
if (!blinking) showCursor = true;
if (showCursor) drawRectangleCursor(cursor_row_pos, _x, _y, _z);
display.display();
}
}
}
bool checkButtonState(bool btn_name, bool &last_button_state) {
bool result = false;
if (btn_name == LOW) {
if (last_button_state == HIGH)
result = true;
else {
if (millis() - last_time_button_release >= 2000 && blinking) result = true;
}
last_button_state = LOW;
}
else {
result = false;
last_button_state = HIGH;
}
return result;
}