ESP32 Web Server: Kawal Relay dari Browser Tanpa App atau Akaun

Cartoon of a laptop showing a large teal toggle switch, sending signal arcs through a white WiFi router to a red relay module with a blue relay cube that runs a cream desk fan, beside a crossed-out grey cloud

Ya β€” ESP32 itu sendiri yang menjadi hos halaman kawalannya: flash sketch di bawah, buka http://esp32.local/ atau alamat IP board itu dalam mana-mana browser pada WiFi yang sama, dan dua butang akan menyuis modul relay 5 V yang didawai dengan tiga jumper wire. Tiada apa-apa untuk dipasang pada telefon, tiada akaun, tiada internet β€” permintaan itu langsung tidak keluar daripada router anda.

Apa yang anda perlukan untuk kawal relay dari browser?

ESP32 DevKit ialah keseluruhan server dalam binaan ini, dan setiap rantai di sini duduk di dalam rumah anda sendiri: browser meminta satu halaman daripadanya, board menjawab melalui WiFi anda, dan salah satu pinnya memacu modul relay yang kontaknya menyuis beban sebenar β€” kipas 12 V, jalur LED atau pam.

Pilihan β€” tapak expansion bila satu relay bertukar jadi tiga

ItemPriceQty
NodeMCU ESP32 Wi-Fi + Bluetooth Development Board CH340/CP2012 - For IOT Project - ESP32 30PIN EXPANSION BOARDNodeMCU ESP32 Wi-Fi + Bluetooth Development Board CH340/CP2012 - For IOT Project - ESP32 30PIN EXPANSION BOARD32DEVBD-X32ECH34RM8.90

Expansion board 30 pin pilihan yang memang muat DevKit ini: ada jack barrel DC untuk input 6.5–16 V dan setiap pin dipecahkan keluar bersebelahan rel 5 V dan GND masing-masing. Tapak yang kemas apabila satu relay bertukar menjadi tiga.

Breakout pada expansion board itu ialah pin male, jadi pasangkannya dengan jumper female-to-female. Dua komponen berdekatan sengaja ditinggalkan: ESP32-C2 ungu itu ialah board ESP-IDF yang memang tidak dibawa oleh boards manager Arduino yang standard, dan board relay merah yang sama ini turut hadir dengan gegelung 12 V β€” beli yang itu hanya kalau sistem anda memang sudah berjalan atas rel 12 V.

Bagaimana sebuah web server boleh muat di dalam ESP32?

Library WebServer dalam core ESP32 sebenarnya hanyalah satu soket ditambah satu jadual carian. WebServer server(80) memberitahu cip itu supaya mendengar pada port TCP 80, iaitu port yang digunakan browser untuk alamat http:// biasa. Buka http://192.168.1.50/on dan browser menghantar satu baris teks: GET /on HTTP/1.1.

Setiap server.on("/on", handleOn) menambah satu baris pada jadual itu β€” laluan /on dipetakan kepada fungsi C bernama handleOn. Pasangan itulah yang dipanggil route. server.handleClient(), yang dipanggil dari loop(), memeriksa sama ada ada permintaan sedang menunggu, membaca laluannya, mencari baris yang sepadan lalu memanggil fungsi tersebut; fungsi itu menulis teks balik melalui sambungan yang sama dengan server.send(), dan browser melukiskannya.

Tiada apa-apa lagi yang terlibat, dan itulah sebabnya tiada akaun untuk didaftarkan. Paket bergerak browser β†’ router β†’ ESP32 dan balik semula, jadi suis ini terus berfungsi walaupun talian internet anda putus β€” hanya WiFi yang perlu hidup. Sisi sebaliknya: ia hanya berfungsi dalam rangkaian anda sendiri, dan itulah yang ditukar oleh panduan kawalan telefon Blynk kami dengan satu lompatan cloud supaya ia sampai kepada anda atas data mudah alih. Ia juga bermakna kata laluan WiFi anda ialah satu-satunya kunci pada halaman itu: sesiapa yang sudah berada dalam rangkaian boleh membukanya, jadi kekalkan board itu pada rangkaian yang anda kawal, bukan rangkaian yang diedar ke sana ke mari.

