📑 เนื้อหาในบทความ
🎯 OTA (Over-The-Air) คืออะไร?
OTA (Over-The-Air) เป็นเทคโนโลยีที่ช่วยให้คุณสามารถอัปเดตฟาร์มแวร์ (firmware) ของ ESP32 ผ่านทาง WiFi โดยไม่ต้องเชื่อมต่อสาย USB หรือเสียบสาย Serial Cable เข้าไปในบอร์ด
ลองนึกภาพว่าคุณมี IoT device ติดตั้งอยู่บนเพดาน หรืออยู่ในกล่องที่ปิดสนิท การถอดออกมาเพื่ออัปเดตโปรแกรมก็เป็นเรื่องยาก แต่ด้วย OTA คุณสามารถอัปเดตได้ทันทีผ่าน WiFi ได้เลย!
💡 จุดเด่นของ OTA: ช่วยประหยัดเวลาและความยุ่งยากในการบำรุงรักษา IoT devices จำนวนมาก โดยเฉพาะที่ติดตั้งในที่เข้าถึงยาก
🚀 ทำไมต้องใช้ OTA Updates?
ไม่ต้องถอดอุปกรณ์
อัปเดตฟาร์มแวร์ได้แม้ว่าอุปกรณ์จะติดตั้งอยู่บนเพดาน ฝั่งผนัง หรืออยู่ในกล่องที่ปิดสนิท
ประหยัดเวลา
อัปเดตหลายบอร์ดพร้อมกันผ่านเครือข่าย ไม่ต้องเสียบสายทีละตัว
ลดต้นทุน
ไม่ต้องเดินทางไปยังตำแหน่งติดตั้ง IoT device แต่ละตัว
อัปเดตได้ตลอดเวลา
แก้ไข bug หรือเพิ่มฟีเจอร์ใหม่ได้ทันที โดยไม่กระทบผู้ใช้งาน
📋 ข้อกำหนดเบื้องต้น (Prerequisites)
🛠️ Hardware
- ESP32 Board (รุ่นใดก็ได้: DevKit, NodeMCU, Wroom, Wrover)
- สาย USB สำหรับอัปโหลดครั้งแรก
- เครือข่าย WiFi 2.4GHz (ต้องเชื่อมต่อเครือข่ายเดียวกับคอมพิวเตอร์)
💻 Software
- Arduino IDE 2.x หรือ PlatformIO
- ESP32 Board Library (ล่าสุด)
- ArduinoOTA library (มีให้ใช้แล้วใน Arduino IDE)
- Network Tools อย่าง Advanced IP Scanner หรือ nmap
⚠️ ข้อจำกัดที่ต้องรู้
- • OTA partition ต้องมีขนาดอย่างน้อย 1.5 เท่าของ sketch
- • ครั้งแรกต้องอัปโหลดผ่าน USB เสมอ
- • WiFi ต้องเสถียร ไม่งั้นอัปเดตจนกลางคันอาจทำให้บอร์ดเสียหาย
- • OTA ขนาดใหญ่อาจใช้เวลานาน (ขึ้นกับความเร็ว WiFi)
🔥 ตัวอย่างที่ 1: Basic OTA (OTA พื้นฐาน)
Step 1: อัปโหลดโค้ดครั้งแรกผ่าน USB
อัปโหลดโค้ดนี้ผ่านสาย USB ครั้งแรกเพื่อเปิดใช้งาน OTA บน ESP32
#include <WiFi.h>
#include <ESPmDNS.h>
#include <ArduinoOTA.h>
// ตั้งค่า WiFi
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
void setup() {
Serial.begin(115200);
Serial.println("Booting");
// เชื่อมต่อ WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// ตั้งค่า OTA Port (Default: 3232)
ArduinoOTA.setPort(3232);
// ตั้งค่าชื่อ Hostname (จะแสดงใน Arduino IDE)
ArduinoOTA.setHostname("ESP32-OTA-Device");
// ตั้งค่ารหัสผ่าน (Optional)
ArduinoOTA.setPassword("admin123");
// ตั้งค่า callback functions
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
}
void loop() {
ArduinoOTA.handle(); // ต้องเรียกใน loop เสมอ
}Step 2: ตรวจสอบ IP Address
เปิด Serial Monitor (115200 baud) และจด IP address ของ ESP32:
Ready
IP address: 192.168.1.100📡 ตัวอย่างที่ 2: อัปเดตผ่าน Arduino IDE
Step 1: เลือก Port ผ่าน WiFi
หลังจากอัปโหลดโค้ด Basic OTA แล้ว ให้:
- เปิด Arduino IDE
- ไปที่ Tools → Port
- คุณจะเห็น IP address ของ ESP32 ปรากฏขึ้น เช่น:
esp32-ota-device at 192.168.1.100 - คลิกเลือก Port นั้น
Step 2: แก้ไขโค้ด
ตอนนี้ลองแก้โค้ดใน loop() ให้ทำอย่างอื่น:
void loop() {
ArduinoOTA.handle(); // ต้องเรียกใน loop เสมอ
// ลองเพิ่มโค้ดนี้
static unsigned long lastPrint = 0;
if (millis() - lastPrint > 5000) {
Serial.println("OTA is working! Device running...");
lastPrint = millis();
}
}Step 3: อัปเดตผ่าน WiFi
- คลิก Upload ใน Arduino IDE (หรือกด Ctrl+U)
- Arduino IDE จะค้นหา ESP32 ผ่าน WiFi แทน USB
- ดู Process ที่ Serial Monitor หรือ Arduino IDE
- เมื่อเสร็จสิ้น ESP32 จะรีสตาร์ทใหม่พร้อมโค้ดใหม่
✅ สำเร็จ! ตอนนี้คุณสามารถอัปเดต ESP32 ได้โดยไม่ต้องเสียบสาย USB แล้ว! ทุกครั้งที่อัปโหลดโค้ดใหม่ ระบบจะ OTA อัปเดตให้อัตโนมัติ
🌐 ตัวอย่างที่ 3: OTA ผ่าน Web Server (Browser)
💡 ข้อดี: อัปเดตได้โดยไม่ต้องใช้ Arduino IDE เหมาะสำหรับให้ลูกค้าอัปเดตเองผ่านหน้าเว็บ
โค้ด Web Server OTA
#include <WiFi.h>
#include <WebServer.h>
#include <ESP32httpUpdate.h>
WebServer server(80);
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// หน้าเว็บสำหรับอัปเดต
const char* serverIndex =
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
"<input type='file' name='update'>"
"<input type='submit' value='Update'>"
"</form>"
"<div id='prg'>progress: 0%</div>"
"<script>"
"$('form').submit(function(e){"
"e.preventDefault();"
"var form = $('#upload_form')[0];"
"var data = new FormData(form);"
"$.ajax({"
"url: '/update',"
"type: 'POST',"
"data: data,"
"contentType: false,"
"processData:false,"
"xhr: function() {"
"var xhr = new window.XMLHttpRequest();"
"xhr.upload.addEventListener('progress', function(evt) {"
"if (evt.lengthComputable) {"
"var per = evt.loaded / evt.total;"
"$('#prg').html('progress: ' + Math.round(per*100) + '%');"
"}"
"}, false);"
"return xhr;"
"},"
"success:function(d, s) {"
"console.log('success!'); "
"},"
"error: function (a, b, c) {"
"}"
"});"
"});"
"</script>";
void setup(void) {
Serial.begin(115200);
// เชื่อมต่อ WiFi
WiFi.begin(ssid, password);
Serial.println("");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// รับส่งไฟล์ HTML
server.on("/", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
// Handler สำหรับอัปเดต
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) {
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
}
});
server.begin();
}
void loop(void) {
server.handleClient();
delay(2);
}วิธีใช้งาน
- อัปโหลดโค้ดนี้ครั้งแรกผ่าน USB
- เปิด Browser และไปที่
http://ESP32_IP_ADDRESS - คุณจะเห็นหน้าเว็บสำหรับอัปเดต
- คลิก Choose File และเลือกไฟล์ .bin จาก Arduino IDE
- ไฟล์ .bin จะอยู่ที่:
C:\Users\YOUR_USER\AppData\Local\Temp\arduino_build_xxxxxx.ino.bin - คลิก Update และรอสักครู่
- ESP32 จะรีสตาร์ทใหม่พร้อมฟาร์มแวร์ใหม่!
🔬 เทคนิคขั้นสูง (Advanced OTA Tips)
1. การตรวจสอบเวอร์ชันฟาร์มแวร์
เพิ่มระบบตรวจสอบเวอร์ชันเพื่อป้องกันการอัปเดตซ้ำ:
#define FIRMWARE_VERSION "1.0.2"
void setup() {
Serial.begin(115200);
Serial.println("Firmware Version: " + String(FIRMWARE_VERSION));
// OTA setup code...
}2. การ Rollback กลับเวอร์ชันเก่า
หากอัปเดตใหม่แล้วมีปัญหา สามารถ rollback ได้:
// ใน setup() หลังจาก OTA begin
if (!Update.isFinished()) {
// ถ้า OTA ไม่สำเร็จ ให้ rollback
Update.abort();
Serial.println("OTA failed! Rolling back...");
ESP.restart();
}
// หรือสั่ง rollback เอง
// Update.rollback();3. การจัดการ Partition Table
ใช้ Tools → Partition Scheme ใน Arduino IDE:
Default (4MB with spiffs): OTA 1.2MBMinimal SPIFFS (1.9MB APP with OTA): OTA 1.2MBHuge APP (3MB No OTA/SMIFFS): ไม่รองรับ OTA
4. การทำ HTTPS OTA (ปลอดภัยกว่า)
ใช้ ESP32httpUpdate กับ HTTPS:
WiFiClientSecure client;
// ข้ามการตรวจสอบ certificate (สำหรับทดสอบ)
client.setInsecure();
t_httpUpdate_return ret = httpUpdate.update(client, "https://example.com/firmware.bin");
switch(ret) {
case HTTP_UPDATE_FAILED:
Serial.println("Update failed: " + httpUpdate.getLastErrorString());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("No updates available");
break;
case HTTP_UPDATE_OK:
Serial.println("Update OK!");
break;
}🛠️ ปัญหาที่พบบ่อยและวิธีแก้ไข
❌ ปัญหา: OTA Port ไม่ปรากฏ
สาเหตุ: อาจเป็นเพราะ Firewall บล็อก หรือ ESP32 ไม่อยู่ในเครือข่ายเดียวกัน
วิธีแก้: ปิด Firewall/พิจารณาเพิ่ม Port 3232 ใน allowlist หรือใช้ static IP
❌ ปัญหา: Update Failed / Auth Failed
สาเหตุ: ใส่รหัสผ่านผิด หรือ sketch ขนาดใหญ่เกินไป
วิธีแก้: ตรวจสอบรหัสผ่าน และ Partition Scheme
❌ ปัญหา: WiFi Disconnect ระหว่างอัปเดต
สาเหตุ: สัญญาณ WiFi ไม่ดี หรือ interference จากอุปกรณ์อื่น
วิธีแก้: ย้ายใกล้ Access Point/ใช้ WiFi คุณภาพสูง หรือเพิ่ม retry logic
⚠️ ปัญหา: ESP32 ค้าง หลังอัปเดต
สาเหตุ: ฟาร์มแวร์ใหม่มี bug หรือใช้ RAM จนเต็ม
วิธีแก้: รอ 30 วินาทีให้ watchdog reset หรือถอดใส่ไฟใหม่
❌ ปัญหา: OTA เริ่มไม่ได้หลัง Power Cycle
สาเหตุ: ลืมเรียก ArduinoOTA.handle() ใน loop()
วิธีแก้: ตรวจสอบให้แน่ใจว่ามี ArduinoOTA.handle(); ใน loop()
✅ สรุป
ในบทความนี้คุณได้เรียนรู้:
- ✅ หลักการทำงานของ OTA (Over-The-Air Updates)
- ✅ วิธีอัปเดต ESP32 ผ่าน Arduino IDE โดยไม่ใช้ USB
- ✅ วิธีสร้าง Web Server สำหรับอัปเดตผ่าน Browser
- ✅ เทคนิคขั้นสูง: version checking, rollback, HTTPS OTA
- ✅ การแก้ปัญหาที่พบบ่อย
🚀 ถัดไป
ลองนำไปประยุกต์ใช้กับ โปรเจกต์ IoT จริง หรือดู วิธีประหยัดแบตเตอรี่ด้วย Deep Sleep