/*************************************************
* DADU DIGITAL ESP32 FINAL
* OLED + ENCODER + BUTTON + BUZZER + BLYNK
*************************************************/
#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "TMPL67S4-IZ9T"
#define BLYNK_TEMPLATE_NAME "Dadu Digital"
#define BLYNK_AUTH_TOKEN "T2oigg-FnacIlrmFT06FM7qfBiBK_UWB"
// ================= LIBRARY =================
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ================= WIFI =================
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
// ================= OLED =================
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// ================= PIN =================
#define CLK 27
#define DT 14
#define SW 25
#define RESET_BTN 26
#define BUZZER 18
// ================= STATE =================
enum State {
START_MENU,
PILIH_MODE,
MANUAL,
OTOMATIS
};
State state = START_MENU;
// ================= VAR =================
int menuMode = 0; // 0 Manual | 1 Otomatis
int menuDadu = 0; // 0 = 1 dadu | 1 = 2 dadu
int lastCLK;
int dadu1 = 1;
int dadu2 = 1;
unsigned long lastAuto = 0;
const unsigned long autoDelay = 4000;
// ================= BLYNK =================
BLYNK_WRITE(V0) { // MODE
if (state != START_MENU) {
state = param.asInt() ? OTOMATIS : MANUAL;
tampilMenuDadu();
}
}
BLYNK_WRITE(V1) { // JUMLAH DADU
menuDadu = param.asInt();
tampilMenuDadu();
}
BLYNK_WRITE(V2) { // LEMPAR MANUAL
if (state == MANUAL && param.asInt()) {
lemparDadu();
}
}
BLYNK_WRITE(V3) { // RESET
if (param.asInt()) resetSistem();
}
BLYNK_WRITE(V4) { // START
if (param.asInt() && state == START_MENU) {
state = PILIH_MODE;
tampilPilihMode();
}
}
// ================= SETUP =================
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
pinMode(SW, INPUT_PULLUP);
pinMode(RESET_BTN, INPUT_PULLUP);
pinMode(BUZZER, OUTPUT);
randomSeed(analogRead(34));
lastCLK = digitalRead(CLK);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
while (1);
}
tampilStart();
}
// ================= LOOP =================
void loop() {
Blynk.run();
bacaEncoder();
if (digitalRead(SW) == LOW) {
delay(200);
tombolEnter();
}
if (digitalRead(RESET_BTN) == LOW) {
delay(200);
resetSistem();
}
if (state == OTOMATIS && millis() - lastAuto >= autoDelay) {
lastAuto = millis();
lemparDadu();
}
}
// ================= START SCREEN =================
void tampilStart() {
const char* text = "Start";
int textSize = 3;
int charWidth = 6 * textSize;
int charHeight = 8 * textSize;
int textWidth = strlen(text) * charWidth;
int x = (SCREEN_WIDTH - textWidth) / 2;
int y = (SCREEN_HEIGHT - charHeight) / 2;
// Kedip 3x
for (int i = 0; i < 3; i++) {
display.clearDisplay();
display.setTextSize(textSize);
display.setTextColor(WHITE);
display.setCursor(x, y);
display.print(text);
display.display();
delay(200);
display.clearDisplay();
display.display();
delay(200);
}
// Teks diam (tenang)
display.clearDisplay();
display.setTextSize(textSize);
display.setTextColor(WHITE);
display.setCursor(x, y);
display.print(text);
display.display();
digitalWrite(BUZZER, HIGH);
delay(80);
digitalWrite(BUZZER, LOW);
}
// ================= ENCODER =================
void bacaEncoder() {
if (state == START_MENU) return;
int currentCLK = digitalRead(CLK);
if (currentCLK != lastCLK && currentCLK == HIGH) {
if (digitalRead(DT) != currentCLK) {
if (state == PILIH_MODE) menuMode++;
else menuDadu++;
} else {
if (state == PILIH_MODE) menuMode--;
else menuDadu--;
}
menuMode = constrain(menuMode, 0, 1);
menuDadu = constrain(menuDadu, 0, 1);
if (state == PILIH_MODE) tampilPilihMode();
else tampilMenuDadu();
}
lastCLK = currentCLK;
}
// ================= ENTER =================
void tombolEnter() {
if (state == START_MENU) {
state = PILIH_MODE;
tampilPilihMode();
}
else if (state == PILIH_MODE) {
state = (menuMode == 0) ? MANUAL : OTOMATIS;
tampilMenuDadu();
}
else if (state == MANUAL) {
lemparDadu();
}
}
// ================= DISPLAY =================
void tampilPilihMode() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(30, 0);
display.print("PILIH MODE");
display.setCursor(20, 25);
display.print(menuMode == 0 ? "> MANUAL" : " MANUAL");
display.setCursor(20, 40);
display.print(menuMode == 1 ? "> OTOMATIS" : " OTOMATIS");
display.display();
}
void tampilMenuDadu() {
display.clearDisplay();
display.setCursor(15, 0);
display.print(state == MANUAL ? "MODE MANUAL" : "MODE OTOMATIS");
display.setCursor(20, 25);
display.print(menuDadu == 0 ? "> 1 DADU" : " 1 DADU");
display.setCursor(20, 40);
display.print(menuDadu == 1 ? "> 2 DADU" : " 2 DADU");
display.display();
}
// ================= DADU =================
void lemparDadu() {
digitalWrite(BUZZER, HIGH);
for (int i = 0; i < 6; i++) {
dadu1 = random(1, 7);
dadu2 = random(1, 7);
tampilDadu();
delay(120);
}
digitalWrite(BUZZER, LOW);
kirimKeBlynk();
}
void tampilDadu() {
display.clearDisplay();
display.drawRect(10, 10, 40, 40, WHITE);
gambarTitik(dadu1, 10, 10);
if (menuDadu == 1) {
display.drawRect(78, 10, 40, 40, WHITE);
gambarTitik(dadu2, 78, 10);
}
display.setCursor(25, 55);
display.print("TOTAL: ");
display.print(menuDadu == 0 ? dadu1 : dadu1 + dadu2);
display.display();
}
// ================= BLYNK SEND =================
void kirimKeBlynk() {
Blynk.virtualWrite(V5, dadu1);
Blynk.virtualWrite(V6, menuDadu ? dadu2 : 0);
Blynk.virtualWrite(V7, menuDadu ? dadu1 + dadu2 : dadu1);
}
// ================= RESET =================
void resetSistem() {
state = START_MENU;
menuMode = 0;
menuDadu = 0;
tampilStart();
}
// ================= TITIK DADU =================
void gambarTitik(int n, int x, int y) {
int cx = x + 20, cy = y + 20, s = 10;
if (n == 1) dot(cx, cy);
if (n == 2) { dot(cx - s, cy - s); dot(cx + s, cy + s); }
if (n == 3) { dot(cx, cy); dot(cx - s, cy - s); dot(cx + s, cy + s); }
if (n == 4) {
dot(cx - s, cy - s); dot(cx + s, cy - s);
dot(cx - s, cy + s); dot(cx + s, cy + s);
}
if (n == 5) {
dot(cx, cy);
dot(cx - s, cy - s); dot(cx + s, cy - s);
dot(cx - s, cy + s); dot(cx + s, cy + s);
}
if (n == 6) {
dot(cx - s, cy - s); dot(cx - s, cy); dot(cx - s, cy + s);
dot(cx + s, cy - s); dot(cx + s, cy); dot(cx + s, cy + s);
}
}
void dot(int x, int y) {
display.fillCircle(x, y, 2, WHITE);
}