Timer Countdown ESP32 Input via Browser Penampil DMD P10 (Timer ujian atau Timer Futsal)
Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah alat yang dapat digunakan untuk Timer ujian sekolah atau Timer Sepak Bola seperti Futsal atau sejenisnya. alat ini pengoperasiannya sangatlah mudah yaitu hanya perlu menyambungkan wifi esp32 lalu masukkan passwordnya setelah itu buka browser lalu ketikkan IP 192.168.4.1 sehingga akan tampil interface seperti dibawah. untuk lebih jelasnya berikut adalah koding dan skemanya.
1. Skema
2. Interface
3. Program ESP32
#include <WiFi.h>
#include <WebServer.h>
#include <DMD32.h>
#include "fonts/Arial_Black_16.h"
#include "fonts/SystemFont5x7.h"
// =====================================================
// PENGATURAN P10
// =====================================================
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
// =====================================================
// TIMER REFRESH P10
// =====================================================
hw_timer_t *timer = NULL;
void IRAM_ATTR triggerScan()
{
dmd.scanDisplayBySPI();
}
// =====================================================
// WIFI
// =====================================================
const char* ssid = "P10-COUNTDOWN";
const char* password = "12345678";
WebServer server(80);
// =====================================================
// COUNTDOWN
// =====================================================
long setSeconds = 60;
long remainingSeconds = 60;
bool timerRunning = false;
unsigned long lastSecond = 0;
// =====================================================
// FORMAT WAKTU
// =====================================================
String getTimeString()
{
int menit = remainingSeconds / 60;
int detik = remainingSeconds % 60;
char buffer[10];
sprintf(buffer, "%02d:%02d", menit, detik);
return String(buffer);
}
// =====================================================
// TAMPILKAN KE P10
// =====================================================
void displayTime()
{
String waktu = getTimeString();
dmd.clearScreen(true);
dmd.selectFont(SystemFont5x7);
/*
P10 = 32 x 16 pixel
Arial Black 16:
"00:00" biasanya terlalu lebar untuk
1 panel jika menggunakan font besar.
Posisi awal dapat disesuaikan.
*/
int panjang = waktu.length();
// Untuk Arial Black 16
// posisi kira-kira di tengah
int x = 1;
int y = 3;
dmd.drawString(
x,
y,
waktu.c_str(),
panjang,
GRAPHICS_NORMAL
);
}
// =====================================================
// HALAMAN WEB
// =====================================================
void handleRoot()
{
String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport"
content="width=device-width, initial-scale=1">
<title>ESP32 P10 Countdown</title>
<style>
body {
margin: 0;
padding: 20px;
background: #101010;
color: white;
font-family: Arial;
text-align: center;
}
.container {
max-width: 420px;
margin: auto;
background: #202020;
padding: 25px;
border-radius: 20px;
}
h1 {
color: #00ff66;
}
.timer {
font-size: 55px;
font-weight: bold;
color: #00ff66;
margin: 25px 0;
}
input {
width: 90%;
padding: 15px;
margin: 8px 0;
font-size: 25px;
text-align: center;
border: none;
border-radius: 10px;
}
button {
width: 90%;
padding: 15px;
margin: 7px;
border: none;
border-radius: 10px;
font-size: 20px;
color: white;
cursor: pointer;
}
.set {
background: #3498db;
}
.start {
background: #27ae60;
}
.stop {
background: #e67e22;
}
.reset {
background: #e74c3c;
}
</style>
</head>
<body>
<div class="container">
<h1>ESP32 P10</h1>
<h2>COUNTDOWN TIMER</h2>
<div class="timer" id="timer">
00:00
</div>
<form action="/set" method="GET">
<input
type="number"
name="seconds"
min="1"
placeholder="Masukkan detik"
required
>
<br>
<button class="set" type="submit">
SET WAKTU
</button>
</form>
<button class="start"
onclick="location.href='/start'">
START
</button>
<button class="stop"
onclick="location.href='/stop'">
STOP / PAUSE
</button>
<button class="reset"
onclick="location.href='/reset'">
RESET
</button>
</div>
<script>
function updateTimer()
{
fetch('/time')
.then(response => response.text())
.then(data => {
document.getElementById("timer").innerHTML = data;
});
}
setInterval(updateTimer, 500);
updateTimer();
</script>
</body>
</html>
)rawliteral";
server.send(200, "text/html", html);
}
// =====================================================
// SET WAKTU
// =====================================================
void handleSet()
{
if (server.hasArg("seconds"))
{
long value = server.arg("seconds").toInt();
if (value > 0)
{
setSeconds = value;
remainingSeconds = value;
timerRunning = false;
displayTime();
}
}
server.sendHeader("Location", "/");
server.send(303);
}
// =====================================================
// START
// =====================================================
void handleStart()
{
if (remainingSeconds > 0)
{
timerRunning = true;
lastSecond = millis();
}
server.sendHeader("Location", "/");
server.send(303);
}
// =====================================================
// STOP / PAUSE
// =====================================================
void handleStop()
{
timerRunning = false;
server.sendHeader("Location", "/");
server.send(303);
}
// =====================================================
// RESET
// =====================================================
void handleReset()
{
timerRunning = false;
remainingSeconds = setSeconds;
displayTime();
server.sendHeader("Location", "/");
server.send(303);
}
// =====================================================
// DATA TIMER
// =====================================================
void handleTime()
{
server.send(
200,
"text/plain",
getTimeString()
);
}
// =====================================================
// SETUP
// =====================================================
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.println("WiFi AP aktif");
Serial.print("SSID: ");
Serial.println(ssid);
Serial.print("IP ESP32: ");
Serial.println(WiFi.softAPIP());
// ---------------------------------------------------
// P10
// ---------------------------------------------------
dmd.clearScreen(true);
dmd.selectFont(Arial_Black_16);
displayTime();
// ---------------------------------------------------
// TIMER REFRESH DMD32
// ---------------------------------------------------
/*
DMD32 versi lama menggunakan hardware timer ESP32.
80 = prescaler
300 = interval refresh
*/
timer = timerBegin(0, 80, true);
timerAttachInterrupt(
timer,
&triggerScan,
true
);
timerAlarmWrite(
timer,
300,
true
);
timerAlarmEnable(timer);
// ---------------------------------------------------
// WIFI ACCESS POINT
// ---------------------------------------------------
WiFi.softAP(
ssid,
password
);
Serial.println();
Serial.println("==============================");
Serial.println("ESP32 P10 COUNTDOWN");
Serial.println("==============================");
Serial.print("SSID : ");
Serial.println(ssid);
Serial.print("IP : ");
Serial.println(WiFi.softAPIP());
// ---------------------------------------------------
// WEB SERVER
// ---------------------------------------------------
server.on("/", handleRoot);
server.on("/set", handleSet);
server.on("/start", handleStart);
server.on("/stop", handleStop);
server.on("/reset", handleReset);
server.on("/time", handleTime);
server.begin();
Serial.println("Webserver aktif");
}
// =====================================================
// LOOP
// =====================================================
void loop()
{
server.handleClient();
// ---------------------------------------------------
// COUNTDOWN
// ---------------------------------------------------
if (timerRunning)
{
if (millis() - lastSecond >= 1000)
{
lastSecond += 1000;
if (remainingSeconds > 0)
{
remainingSeconds--;
displayTime();
}
// ------------------------------------------------
// SELESAI
// ------------------------------------------------
if (remainingSeconds <= 0)
{
remainingSeconds = 0;
timerRunning = false;
displayTime();
}
}
}
}
#include <WebServer.h>
#include <DMD32.h>
#include "fonts/Arial_Black_16.h"
#include "fonts/SystemFont5x7.h"
// =====================================================
// PENGATURAN P10
// =====================================================
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
// =====================================================
// TIMER REFRESH P10
// =====================================================
hw_timer_t *timer = NULL;
void IRAM_ATTR triggerScan()
{
dmd.scanDisplayBySPI();
}
// =====================================================
// WIFI
// =====================================================
const char* ssid = "P10-COUNTDOWN";
const char* password = "12345678";
WebServer server(80);
// =====================================================
// COUNTDOWN
// =====================================================
long setSeconds = 60;
long remainingSeconds = 60;
bool timerRunning = false;
unsigned long lastSecond = 0;
// =====================================================
// FORMAT WAKTU
// =====================================================
String getTimeString()
{
int menit = remainingSeconds / 60;
int detik = remainingSeconds % 60;
char buffer[10];
sprintf(buffer, "%02d:%02d", menit, detik);
return String(buffer);
}
// =====================================================
// TAMPILKAN KE P10
// =====================================================
void displayTime()
{
String waktu = getTimeString();
dmd.clearScreen(true);
dmd.selectFont(SystemFont5x7);
/*
P10 = 32 x 16 pixel
Arial Black 16:
"00:00" biasanya terlalu lebar untuk
1 panel jika menggunakan font besar.
Posisi awal dapat disesuaikan.
*/
int panjang = waktu.length();
// Untuk Arial Black 16
// posisi kira-kira di tengah
int x = 1;
int y = 3;
dmd.drawString(
x,
y,
waktu.c_str(),
panjang,
GRAPHICS_NORMAL
);
}
// =====================================================
// HALAMAN WEB
// =====================================================
void handleRoot()
{
String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport"
content="width=device-width, initial-scale=1">
<title>ESP32 P10 Countdown</title>
<style>
body {
margin: 0;
padding: 20px;
background: #101010;
color: white;
font-family: Arial;
text-align: center;
}
.container {
max-width: 420px;
margin: auto;
background: #202020;
padding: 25px;
border-radius: 20px;
}
h1 {
color: #00ff66;
}
.timer {
font-size: 55px;
font-weight: bold;
color: #00ff66;
margin: 25px 0;
}
input {
width: 90%;
padding: 15px;
margin: 8px 0;
font-size: 25px;
text-align: center;
border: none;
border-radius: 10px;
}
button {
width: 90%;
padding: 15px;
margin: 7px;
border: none;
border-radius: 10px;
font-size: 20px;
color: white;
cursor: pointer;
}
.set {
background: #3498db;
}
.start {
background: #27ae60;
}
.stop {
background: #e67e22;
}
.reset {
background: #e74c3c;
}
</style>
</head>
<body>
<div class="container">
<h1>ESP32 P10</h1>
<h2>COUNTDOWN TIMER</h2>
<div class="timer" id="timer">
00:00
</div>
<form action="/set" method="GET">
<input
type="number"
name="seconds"
min="1"
placeholder="Masukkan detik"
required
>
<br>
<button class="set" type="submit">
SET WAKTU
</button>
</form>
<button class="start"
onclick="location.href='/start'">
START
</button>
<button class="stop"
onclick="location.href='/stop'">
STOP / PAUSE
</button>
<button class="reset"
onclick="location.href='/reset'">
RESET
</button>
</div>
<script>
function updateTimer()
{
fetch('/time')
.then(response => response.text())
.then(data => {
document.getElementById("timer").innerHTML = data;
});
}
setInterval(updateTimer, 500);
updateTimer();
</script>
</body>
</html>
)rawliteral";
server.send(200, "text/html", html);
}
// =====================================================
// SET WAKTU
// =====================================================
void handleSet()
{
if (server.hasArg("seconds"))
{
long value = server.arg("seconds").toInt();
if (value > 0)
{
setSeconds = value;
remainingSeconds = value;
timerRunning = false;
displayTime();
}
}
server.sendHeader("Location", "/");
server.send(303);
}
// =====================================================
// START
// =====================================================
void handleStart()
{
if (remainingSeconds > 0)
{
timerRunning = true;
lastSecond = millis();
}
server.sendHeader("Location", "/");
server.send(303);
}
// =====================================================
// STOP / PAUSE
// =====================================================
void handleStop()
{
timerRunning = false;
server.sendHeader("Location", "/");
server.send(303);
}
// =====================================================
// RESET
// =====================================================
void handleReset()
{
timerRunning = false;
remainingSeconds = setSeconds;
displayTime();
server.sendHeader("Location", "/");
server.send(303);
}
// =====================================================
// DATA TIMER
// =====================================================
void handleTime()
{
server.send(
200,
"text/plain",
getTimeString()
);
}
// =====================================================
// SETUP
// =====================================================
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.println("WiFi AP aktif");
Serial.print("SSID: ");
Serial.println(ssid);
Serial.print("IP ESP32: ");
Serial.println(WiFi.softAPIP());
// ---------------------------------------------------
// P10
// ---------------------------------------------------
dmd.clearScreen(true);
dmd.selectFont(Arial_Black_16);
displayTime();
// ---------------------------------------------------
// TIMER REFRESH DMD32
// ---------------------------------------------------
/*
DMD32 versi lama menggunakan hardware timer ESP32.
80 = prescaler
300 = interval refresh
*/
timer = timerBegin(0, 80, true);
timerAttachInterrupt(
timer,
&triggerScan,
true
);
timerAlarmWrite(
timer,
300,
true
);
timerAlarmEnable(timer);
// ---------------------------------------------------
// WIFI ACCESS POINT
// ---------------------------------------------------
WiFi.softAP(
ssid,
password
);
Serial.println();
Serial.println("==============================");
Serial.println("ESP32 P10 COUNTDOWN");
Serial.println("==============================");
Serial.print("SSID : ");
Serial.println(ssid);
Serial.print("IP : ");
Serial.println(WiFi.softAPIP());
// ---------------------------------------------------
// WEB SERVER
// ---------------------------------------------------
server.on("/", handleRoot);
server.on("/set", handleSet);
server.on("/start", handleStart);
server.on("/stop", handleStop);
server.on("/reset", handleReset);
server.on("/time", handleTime);
server.begin();
Serial.println("Webserver aktif");
}
// =====================================================
// LOOP
// =====================================================
void loop()
{
server.handleClient();
// ---------------------------------------------------
// COUNTDOWN
// ---------------------------------------------------
if (timerRunning)
{
if (millis() - lastSecond >= 1000)
{
lastSecond += 1000;
if (remainingSeconds > 0)
{
remainingSeconds--;
displayTime();
}
// ------------------------------------------------
// SELESAI
// ------------------------------------------------
if (remainingSeconds <= 0)
{
remainingSeconds = 0;
timerRunning = false;
displayTime();
}
}
}
}
4. VIDEO HASILNYA







.jpeg)