Rajah kartun sebuah laptop memaparkan togol teal menghantar anak panah teal melalui router WiFi putih ke board ESP32 hitam yang menjawab balik, dengan tiga jumper wire menyambung terus ke modul relay merah
Gelung permintaan berhenti di board itu sendiri. Browser bertanya, ESP32 sendiri yang menjawab dengan halaman itu, dan barulah satu pin menggerakkan relay – tiada server lain di mana-mana sepanjang laluan itu.

Nak tengok dulu bagaimana ia menyajikan halaman pertamanya?

Bagaimana cara mendawai modul relay ke ESP32?

Bahagian kawalan modul relay 1 saluran ini ialah terminal skru 3 jalur bertanda IN, DCβˆ’ dan DC+, bukan pin header β€” sebab itulah jumper male-to-female: hujung female mencengkam pin DevKit, hujung male yang telanjang diapit di bawah skru. Tiga wayar, tanpa breadboard, tiada apa-apa untuk dipateri.

Terminal relay Pin DevKit Sebabnya
DC+ VIN Gegelung itu ialah elektromagnet 5 V; VIN membawa 5 V dari port USB terus masuk
DCβˆ’ GND Laluan balik yang dikongsi untuk arus gegelung dan untuk isyarat kawalan
IN D26 GPIO26 β€” pin output penuh biasa yang senyap sepanjang boot

Suap gegelung itu dari VIN, bukan dari pin 3V3, dan angkanya yang menjelaskan sebabnya. Gegelung SRD-05VDC berukuran kira-kira 70 Ξ©, jadi 5 V menolak lebih kurang 71 mA menerusinya β€” remeh sahaja bagi kuasa USB β€” tetapi Songle menetapkan pull-in pada 75% daripada voltan gegelung terkadar, iaitu kira-kira 3.75 V, jadi 3.3 V mungkin langsung tidak berjaya menarik angker itu menyeberang. Panduan kuasa ESP32 kami membincangkan bahagian bekalan.

Letakkan jumper trigger hitam modul itu pada H, iaitu kedudukan high-level, dan RELAY_ON menjadi HIGH. Jumper itu ialah header tiga pin di sepanjang tepi bawah board, bersebelahan terminal IN/DCβˆ’/DC+: pin tengah ialah pin common dan dua pin luar bertanda silkscreen L di sebelah kiri dan H di sebelah kanan, jadi shunt hitam itu merapatkan pin tengah dengan pin sebelah kanan. Pada H, LED optocoupler dipacu dari IN turun ke DCβˆ’ melalui perintang 1 kΞ© modul itu sendiri, jadi keadaan tinggi 3.3 V menolak lebih kurang 2 mA menerusinya β€” beban yang disumberkan pin ESP32 dengan selesa β€” dan 0 V mematikannya terus. L pula ialah perangkap pada board 3.3 V: di situ LED yang sama tergantung pada rel DC+ modul, dan ia terus mengalirkan arus sehingga IN naik sampai dalam lingkungan 1.5 V daripada rel tersebut, iaitu kira-kira 3.5 V pada modul 5 V (skematik modul ini yang dijejak semula). Keadaan tinggi 3.3 V tidak pernah sampai ke garisan itu, jadi apabila duduk pada L relay itu akan menarik masuk sebaik sahaja modul dikuasakan dan tidak pernah melepas.

GPIO26 dipilih atas sebab yang sama. Semasa reset, ESP32 membaca strapping pinnya β€” GPIO0, 2, 5, 12 dan 15 β€” untuk menentukan cara ia perlu boot, dan menggoyangkan pin-pin itu sepanjang ia menimbang, yang membuatkan relay berdetik pada setiap restart. GPIO34, 35, 36 dan 39 gagal dengan cara yang lain pula: ia pad input sahaja tanpa pemacu output, jadi ia langsung tidak boleh menyuis apa-apa. GPIO26 tiada kedua-dua masalah itu, dan sementara ia masih input yang belum dikonfigur semasa kuasa dihidupkan, ia tidak menyumberkan apa-apa ke dalam rantaian kedudukan H, jadi relay bermula dalam keadaan mati.

