Alat cerdas cermat sederhana. Juri membuka babak dari HP, dua pemain berlomba menekan tombol. Yang paling cepat menyalakan lampunya, waktu reaksinya tercatat, dan skornya bertambah di dashboard.
Selama babak tertutup, tombol diabaikan. Saat switch Mulai dinyalakan, ESP32 mencatat waktu buka dan mulai memeriksa kedua tombol setiap putaran loop(). Tombol pertama yang terbaca LOW menang, babak langsung ditutup, dan tombol kedua tidak dihitung. loop() berputar ratusan ribu kali per detik, jadi selisih sepersekian milidetik pun tetap terbedakan.
Komponen
| Komponen | Qty | Harga |
|---|---|---|
| ESP32 DOIT DevKit V1 30 pin | 1 | Rp75.000 |
| Push button 6×6 mm (isi 10)isi 10, terpakai 2 | 1 | Rp4.750 |
| LED 5 mm merah (isi 10)isi 10, terpakai 1 | 1 | Rp2.500 |
| LED 5 mm hijau (isi 10)isi 10, terpakai 1 | 1 | Rp2.850 |
| Resistor 330 Ω (isi 10)isi 10, terpakai 2 | 1 | Rp1.800 |
| Breadboard 830 titik | 1 | Rp18.000 |
| Kabel jumper male-female 10 cm (isi 10)isi 10, terpakai 8 | 1 | Rp3.500 |
| Kabel micro USB data 30 cmopsional, kalau belum punya kabel micro USB data | 1 | Rp11.700 |
| Total (tanpa opsional) | Rp108.400 |
Langkah 1: Rangkai komponen
Sambungkan kabel sesuai gambar di atas. Kalau gambar dan tabel terlihat berbeda, ikuti tabel.
| Dari | Ke | Kabel | |
|---|---|---|---|
| Tombol pemain 1 1 | → | D32 GPIO32 | biru |
| Tombol pemain 1 2 | → | GND | hitam |
| Tombol pemain 2 1 | → | D33 GPIO33 | ungu |
| Tombol pemain 2 2 | → | GND | hitam |
| LED merah + resistor 330 Ω + | → | D25 GPIO25 | merah |
| LED merah + resistor 330 Ω − | → | GND | hitam |
| LED hijau + resistor 330 Ω + | → | D26 GPIO26 | hijau |
| LED hijau + resistor 330 Ω − | → | GND | hitam |
Langkah 2: Siapkan dashboard Klenik
Cara cepat: unduh p019.json, ganti budi1234 dengan KODE-mu, lalu import di Klenik (menu titik tiga → Export / Import → Import → Ganti total). Langkah lengkapnya ada di Panduan Klenik.
| Widget | Topic | Setting |
|---|---|---|
| Switch Mulai Babak | ichibot/KODE/p019/mulai | payload ON / OFF |
| Switch Nolkan Skor | ichibot/KODE/p019/nolkan | payload ON / OFF |
| Gauge Skor Pemain 1 | ichibot/KODE/p019/skor1 | 0–20 |
| Gauge Skor Pemain 2 | ichibot/KODE/p019/skor2 | 0–20 |
| Text Log Hasil Babak | ichibot/KODE/p019/log | menampilkan teks masuk |
Langkah 3: Upload kode
Library: PubSubClient (Nick O'Leary). Board di Arduino IDE: ESP32 Dev Module.
Isi dulu nama WiFi dan password di bagian ISI DULU, lalu ganti budi1234 di baris topic dengan KODE-mu, lalu upload dan buka Serial Monitor (115200).
// Proyek 019 - Kuis Tombol Cepat-cepatan 2 Pemain
// Board: ESP32 DOIT DevKit V1 | Dashboard: klenik.ichibot.id
#include <WiFi.h>
#include <PubSubClient.h>
// ===== ISI DULU =====
const char* WIFI_NAMA = "nama-wifi-kamu";
const char* WIFI_PASS = "password-wifi-kamu";
// topic MQTT: ganti budi1234 dengan KODE-mu (sama dengan di dashboard Klenik)
const char* TOPIK_SKOR1 = "ichibot/budi1234/p019/skor1";
const char* TOPIK_SKOR2 = "ichibot/budi1234/p019/skor2";
const char* TOPIK_LOG = "ichibot/budi1234/p019/log";
const char* TOPIK_MULAI = "ichibot/budi1234/p019/mulai";
const char* TOPIK_NOLKAN = "ichibot/budi1234/p019/nolkan";
const char* BROKER = "mqtt.ichibot.id";
WiFiClient wifi;
PubSubClient mqtt(wifi);
const int TOMBOL1 = 32, TOMBOL2 = 33, LED1 = 25, LED2 = 26;
bool babakBuka = false;
unsigned long mulai = 0;
int skor1 = 0, skor2 = 0;
void kirimSkor() {
mqtt.publish(TOPIK_SKOR1, String(skor1).c_str(), true);
mqtt.publish(TOPIK_SKOR2, String(skor2).c_str(), true);
}
void pesanMasuk(char* t, byte* isi, unsigned int panjang) {
String topik = t, p;
for (unsigned int i = 0; i < panjang; i++) p += (char)isi[i];
if (topik == TOPIK_MULAI && p == "ON") {
babakBuka = true;
mulai = millis();
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
mqtt.publish(TOPIK_LOG, "Babak dibuka, siap tekan!");
} else if (topik == TOPIK_NOLKAN && p == "ON") {
skor1 = skor2 = 0;
kirimSkor();
}
}
void langganan() {
mqtt.subscribe(TOPIK_MULAI);
mqtt.subscribe(TOPIK_NOLKAN);
kirimSkor();
}
void menang(int pemain) {
babakBuka = false;
digitalWrite(pemain == 1 ? LED1 : LED2, HIGH);
if (pemain == 1) skor1++; else skor2++;
float detik = (millis() - mulai) / 1000.0;
mqtt.publish(TOPIK_LOG, ("Pemain " + String(pemain) + " paling cepat (" + String(detik, 2) + " s)").c_str());
kirimSkor();
}
sambungWiFi() dan sambungMQTT(): sama di semua proyek (klik untuk lihat)
void sambungWiFi() {
WiFi.begin(WIFI_NAMA, WIFI_PASS);
Serial.print("WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" OK, IP " + WiFi.localIP().toString());
}
void sambungMQTT() {
while (!mqtt.connected()) {
if (mqtt.connect(WiFi.macAddress().c_str())) {
Serial.println("Terhubung ke Klenik");
langganan();
} else {
Serial.println("Broker gagal, coba lagi 3 detik");
delay(3000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(TOMBOL1, INPUT_PULLUP);
pinMode(TOMBOL2, INPUT_PULLUP);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
sambungWiFi();
mqtt.setServer(BROKER, 1883);
mqtt.setCallback(pesanMasuk);
}
void loop() {
if (!mqtt.connected()) sambungMQTT();
mqtt.loop();
if (!babakBuka) return;
if (digitalRead(TOMBOL1) == LOW) menang(1);
else if (digitalRead(TOMBOL2) == LOW) menang(2);
}Langkah 4: Pahami kodenya
- Penjaga keadilan: menekan tombol sebelum juri membuka babak tidak ada artinya.
- Juri membuka babak dengan menggeser switch ke ON. Lampu kedua pemain dimatikan dan waktu mulai dicatat.
- Babak langsung ditutup di baris pertama, supaya tombol pemain lain yang menyusul sepersekian detik tidak ikut dihitung.
- Waktu reaksi dalam detik dengan 2 angka di belakang koma. Ditulis
1000.0supaya hasil baginya pecahan, bukan bilangan bulat.