Blog Archive

Arduino Indonesia. Gambar tema oleh Storman. Diberdayakan oleh Blogger.

Supported by Electronics 3 in 1

1. Jasa pencetakan PCB single layer dengan harga paling murah.

(Metode Pembuatan dengan Transfer Toner)
>PCB design sendiri (siap cetak) : Rp.150,-/Cm2
>PCB design dari kami : Rp.250,-/Cm2

(Metode Sablon Full Masking dan Silk Screen minimal pemesanan 100 Pcs)
>PCB design sendiri (siap cetak) : Rp.200,-/Cm2
>PCB design dari kami : Rp.250,-/Cm2

2. Jasa perancangan, perakitan, dan pembuatan trainer pembelajaran elektronika untuk SMK dan Mahasiswa.

3. Jasa perancangan, perakitan, dan pembuatan berbagai macam kontroller, sensor, aktuator, dan tranduser.
>Design Rangkaian / Sistem Elektronika
>Design Rangkaian / Sistem Instrumentasi
>Design Rangkaian / Sistem Kendali
>Kerjasama Riset (data atau peralatan)
>Kerjasama Produksi Produk-Produk KIT Elektronika
>Produksi Instrumentasi Elektronika

4. Jasa Pembuatan Proyek, Tugas Akhir, Tugas Laboratorium, PKM, Karya Ilmiah, SKRIPSI, dll

Like My Facebook

Popular Posts

Minggu, 26 Juli 2026

DIYables ESP32 Web Apps Web Plotter - Cara Membuat Serial Plotter Berbasis Web pada ESP32

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.  

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