Beban pula duduk di tepi yang bertentangan: positif daripada bekalannya sendiri masuk ke COM, keluar dari NO (normally open) ke beban, dan negatif beban itu terus balik ke bekalan yang sama β€” mati sehinggalah relay menarik masuk. Dawaikannya ke NC pula, maka beban itu hidup sehinggalah relay menyala. Tiga terminal itu ialah suis mekanikal yang tertutup di dalam kiub biru, terasing daripada gegelung dan daripada ESP32, jadi bekalan beban itu tidak perlu berkongsi ground dengan board. Kekalkan ia pada DC voltan rendah: kiub biru itu membawa rating kontak bersaiz mains, tetapi menyuis mains memerlukan enclosure, jarak creepage dan strain relief yang memang tiada pada board terdedah di atas meja. Panduan keselamatan relay kami menerangkan bahagian itu.

Kartun close-up modul relay merah dengan kiub relay biru, tiga jumper wire diapit dalam terminal skru birunya, dan shunt jumper trigger hitam ditandakan dengan bulatan teal
Bahagian kawalan ialah terminal skru, bukan pin header β€” hujung male jumper yang telanjang diapit di bawah skru, dan shunt trigger hitam duduk pada pasangan pin high-level.

Macam mana rupa sketch web server ESP32 ini?

Sketch ESP32 ini hanya perlukan library yang memang sudah dipasang oleh core ESP32 β€” WiFi.h, WebServer.h dan ESPmDNS.h. Core itulah satu-satunya benda yang Arduino IDE yang baru masih perlukan: tampal URL pakej board daripada Espressif ke dalam Preferences β†’ Additional Boards Manager URLs, kemudian pasang esp32 by Espressif Systems daripada Boards Manager. Tanpanya tiada entri ESP32 Dev Module dan tiada WebServer.h. Pilih board itu, isikan nama rangkaian 2.4 GHz dan kata laluan anda, dan upload. Satu keputusan reka bentuk di sini berbaloi ditiru: /on dan /off langsung tidak melukis halaman sendiri. Kedua-duanya menukar relayState, kemudian menjawab dengan redirect HTTP 303 balik ke /, yang membina semula halaman itu daripada pemboleh ubah tersebut β€” jadi halaman itu melaporkan apa yang relay betul-betul sedang buat, dan satu refresh akan meminta semula / dan bukannya menembak arahan terakhir sekali lagi.

// Relay web server ESP32 - suis relay dari mana-mana browser pada WiFi anda sendiri.
// Tiada app, tiada akaun cloud, tiada internet diperlukan. Board: ESP32 Dev Module.

#include <WiFi.h>
#include <WebServer.h>   // terkandung dalam core ESP32 - tiada apa nak dipasang
#include <ESPmDNS.h>     // membolehkan board menyahut nama esp32.local

const char WIFI_SSID[] = "YourWiFiName";       // mesti rangkaian 2.4 GHz
const char WIFI_PASS[] = "YourWiFiPassword";
const char HOSTNAME[]  = "esp32";              // menjadi http://esp32.local/

const int RELAY_PIN = 26;      // silkscreen D26 - bukan strapping pin
const int RELAY_ON  = HIGH;    // jumper trigger pada H: pacu IN tinggi = hidup
const int RELAY_OFF = LOW;

bool relayState = false;       // satu-satunya keadaan sebenar, disimpan pada board
WebServer server(80);          // HTTP mendengar pada port 80

void applyRelay() {
  digitalWrite(RELAY_PIN, relayState ? RELAY_ON : RELAY_OFF);
}

