Saat mengembangkan proyek Internet of Things (IoT) menggunakan ESP32, proses memantau data sensor secara real-time merupakan salah satu tahap yang sangat penting. Biasanya, data tersebut ditampilkan melalui Serial Plotter di Arduino IDE. Namun, cara ini mengharuskan ESP32 selalu terhubung ke komputer melalui kabel USB. Melalui tutorial ini, Anda akan mempelajari cara membuat Web Plotter berbasis ESP32 yang memiliki fungsi serupa dengan Serial Plotter Arduino IDE, tetapi dapat diakses langsung melalui web browser pada komputer, laptop, maupun smartphone. Dengan memanfaatkan Web Server dan WebSocket, ESP32 dapat mengirimkan data secara real-time sehingga grafik akan diperbarui secara langsung tanpa perlu me-refresh halaman. Metode ini sangat berguna untuk berbagai aplikasi monitoring, seperti menampilkan data suhu, kelembapan, intensitas cahaya, tegangan, hingga berbagai data sensor lainnya secara visual melalui jaringan WiFi.
Perangkat Keras yang Dibutuhkan
- ESP32 Dev Module (ESP-WROOM-32 38 Pin)
- Kabel USB (Micro USB atau USB Type-C sesuai board yang digunakan)
Cara Kerja Web Plotter pada ESP32
Sebelum masuk ke proses pemrograman, ada baiknya memahami terlebih dahulu bagaimana sistem Web Plotter ini bekerja. Secara umum, komunikasi antara ESP32 dan web browser dilakukan menggunakan teknologi WebSocket, yaitu protokol komunikasi dua arah (full-duplex) yang memungkinkan pertukaran data secara cepat tanpa perlu melakukan refresh halaman web. Alur kerjanya adalah sebagai berikut:
1. ESP32 menjalankan Web Server sekaligus WebSocket Server.
Setelah ESP32 berhasil terhubung ke jaringan WiFi, board akan membuat sebuah Web Server yang bertugas mengirimkan halaman web serta sebuah WebSocket Server untuk mengirimkan data secara real-time.
2. Pengguna membuka alamat IP ESP32 melalui browser.
Ketika alamat IP ESP32 diakses menggunakan browser pada komputer atau smartphone, Web Server akan mengirimkan file halaman web yang berisi HTML, CSS, dan JavaScript.
3. Browser menampilkan antarmuka Web Plotter.
JavaScript yang terdapat pada halaman web akan membuat tampilan grafik yang menyerupai Serial Plotter pada Arduino IDE.
4. Pengguna menekan tombol CONNECT.
Setelah tombol CONNECT diklik, JavaScript akan membangun koneksi WebSocket ke ESP32.
5. ESP32 mengirimkan data secara real-time.
Data yang dihasilkan ESP32 akan dikirim melalui koneksi WebSocket tanpa harus memuat ulang (reload) halaman web.
6. Browser menggambar grafik secara langsung.
Setiap data yang diterima akan diproses oleh JavaScript dan langsung ditampilkan dalam bentuk grafik secara real-time.
Dengan mekanisme tersebut, pengguna dapat memantau perubahan nilai sensor secara langsung melalui browser layaknya menggunakan Serial Plotter Arduino IDE, tetapi tanpa harus membuka Arduino IDE.
Baca juga: ESP32 Web Server Multiple Pages - Membuat Web Server ESP32 dengan Banyak Halaman Web
Format Data yang Dikirim ESP32 ke Web Plotter
Agar Web Plotter dapat menampilkan grafik dengan benar, ESP32 harus mengirimkan data menggunakan format tertentu. Jika hanya mengirimkan satu variabel, ESP32 cukup mengirimkan nilai tersebut dan mengakhirinya dengan karakter \r\n (carriage return dan newline). Namun, jika ingin menampilkan lebih dari satu variabel dalam satu grafik, setiap nilai harus dipisahkan menggunakan karakter tab (\t) atau spasi ( ). Setelah seluruh nilai dikirim, data harus diakhiri dengan karakter \r\n sebagai penanda bahwa satu paket data telah selesai dikirim. Secara rinci, format pengiriman datanya adalah sebagai berikut:
1. Variabel Pertama
webSocket->broadcastTXT(variable_1);
2. Variabel di Tengah
webSocket->broadcastTXT(" "); // Dapat menggunakan karakter tab '\t' atau spasi ' '
webSocket->broadcastTXT(variable_2);
webSocket->broadcastTXT(" ");
webSocket->broadcastTXT(variable_3);
3. Variabel Terakhir
webSocket->broadcastTXT(" ");
webSocket->broadcastTXT(variable_4);
webSocket->broadcastTXT("\r\n"); // Mengakhiri satu paket data
Catatan:
Jika format data tidak sesuai, Web Plotter tidak akan mampu membaca maupun memisahkan setiap variabel dengan benar sehingga grafik yang ditampilkan bisa menjadi tidak akurat.
Struktur Program ESP32 Web Plotter
Pada proyek ini, kode program dipisahkan menjadi dua file agar lebih rapi dan mudah dikelola.
- File .ino digunakan sebagai program utama ESP32 yang bertugas menjalankan WiFi, Web Server, dan WebSocket.
- File index.h berisi seluruh kode halaman web, seperti HTML, CSS, dan JavaScript yang akan dikirimkan ke browser.
Dengan pemisahan ini, proses pengembangan dan pemeliharaan program menjadi lebih mudah dibandingkan menuliskan seluruh kode dalam satu file.
Langkah-langkah Membuat Web Plotter pada ESP32
Ikuti langkah-langkah berikut untuk membuat Web Plotter berbasis ESP32:
1. Hubungkan ESP32 ke Komputer
Hubungkan board ESP32 ke komputer atau laptop menggunakan kabel USB.
2. Buka Arduino IDE
Jalankan Arduino IDE yang telah terinstal pada komputer Anda.
3. Pilih Board dan Port
Pilih jenis board ESP32 yang digunakan, misalnya ESP32 Dev Module, kemudian pilih port COM yang sesuai.
4. Install Library DIYables ESP32 WebServer
Buka Library Manager melalui menu di sebelah kiri Arduino IDE. Cari library DIYables ESP32 WebServer. Setelah library ditemukan, klik tombol Install untuk memasangnya.
5. Buat Sketch Baru
Buat sketch baru di Arduino IDE, kemudian simpan dengan nama, misalnya:
esp32-websocket.ino
6. Masukkan Program Utama ESP32
Salin seluruh kode program utama berikut ke dalam file esp32-websocket.ino.
#include <DIYables_ESP32_WebServer.h>
#include "index.h"
// WiFi credentials
const char WIFI_SSID[] = "YOUR_WIFI_SSID";
const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";
// Create web server instance
DIYables_ESP32_WebServer server;
DIYables_ESP32_WebSocket* webSocket;
int last_update = 0;
// Web Page handlers
void handleHome(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
// HTML_CONTENT from the index.h file
server.sendResponse(client, HTML_CONTENT);
}
// WebSocket event handlers
void onWebSocketOpen(net::WebSocket& ws) {
Serial.println("New WebSocket connection");
// Send welcome message
const char welcome[] = "Connected to ESP32 WebSocket Server!";
}
void onWebSocketMessage(net::WebSocket& ws, const net::WebSocket::DataType dataType, const char* message, uint16_t length) {
Serial.print("WebSocket Received (");
Serial.print(length);
Serial.print(" bytes): ");
Serial.println(message);
String msgStr = String(message);
String response = "";
// Broadcast response to all connected clients using the library
if (webSocket != nullptr) {
webSocket->broadcastTXT(response);
Serial.print("WebSocket sent (");
Serial.print(response.length());
Serial.print(" bytes): ");
Serial.println(response);
}
}
void onWebSocketClose(net::WebSocket& ws, const net::WebSocket::CloseCode code, const char* reason, uint16_t length) {
Serial.println("WebSocket client disconnected");
}
void setup() {
Serial.begin(9600);
delay(1000);
Serial.println("ESP32 Web Server and WebSocket Server");
// Configure web server routes
server.addRoute("/", handleHome);
// Start web server with WiFi connection
server.begin(WIFI_SSID, WIFI_PASSWORD);
// Enable WebSocket functionality
webSocket = server.enableWebSocket(81);
if (webSocket != nullptr) {
// Set up WebSocket event handlers
webSocket->onOpen(onWebSocketOpen);
webSocket->onMessage(onWebSocketMessage);
webSocket->onClose(onWebSocketClose);
} else {
Serial.println("Failed to start WebSocket server");
}
}
void loop() {
// Then handle HTTP requests
server.handleClient();
// Handle WebSocket
server.handleWebSocket();
if (millis() - last_update > 500) {
last_update = millis();
String variable_1 = String(random(0, 100));
String variable_2 = String(random(0, 100));
String variable_3 = String(random(0, 100));
String variable_4 = String(random(0, 100));
// TO SERIAL PLOTTER
Serial.print(variable_1);
Serial.print(" "); // a tab '\t' or space ' ' character is printed between the two values.
Serial.print(variable_2);
Serial.print(" "); // a tab '\t' or space ' ' character is printed between the two values.
Serial.print(variable_3);
Serial.print(" "); // a tab '\t' or space ' ' character is printed between the two values.
Serial.println(variable_4); // the last value is terminated by a carriage return and a newline characters.
// TO WEB PLOTTER
webSocket->broadcastTXT(variable_1);
webSocket->broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket->broadcastTXT(variable_2);
webSocket->broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket->broadcastTXT(variable_3);
webSocket->broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket->broadcastTXT(variable_4);
webSocket->broadcastTXT("\r\n"); // the last value is terminated by a carriage return and a newline characters.
}
}
7. Ubah Informasi WiFi
Sebelum mengunggah program, ubah bagian SSID dan password WiFi agar sesuai dengan jaringan yang akan digunakan ESP32. Pastikan jaringan WiFi menggunakan frekuensi 2,4 GHz, karena sebagian besar modul ESP32 tidak mendukung jaringan 5 GHz.
8. Buat File index.h
Selanjutnya, buat file baru bernama index.h. Caranya adalah sebagai berikut:
- Klik tombol New Tab yang berada di bawah ikon Serial Monitor, atau tekan Ctrl + Shift + N.
- Beri nama file index.h.
- Klik tombol OK.
9. Salin Kode Halaman Web
Salin seluruh kode halaman web ke dalam file index.h.
const char *HTML_CONTENT = R"=====(
<!DOCTYPE html>
<html>
<head>
<title>ESP32 - Web Plotter</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<style>
body {text-align: center; height: 750px; }
h1 {font-weight: bold; font-size: 20pt; padding-bottom: 5px; color: navy; }
h2 {font-weight: bold; font-size: 15pt; padding-bottom: 5px; }
button {font-weight: bold; font-size: 15pt; }
#footer {width: 100%; margin: 0px; padding: 0px 0px 10px 0px; bottom: 0px; }
.sub-footer {margin: 0 auto; position: relative; width:400px; }
.sub-footer a {position: absolute; font-size: 10pt; top: 3px; }
</style>
<script>
var COLOR_BACKGROUND = "#FFFFFF";
var COLOR_TEXT = "#000000";
var COLOR_BOUND = "#000000";
var COLOR_GRIDLINE = "#F0F0F0";
//var COLOR_LINE = ["#33FFFF", "#FF00FF", "#FF0000", "#FF8C00", "#00FF00"];
//var COLOR_LINE = ["#0000FF", "#FF0000", "#00FF00", "#FF8C00", "#00FF00"];
//var COLOR_LINE = ["#33FFFF", "#FF0000", "#00FF00", "#FF8C00", "#00FF00"];
var COLOR_LINE = ["#0000FF", "#FF0000", "#009900", "#FF9900", "#CC00CC", "#666666", "#00CCFF", "#000000"];
var LEGEND_WIDTH = 10;
var X_AXIS_TITLE_HEIGHT = 40;
var Y_AXIS_TITLE_WIDTH = 40;
var X_AXIS_VALUE_HEIGHT = 40;
var Y_AXIS_VALUE_WIDTH = 50;
var PLOT_AREA_PADDING_TOP = 30;
var PLOT_AREA_PADDING_RIGHT = 30;
var X_GRIDLINE_NUM = 5;
var Y_GRIDLINE_NUM = 4;
var WSP_SIZE_TYPE = 1; /* 0: Fixed size, 1: full screen */
var WSP_WIDTH = 400;
var WSP_HEIGHT = 200;
var MAX_SAMPLE = 50; // in sample
var X_AXIS_MIN = 0;
var X_AXIS_MAX = MAX_SAMPLE;
var Y_AXIS_AUTO_SCALE = 1; /* 0: y axis fixed range, 1: y axis auto scale */
var Y_AXIS_MIN = -5;
var Y_AXIS_MAX = 5;
var X_AXIS_TITLE = "X";
var Y_AXIS_TITLE = "Y";
var plot_area_width;
var plot_area_height;
var plot_area_pivot_x;
var plot_area_pivot_y;
var sample_count = 0;
var buffer = "";
var data = [];
var ws;
var canvas;
var ctx;
function init()
{
canvas = document.getElementById("graph");
canvas.style.backgroundColor = COLOR_BACKGROUND;
ctx = canvas.getContext("2d");
canvas_resize();
setInterval(update_view, 1000 / 60);
}
function connect_onclick()
{
if(ws == null)
{
ws = new WebSocket("ws://" + window.location.host + ":81");
document.getElementById("ws_state").innerHTML = "CONNECTING";
ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
ws.binaryType = "arraybuffer";
}
else
ws.close();
}
function ws_onopen()
{
document.getElementById("ws_state").innerHTML = "<span style='color: blue'>CONNECTED</span>";
document.getElementById("bt_connect").innerHTML = "Disconnect";
}
function ws_onclose()
{
document.getElementById("ws_state").innerHTML = "<span style='color: gray'>CLOSED</span>";
document.getElementById("bt_connect").innerHTML = "Connect";
ws.onopen = null;
ws.onclose = null;
ws.onmessage = null;
ws = null;
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event; // MessageEvent
console.log(e_msg.data);
buffer += e_msg.data;
buffer = buffer.replace(/\r\n/g, "\n");
buffer = buffer.replace(/\r/g, "\n");
while(buffer.indexOf("\n") == 0)
buffer = buffer.substr(1);
if(buffer.indexOf("\n") <= 0)
return;
var pos = buffer.lastIndexOf("\n");
var str = buffer.substr(0, pos);
var new_sample_arr = str.split("\n");
buffer = buffer.substr(pos + 1);
for(var si = 0; si < new_sample_arr.length; si++)
{
var str = new_sample_arr[si];
var arr = [];
if(str.indexOf("\t") > 0)
arr = str.split("\t");
else
arr = str.split(" ");
for(var i = 0; i < arr.length; i++)
{
var value = parseFloat(arr[i]);
if(isNaN(value))
continue;
if(i >= data.length)
{
var new_line = [value];
data.push(new_line); // new line
}
else
data[i].push(value);
}
sample_count++;
}
for(var line = 0; line < data.length; line++)
{
while(data[line].length > MAX_SAMPLE)
data[line].splice(0, 1);
}
if(Y_AXIS_AUTO_SCALE)
auto_scale();
}
function map(x, in_min, in_max, out_min, out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
function get_random_color()
{
var letters = '0123456789ABCDEF';
var _color = '#';
for (var i = 0; i < 6; i++)
_color += letters[Math.floor(Math.random() * 16)];
return _color;
}
function update_view()
{
if(sample_count <= MAX_SAMPLE)
X_AXIS_MAX = sample_count;
else
X_AXIS_MAX = 50;
ctx.clearRect(0, 0, WSP_WIDTH, WSP_HEIGHT);
ctx.save();
ctx.translate(plot_area_pivot_x, plot_area_pivot_y);
ctx.font = "bold 20px Arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillStyle = COLOR_TEXT;
// draw X axis title
if(X_AXIS_TITLE != "")
{
ctx.fillText(X_AXIS_TITLE, plot_area_width / 2, X_AXIS_VALUE_HEIGHT + X_AXIS_TITLE_HEIGHT / 2);
}
// draw Y axis title
if(Y_AXIS_TITLE != "")
{
ctx.rotate(-90 * Math.PI / 180);
ctx.fillText(Y_AXIS_TITLE, plot_area_height / 2, -Y_AXIS_VALUE_WIDTH - Y_AXIS_TITLE_WIDTH / 2);
ctx.rotate(90 * Math.PI / 180);
}
ctx.font = "16px Arial";
ctx.textAlign = "right";
ctx.strokeStyle = COLOR_BOUND;
for(var i = 0; i <= Y_GRIDLINE_NUM; i++)
{
var y_gridline_px = -map(i, 0, Y_GRIDLINE_NUM, 0, plot_area_height);
y_gridline_px = Math.round(y_gridline_px) + 0.5;
ctx.beginPath();
ctx.moveTo(0, y_gridline_px);
ctx.lineTo(plot_area_width, y_gridline_px);
ctx.stroke();
ctx.strokeStyle = COLOR_BOUND;
ctx.beginPath();
ctx.moveTo(-7 , y_gridline_px);
ctx.lineTo(4, y_gridline_px);
ctx.stroke();
var y_gridline_value = map(i, 0, Y_GRIDLINE_NUM, Y_AXIS_MIN, Y_AXIS_MAX);
y_gridline_value = y_gridline_value.toFixed(1);
ctx.fillText(y_gridline_value + "", -15, y_gridline_px);
ctx.strokeStyle = COLOR_GRIDLINE;
}
ctx.strokeStyle = COLOR_BOUND;
ctx.textAlign = "center";
ctx.beginPath();
ctx.moveTo(0.5, y_gridline_px - 7);
ctx.lineTo(0.5, y_gridline_px + 4);
ctx.stroke();
for(var i = 0; i <= X_GRIDLINE_NUM; i++)
{
var x_gridline_px = map(i, 0, X_GRIDLINE_NUM, 0, plot_area_width);
x_gridline_px = Math.round(x_gridline_px) + 0.5;
ctx.beginPath();
ctx.moveTo(x_gridline_px, 0);
ctx.lineTo(x_gridline_px, -plot_area_height);
ctx.stroke();
ctx.strokeStyle = COLOR_BOUND;
ctx.beginPath();
ctx.moveTo(x_gridline_px, 7);
ctx.lineTo(x_gridline_px, -4);
ctx.stroke();
var x_gridline_value;
if(sample_count <= MAX_SAMPLE)
x_gridline_value = map(i, 0, X_GRIDLINE_NUM, X_AXIS_MIN, X_AXIS_MAX);
else
x_gridline_value = map(i, 0, X_GRIDLINE_NUM, sample_count - MAX_SAMPLE, sample_count);;
ctx.fillText(x_gridline_value.toString(), x_gridline_px, X_AXIS_VALUE_HEIGHT / 2 + 5);
ctx.strokeStyle = COLOR_GRIDLINE;
}
//ctx.lineWidth = 2;
var line_num = data.length;
for(var line = 0; line < line_num; line++)
{
// draw graph
var sample_num = data[line].length;
if(sample_num >= 2)
{
var y_value = data[line][0];
var x_px = 0;
var y_px = -map(y_value, Y_AXIS_MIN, Y_AXIS_MAX, 0, plot_area_height);
if(line == COLOR_LINE.length)
COLOR_LINE.push(get_random_color());
ctx.strokeStyle = COLOR_LINE[line];
ctx.beginPath();
ctx.moveTo(x_px, y_px);
for(var i = 0; i < sample_num; i++)
{
y_value = data[line][i];
x_px = map(i, X_AXIS_MIN, X_AXIS_MAX -1, 0, plot_area_width);
y_px = -map(y_value, Y_AXIS_MIN, Y_AXIS_MAX, 0, plot_area_height);
ctx.lineTo(x_px, y_px);
}
ctx.stroke();
}
// draw legend
var x = plot_area_width - (line_num - line) * LEGEND_WIDTH - (line_num - line - 1) * LEGEND_WIDTH / 2;
var y = -plot_area_height - PLOT_AREA_PADDING_TOP / 2 - LEGEND_WIDTH / 2;
ctx.fillStyle = COLOR_LINE[line];
ctx.beginPath();
ctx.rect(x, y, LEGEND_WIDTH, LEGEND_WIDTH);
ctx.fill();
}
ctx.restore();
}
function canvas_resize()
{
canvas.width = 0; // to avoid wrong screen size
canvas.height = 0;
if(WSP_SIZE_TYPE)
{ // full screen
document.getElementById('footer').style.position = "fixed";
var width = window.innerWidth - 20;
var height = window.innerHeight - 20;
WSP_WIDTH = width;
WSP_HEIGHT = height - document.getElementById('header').offsetHeight - document.getElementById('footer').offsetHeight;
}
canvas.width = WSP_WIDTH;
canvas.height = WSP_HEIGHT;
ctx.font = "16px Arial";
var y_min_text_size = ctx.measureText(Y_AXIS_MIN.toFixed(1) + "").width;
var y_max_text_size = ctx.measureText(Y_AXIS_MAX.toFixed(1) + "").width;
Y_AXIS_VALUE_WIDTH = Math.round(Math.max(y_min_text_size, y_max_text_size)) + 15;
plot_area_width = WSP_WIDTH - Y_AXIS_VALUE_WIDTH - PLOT_AREA_PADDING_RIGHT;
plot_area_height = WSP_HEIGHT - X_AXIS_VALUE_HEIGHT - PLOT_AREA_PADDING_TOP;
plot_area_pivot_x = Y_AXIS_VALUE_WIDTH;
plot_area_pivot_y = WSP_HEIGHT - X_AXIS_VALUE_HEIGHT;
if(X_AXIS_TITLE != "")
{
plot_area_height -= X_AXIS_TITLE_HEIGHT;
plot_area_pivot_y -= X_AXIS_TITLE_HEIGHT;
}
if(Y_AXIS_TITLE != "")
{
plot_area_width -= Y_AXIS_TITLE_WIDTH;
plot_area_pivot_x += Y_AXIS_TITLE_WIDTH;
}
ctx.lineWidth = 1;
}
function auto_scale()
{
if(data.length >= 1)
{
var max_arr = [];
var min_arr = [];
for(var i = 0; i < data.length; i++)
{
if(data[i].length >= 1)
{
var max = Math.max.apply(null, data[i]);
var min = Math.min.apply(null, data[i]);
max_arr.push(max);
min_arr.push(min);
}
}
var max = Math.max.apply(null, max_arr);
var min = Math.min.apply(null, min_arr);
var MIN_DELTA = 10.0;
if((max - min) < MIN_DELTA)
{
var mid = (max + min) / 2;
max = mid + MIN_DELTA / 2;
min = mid - MIN_DELTA / 2;
}
var range = max - min;
var exp;
if (range == 0.0)
exp = 0;
else
exp = Math.floor(Math.log10(range / 4));
var scale = Math.pow(10, exp);
var raw_step = (range / 4) / scale;
var step;
potential_steps =[1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0];
for (var i = 0; i < potential_steps.length; i++)
{
if (potential_steps[i] < raw_step)
continue;
step = potential_steps[i] * scale;
Y_AXIS_MIN = step * Math.floor(min / step);
Y_AXIS_MAX = Y_AXIS_MIN + step * (4);
if (Y_AXIS_MAX >= max)
break;
}
var count = 5 - Math.floor((Y_AXIS_MAX - max) / step);
Y_AXIS_MAX = Y_AXIS_MIN + step * (count - 1);
ctx.font = "16px Arial";
var y_min_text_size = ctx.measureText(Y_AXIS_MIN.toFixed(1) + "").width;
var y_max_text_size = ctx.measureText(Y_AXIS_MAX.toFixed(1) + "").width;
Y_AXIS_VALUE_WIDTH = Math.round(Math.max(y_min_text_size, y_max_text_size)) + 15;
plot_area_width = WSP_WIDTH - Y_AXIS_VALUE_WIDTH - PLOT_AREA_PADDING_RIGHT;
plot_area_pivot_x = Y_AXIS_VALUE_WIDTH;
}
}
window.onload = init;
</script>
</head>
<body onresize="canvas_resize()">
<h1 id="header">ESP32 - Web Plotter</h1>
<canvas id="graph"></canvas>
<br>
<div id="footer">
<div class="sub-footer">
<h2>WebSocket <span id="ws_state"><span style="color: gray">CLOSED</span></span></h2>
</div>
<button id="bt_connect" type="button" onclick="connect_onclick();">Connect</button>
</div>
</body>
</html>
)=====";
10. Pastikan Terdapat Dua File Program
Setelah selesai, sketch Arduino Anda akan terdiri dari dua file berikut:
- esp32-websocket.ino
- index.h
Struktur ini memudahkan pengelolaan antara program ESP32 dan halaman web.
11. Upload Program ke ESP32
Klik tombol Upload pada Arduino IDE, kemudian tunggu hingga proses kompilasi dan pengunggahan program selesai.
12. Buka Serial Monitor
Setelah proses upload selesai, buka Serial Monitor. ESP32 akan menampilkan informasi proses koneksi ke jaringan WiFi beserta alamat IP yang diperoleh.
13. Akses Web Plotter
Catat alamat IP yang muncul pada Serial Monitor. Selanjutnya, buka browser di komputer, laptop, atau smartphone yang berada pada jaringan WiFi yang sama, kemudian ketik alamat IP tersebut pada bilah alamat browser. Contoh: http://10.252.6.32. Jika berhasil, halaman Web Plotter akan muncul seperti berikut:
14. Hubungkan Browser ke ESP32
Klik tombol CONNECT pada halaman Web Plotter. Setelah koneksi WebSocket berhasil dibuat, browser akan mulai menerima data yang dikirimkan oleh ESP32 secara real-time.
15. Amati Grafik Secara Real-Time
Begitu ESP32 mulai mengirimkan data, Web Plotter akan menampilkan grafik secara langsung. Setiap perubahan nilai akan digambar secara otomatis tanpa perlu memuat ulang halaman, sehingga proses monitoring menjadi jauh lebih praktis dibandingkan menggunakan Serial Plotter bawaan Arduino IDE.
Keunggulan Menggunakan Web Plotter ESP32
Dibandingkan menggunakan Serial Plotter Arduino IDE, Web Plotter berbasis ESP32 menawarkan beberapa kelebihan berikut:
- Dapat diakses melalui browser tanpa perlu membuka Arduino IDE.
- Mendukung berbagai perangkat, seperti komputer, laptop, tablet, maupun smartphone.
- Menggunakan komunikasi WebSocket, sehingga data dikirim secara real-time dengan latensi yang rendah.
- Tidak memerlukan koneksi USB selama ESP32 dan perangkat pengguna berada pada jaringan WiFi yang sama.
- Cocok untuk monitoring proyek IoT, terutama ketika perangkat ditempatkan di lokasi yang jauh dari komputer.
Baca juga: ESP32 WebSocket - Cara Membangun Komunikasi Real-Time antara ESP32 dan Web Browser
Dalam praktik, hasil dan kendala yang ditemui bisa berbeda tergantung perangkat, konfigurasi, versi library, dan sistem yang digunakan.
- Diskusi umum dan tanya jawab praktik: https://t.me/edukasielektronika
- Kendala spesifik dan kasus tertentu: http://bit.ly/Chatarduino



0 on: "DIYables ESP32 Web Apps Web Plotter - Cara Membuat Serial Plotter Berbasis Web pada ESP32"