ESP8266: Hello World!
Hal besar selalu berawal dari sebuah hello world
Bayangkan jika tidak pernah terjadi hello world; tidak ada bigbang, tidak ada ikan yang melompat ke darat, tidak ada dinosaurus yang punah, tidak ada monyet yang berjalan tegap, tidak ada peradaban, tidak ada tulisan yang tidak ada kaitannya dengan judul ini. Maaf cuman ngetest GitHub Copilot, kan enak ngeblog cuma pencet tab ehehe..
Oke,..
Saya akan mencoba untuk menjalankan hello world pada beberapa protokol yang sering digunakan dalam pengembangan IoT saya tahu dengan board ESP8266.
- Serial
- Web Server (HTTP, SSE, WebSocket)
- MQTT
*Saya menggunakan PlatformIO di VS Code dan framework Arduino
Serial
Serial akan paling sering digunakan, karena ini seperti halnya console
di JavaScript yang sangat berguna untuk tahap development dan debugging, dan juga untuk upload firmware/data ke MCU.
Bedanya di Serial tidak ada fitur seperti console.time()
, console.table()
atau hal fancy JavaScript lainnya karena di Serial hanya bisa output plain text aja.
Ada beberapa board yang tidak support Serial dikarenakan beberapa faktor, misal ESP-01 yang tidak ada interface USB; untuk menggunakan Serial pada board tersebut harus menggunakan modul adapter UART seperti ini. Kapan-kapan saya akan tulis hal tersebut.
Untuk menggukanannya bisa langsung dengan fn berikut pada object Serial
:
print()
atauprintln()
untuk ouput dengan line breakprintf()
untuk output dengan specifier format
void setup(){
Serial.begin(74880);
Serial.println("Hello World!");
}
void main(){
Serial.printf("Seconds since boot: %lu", millis() / 1000);
delay(1000)
}
Hal yang perlu diperhatikan adalah bahwa Serial butuh Serial.begin()
pada block setup dengan parameter baudrate
berupa angka yang harus disamakan dengan settingan IDE, Jika mismatch maka IDE akan mengeluarkan karakter non-utf-8 atau disebut gibberish text.
Web Server
Saya menggunakan ESPAsyncWebServer karena library ini menerapkan konsep asynchronous, jadi tidak membebani main loop dan juga karena sudah support SSE dan WebSocket.
Disini saya hanya fokus pada Web Server, untuk hal lain seperti WiFi akan saya tulis di lain waktu.
Install Library
# platformio.ini
[env:development]
platform = espressif8266
board = nodemcuv2
framework = arduino
+lib_deps = ottowinter/ESPAsyncWebServer-esphome@^2.1.0
*ESPAsyncWebServer-esphome merupakan mirror fork dari repo asli, hanya saja package tersebut lebih update di PlatformIO.
Usage
Pastikan ESP dapat connect ke jaringan WiFi dan mendapatkan IP address. Oiya, contoh lengkap sudah ada pada halaman repository ESPAsyncWebServer.
Basic HTTP Web Server
Web Server ini akan menjadi dasar untuk SSE dan WebSocket.
#include <ESPAsyncWebServer.h>
#include "config.h"
AsyncWebServer server(80);
void setup() {
Serial.begin(74880);
// Connect ke WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.printf("WiFi Failed!\n");
return;
}
server.on("/hello", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Hello World!");
});
server.begin();
}
void loop() {
// server tidak berjalan pada main loop
}
Akan saya sedikit jelaskan kode di atas,..
Pertama include library-nya, lalu buat instance AsyncWebServer
baru dengan parameter port
yang akan digunakan, disini saya buat bernama server
menggunakan port default HTTP: 80
.
Lalu pada block setup()
, register handler untuk:
- URL
/hello
- method
HTTP_GET
dengan response:
- mimetype
text/plain
- content
Hello World!
Terakhir kita jalankan server dengan invoke server.begin()
.
Karena library ini full asynchronous, maka tidak perlu menggunakan loop()
untuk menjalankan server. Semua event berjalan berdasarkan callback yang sudah disediakan oleh library.
Setelah upload program tersebut, coba buka browser dan akses URL http://<ip_esp>/hello
maka akan muncul response text: Hello World!
Static File Serving
Jika ingin menjalankan server dengan file statis, seperti HTML, CSS, JavaScript, atau image bisa menggunakan AsyncWebServer::serveStatic()
.
buat file index.html
:
<!-- {projectRoot}/data/www/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>ESP8266</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
Ada 2 pilihan filesystem yang bisa digunakan; SPIFFS dan LittleFS. Gunakan LittleFS karena SPIFFS sudah tidak didukung lagi, hanya tinggal menunggu waktu.
# platformio.ini
[env:development]
platform = espressif8266
board = nodemcuv2
framework = arduino
lib_deps = ottowinter/ESPAsyncWebServer-esphome@^2.1.0
+board_build.filesystem = littlefs
upload file yang ada di folder data ke MCU:
$ pio run -t uploadfs
Ada sedikit tambahan untuk menjalankan server dengan file statis.
#include <LittleFS.h>
...
setup() {
LittleFS.begin();
...
server.serveStatic("/", LittleFS, "/www/").setDefaultFile("index.html");
...
server.begin()
}
SSE (Server Sent Events)
SSE adalah protokol satu arah dimana server dapat mengirimkan data dalam sebuah event ke client kapanpun server mau, tanpa harus menunggu client mengirimkan request. SSE cocok untuk mengirimkan data secara realtime, seperti data dari sensor.
Untuk SSE hanya perlu attach instance AsyncEventSource
ke AsyncWebServer
sebagai handler.
...
AsyncWebServer server(80);
AsyncEventSource events("/events");
setup() {
...
server.addHandler(&events);
...
server.begin()
}
Untuk mengirim pesan, AsyncEventSource
memiliki method send()
yang membutuhkan 3 parameter:
message
: const char *event
: const char *id
: uint32_t
Misal kita ingin mengirimkan event "hello"
dengan pesan "Hello World!"
dan id generated dari millis()
:
events.send("Hello World!", "hello", millis());
Pada sisi client kita harus buat instance EventSource
dengan endpoint yang sama dengan AsyncEventSource
tadi. Contoh minimal JavaScript di sisi client:
if (!!window.EventSource) {
const source = new EventSource('/events')
source.addEventListener(
'open',
function (e) {
console.log('Events Connected')
},
false
)
source.addEventListener(
'error',
function (e) {
if (e.target.readyState != EventSource.OPEN) {
console.log('Events Disconnected')
}
},
false
)
source.addEventListener(
'hello',
function (e) {
console.log('message:', e.data)
},
false
)
}
contoh lengkap SSE dengan event waktu booting ESP:
// src/main.cpp
#include <ESPAsyncWebServer.h>
#include <LittleFS.h>
#include "config.h"
AsyncWebServer server(80);
AsyncEventSource events("/events");
void setup() {
Serial.begin(74880);
// start file system
LittleFS.begin();
// connect to WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.printf("WiFi Failed!\n");
return;
}
// attach SSE handler
server.addHandler(&events);
// serve static files
server.serveStatic("/", LittleFS, "/www/").setDefaultFile("index.html");
// start the server
server.begin();
}
void loop() {
// send SSE event every second
static char temp[128];
sprintf(temp, "Seconds since boot: %lu", millis() / 1000);
events.send(temp, "time", millis() / 1000);
delay(1000);
}
<!-- data/www/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>SSE Test ESP8266</title>
</head>
<body>
<p>press F12 to open devtool.</p>
<script>
if (!!window.EventSource) {
const source = new EventSource('/events')
source.addEventListener(
'open',
function (e) {
console.log('Events Connected')
},
false
)
source.addEventListener(
'error',
function (e) {
if (e.target.readyState != EventSource.OPEN) {
console.log('Events Disconnected')
}
},
false
)
source.addEventListener(
'time',
function (e) {
console.log({ timeMessage: e.data })
},
false
)
}
</script>
</body>
</html>
masih males ngelanjutin, panjang juga ternyata..