// Halaman ini DIBINA daripada relayState setiap kali ia diminta,
// jadi satu refresh sentiasa menunjukkan apa yang relay betul-betul sedang buat.
String buildPage() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>"
                "<meta name='viewport' content='width=device-width,initial-scale=1'>"
                "<title>ESP32 Relay</title><style>"
                "body{font-family:sans-serif;text-align:center;margin-top:12vh}"
                "a{display:inline-block;padding:18px 40px;margin:8px;border-radius:12px;"
                "color:#fff;font-size:20px;text-decoration:none}"
                ".on{background:#0a7d5a}.off{background:#9b2226}</style></head><body>";
  html += "<h1>Relay is ";
  html += relayState ? "ON" : "OFF";
  html += "</h1><p><a class='on' href='/on'>Turn ON</a>"
          "<a class='off' href='/off'>Turn OFF</a></p></body></html>";
  return html;
}

// Selepas bertindak, hantar browser balik ke "/" supaya refresh halaman
// tidak menembak arahan yang sama sekali lagi.
void redirectHome() {
  server.sendHeader("Location", "/");
  server.send(303, "text/plain", "");
}

void handleRoot() { server.send(200, "text/html", buildPage()); }
void handleOn()   { relayState = true;  applyRelay(); redirectHome(); }
void handleOff()  { relayState = false; applyRelay(); redirectHome(); }

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
  applyRelay();                       // relay MATI sebelum apa-apa yang lain berjalan
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.setHostname(HOSTNAME);         // mesti ditetapkan SEBELUM begin()
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Open http://");
  Serial.print(WiFi.localIP());       // catatkan alamat ini
  Serial.println("/ in any browser on this WiFi");

  if (MDNS.begin(HOSTNAME)) {         // hanya berfungsi selepas WiFi tersambung
    MDNS.addService("http", "tcp", 80);
    Serial.println("Also try http://esp32.local/");
  }

  // Setiap server.on() memetakan satu laluan URL kepada satu fungsi C - itulah "route"
  server.on("/",    handleRoot);
  server.on("/on",  handleOn);
  server.on("/off", handleOff);
  server.onNotFound([]() { server.send(404, "text/plain", "No such page"); });
  server.begin();
}

void loop() {
  server.handleClient();   // periksa permintaan yang menunggu dan jawab
}

Ia dikompil menjadi 956,512 bait β€” 72% daripada partition app 1,310,720 bait dalam skema 4 MB lalai, jadi tiada apa yang perlu dipartition semula. Buka Serial Monitor pada baud 115200 selepas upload: board itu akan mencetak alamat yang perlu anda taip ke dalam mana-mana browser pada WiFi yang sama.

Bagaimana nak capai board itu β€” esp32.local atau alamat IP tetap?

Library ESPmDNS memberi board itu satu nama tanpa perlu ada server DNS di mana-mana. MDNS.begin("esp32") menyertai kumpulan multicast 224.0.0.251 dan mendengar pada port UDP 5353; apabila sesebuah peranti dalam LAN bertanya kuat-kuat “siapa esp32.local?”, board itu menjawab dengan alamatnya. Satu laungan dan satu jawapan β€” itulah sebabnya ia tidak pernah melintasi router anda.

Halangannya, peranti yang bertanya itu pula mesti tahu bercakap mDNS. macOS, iOS, Windows 10 ke atas dan kebanyakan desktop Linux memang tahu. Android hanya mula menyelesaikan .local dalam browser bermula Android 12, dan itu pun tidak konsisten β€” pada banyak telefon alamat itu sekadar time out. Rangkaian guest dan router yang menghidupkan client isolation menyekat multicast terus.

Jadi anggap esp32.local sebagai kemudahan, dan alamat tetap sebagai kebolehpercayaan. Oleh sebab sketch ini memanggil WiFi.setHostname("esp32") sebelum menyambung, board itu akan muncul dengan nama tersebut dalam senarai peranti bersambung pada router anda; catatkan alamat MAC di sebelahnya dan tambah satu DHCP reservation yang mengikat MAC itu kepada alamat pilihan anda. Router kemudian akan memberi board itu alamat yang sama pada setiap boot β€” lebih selamat daripada menetapkan IP statik dalam kod yang boleh berlanggar dengan kolam lease router itu sendiri.

Halaman admin setiap router menyusun tetapan ini dengan cara berbeza:

WebServer.h atau ESPAsyncWebServer β€” yang mana patut anda guna?

ESPAsyncWebServer ialah pilihan kebanyakan contoh web server ESP32, dan untuk sekadar satu suis lampu ia tidak membawa apa-apa selain dua pemasangan tambahan: server itu sendiri berserta lapisan AsyncTCP-nya, yang perlu dipadankan versinya antara satu sama lain dan dengan core anda. WebServer.h pula datang terus bersama core ESP32.

WebServer.h (core) ESPAsyncWebServer
Pemasangan diperlukan Tiada Dua library
Siapa yang menjalankannya handleClient() dalam loop() anda Callback stack TCP
Client serentak Satu Beberapa
loop() yang lambat Melambatkan setiap permintaan Tidak menyekat permintaan
WebSocket, muat naik fail Menyusahkan Sedia terbina

Bezanya ialah siapa yang memiliki masa menunggu itu. handleClient() melayan satu permintaan penuh di dalam loop() anda, jadi tiada apa yang dijawab semasa kod anda sendiri sedang sibuk β€” walaupun begitu, apabila tiada permintaan menunggu ia kembali hampir serta-merta, dan itulah sebabnya dua pautan dan satu relay tidak pernah terasa lembap. ESPAsyncWebServer pula berjalan atas task FreeRTOS-nya sendiri yang dikejutkan oleh stack TCP apabila satu paket tiba, jadi loop() anda memang tiada dalam laluan itu langsung. Itulah keseluruhan maksud baris “tidak menyekat permintaan” di atas. Naik taraf apabila anda menambah kemas kini sensor secara langsung melalui WebSocket, menyajikan fail dari LittleFS, atau menjangka satu rumah penuh telefon menyambung serentak.

Kesilapan biasa yang kami nampak daripada pelanggan sebenar

Cuba menyertai rangkaian 5 GHz. Radio ESP32 ialah 2.4 GHz sahaja, jadi SSID yang 5 GHz sahaja memang tidak kelihatan olehnya dan Serial Monitor akan mencetak titik menyambung sampai bila-bila. Router yang menyiarkan kedua-dua band di bawah satu nama biasanya menjadi; kalau tidak, pisahkan kedua-duanya dan beri board itu yang 2.4 GHz.

Membuka halaman itu dari data mudah alih atau rangkaian guest. Halaman ini tiada alamat awam β€” ia hanya wujud dalam LAN anda β€” jadi telefon yang jatuh ke 4G, atau yang menyertai SSID guest, akan time out persis seperti board yang mati.

Meletakkan delay() dalam loop(). Permintaan hanya dijawab apabila handleClient() berjalan, jadi satu delay(2000) di sebelahnya membuatkan halaman itu mengambil masa sampai dua saat untuk menjawab. Kira masa untuk kerja yang lambat dengan millis().

Upload melalui kabel USB jenis cas sahaja. Board itu hidup dan nampak elok, tetapi tiada port serial yang muncul β€” dua daripada empat wayar kabel itu memang tiada. Itulah gunanya kabel data USB-C dalam senarai komponen. Kalau port itu muncul tetapi upload tersekat pada Connecting........, tekan dan tahan butang BOOT pada board sehingga titik-titik itu mula bergerak; kalau port itu masih menyorok, panduan baiki upload ESP32 kami menyusuri keseluruhan rantaian itu.

Soalan Lazim

Kenapa esp32.local menjadi pada laptop saya tetapi tidak pada telefon Android?

Sebab telefon itu, bukan board, yang menyelesaikan nama tersebut. Android hanya menambah carian .local dalam browser bermula Android 12, dan sokongannya tidak seragam. Guna alamat IP board itu pada telefon berkenaan, dan kekalkannya dengan satu DHCP reservation dalam router anda.

Boleh tak saya suis relay ini semasa berada jauh dari rumah?

Tidak boleh dengan sketch ini, dan itu memang disengajakan. Jangan port-forward halaman ini juga β€” ia tiada login, jadi sesiapa yang menemui alamatnya boleh mengendalikan relay anda. Untuk kawalan dari luar, gunakan pautan cloud yang dilindungi akaun seperti binaan kawalan telefon Blynk kami.

Kenapa relay saya berdetik sendiri apabila ESP32 restart?

Wayar IN itu berada pada strapping pin β€” GPIO0, 2, 5, 12 atau 15 β€” yang digoyangkan cip pada setiap reset sementara ia menentukan cara untuk boot. Pindahkannya ke output penuh yang senyap β€” GPIO26, 27, 25 atau 33.

Boleh tak saya guna modul relay 12 V sebaliknya?

Untuk beban 12 V, biasanya anda tidak perlu. Voltan gegelung dan voltan beban ialah dua perkara yang berasingan β€” kontak modul 5 V itu dicetak 10 A 30 V DC, jadi ia memang sudah boleh menyuis kipas 12 V sementara gegelungnya berjalan atas kuasa USB. Versi 12 V itu untuk binaan yang satu-satunya relnya ialah 12 V: DC+ ke bekalan tersebut, DCβˆ’ ke ground yang dikongsi dengan ESP32, IN kekal ke D26 dan jumper kekal pada H β€” pada H, optocoupler menyuis pada kira-kira 1.5 V di atas DCβˆ’ tidak kira apa voltan gegelungnya, jadi logik 3.3 V memacunya sama sahaja. Pindahkan jumper itu ke L pada modul 12 V dan relay tidak akan pernah melepas, kerana IN terpaksa naik sampai dalam lingkungan 1.5 V daripada 12 V untuk mematikannya β€” dan input modul yang dirujuk kepada 12 V itu kemudiannya duduk berhadapan pin 3.3 V, iaitu bukan keadaan yang patut dibiarkan pada satu GPIO. Gegelung 12 V yang disuap dari pin VIN 5 V DevKit pula memang langsung tidak akan menarik masuk.

Boleh tak saya tambah lebih banyak relay pada halaman yang sama?

Boleh. Beri setiap relay pin dan pemboleh ubah keadaannya sendiri, tambah sepasang route server.on() bagi setiap relay, dan bina halaman itu daripada kesemuanya. Setiap gegelung 5 V menambah kira-kira 71 mA, jadi selepas dua atau tiga, suap modul-modul itu daripada bekalan 5 V mereka sendiri dengan ground diikat bersama.

Kartun binaan atas meja: laptop memaparkan halaman togol teal di sebelah board ESP32 hitam kecil yang didawai tiga jumper ke modul relay merah yang memutarkan kipas meja krim
Meja yang siap: kuasa USB masuk, tiga wayar kawalan menyeberang ke relay, beban voltan rendah pada terminal skru, dan halaman kawalan terbuka pada laptop yang memang sudah berada pada WiFi yang sama.

Sebaik board itu menyajikan halamannya sendiri, selebihnya hanyalah lebih banyak route: bacaan sensor di sebelah butang, relay kedua, satu jadual yang menyalakannya waktu senja. Nak ia disuis dengan suara pula? Relay kawalan suara offline kami memacu modul yang sama ini tanpa rangkaian langsung.

Kemas kini terakhir Ogos 2026. Tersangkut? Chat dengan kami di WhatsApp.

2 thoughts on “ESP32 Web Server: Kawal Relay dari Browser Tanpa App atau Akaun”

  1. Pingback: 10 Idea Projek IoT untuk FYP dan Projek Tahun Akhir

  2. Pingback: Modul Relay WiFi ESP-01S: Cara Flash dan Wayar Beban

Leave a Reply

Your email address will not be published. Required fields are marked *