ตัวอย่างโปรแกรมที่มีมาตอนติดตั้งบอร์ด ESP32 ในโปรแกรม Arduino IDE / PlatformIO ส่วนใหญ่เป็นแบบต่อ WiFi ครั้งเดียวใน void setup() แล้วไปทำโปรแกรมหลักเลย การวางลำดับโค้ดโปรแกรมดังกล่าวเหมาะสำหรับใช้ทดสอบเท่านั้น เนื่องจากการใช้งานจริง WiFi มักจะหลุดอยู่เสมออยู่แล้ว โดยอาจเกิดจากการตั้งค่า Reset เร้าเตอร์ ระบบเน็ตเวิค ตามช่วงเวลา หรือเกิดจากไฟดับ หรือตัวกระจาย WiFi (AP) ค้าง เป็นต้น หากไม่มีการเขียนโปรแกรมจัดการให้เชื่อมต่อ WiFi ใหม่อัตโนมัติ จะทำให้อุปกรณ์ไม่สามารถทำงานได้ตามปกติหากใช้งานนาน ๆ
การใช้ไลบารี่ WiFiMulti
WiFiMuti เป็นไลบารี่ที่มีมาตอนติดตั้งบอร์ด ESP32 เพิ่มอยู่แล้ว โดยหน้าที่หลักของไลบารี่นี้คือสแกนหาชื่อ WiFi ที่อยู่ในลิส และเชื่อมต่อให้หาก WiFi ที่อยู่ในลิสพร้อมใช้เชื่อมต่อ การใช้งานไลบารี่ WiFiMuti มีขั้นตอนดังนี้
1) ใช้คำสั่ง include นำเข้าคำสั่งจากไลบารี่ WiFiMulti
2) สร้างออปเจค wifiMulti จากคลาส WiFiMulti
WiFiMulti wifiMulti;
3) ใน void setup() เพิ่มคำสั่ง wifiMulti.addAP() โดยกำหนดชื่อ WiFi (SSID) และรหัสผ่าน WiFi ลงไป เพื่อเพิ่ม WiFi ที่สามารถเชื่อมต่อได้ลงในลิส ตัวอย่างเพิ่ม WiFi ชื่อ GLABWiFi และรหัสผ่าน 123456789
void setup() {
....
wifiMulti.addAP("GLABWiFi", "123456789");
....
}
4) ใน void loop() ใส่ wifiMulti.run() โดยคำสั่งนี้เบื้องหลังจะสแกนหา WiFi ทั้งหมดก่อน แล้วมาเทียบกับในลิส ว่ามี WiFi ใดสามารถเชื่อมต่อได้บ้าง และหากเชื่อมต่อได้จะคืนค่าเป็น WL_CONNECTED โดยใช้คำสั่ง if มาเทียบแล้วให้ดำเนินการต่อได้
void loop() {
if(wifiMulti.run() == WL_CONNECTED) {
// โค้ดโปรแกรมที่ต้องการให้ทำงานหากเชื่อมต่อ WiFi สำเร็จ
...
}
}
ได้โค้ดเต็ม ๆ ที่ใช้ทดสอบได้ ดังนี้
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
WiFiMulti wifiMulti;
void setup() {
Serial.begin(115200);
wifiMulti.addAP("GLABWiFi", "123456789");
}
void loop() {
if(wifiMulti.run() == WL_CONNECTED) {
// โค้ดโปรแกรมที่ต้องการให้ทำงานหากเชื่อมต่อ WiFi สำเร็จ
Serial.println("WiFI connected");
delay(5 * 1000);
} else {
delay(2000);
Serial.println("WiFi connecting...");
}
}
อัพโหลดโปรแกรมลงบอร์ด แล้วเปิด Serial Monitor ขึ้นมา ใช้โทรศัพท์มือถือเปิดฮอสปอตแล้วให้ ESP32 มาเชื่อมต่อ ทดสอบเปิดสลับปิดหลาย ๆ ครั้ง พบว่าสามารถกลับมาเชื่อมต่อ WiFi ได้ทุกครั้ง
หากมีตัวกระจาย WiFi หลายตัว และต้องการให้เชื่อมต่อตัวอื่นอัตโนมัติหากตัวหลักดับไป สามารถใช้คำสั่ง wifiMulti.addAP() เพิ่มตัวกระจาย WiFi ตัวอื่นในลิสได้
ข้อควรระวังการใช้ WiFiMulti
เนื่องจาก WiFiMulti คำสั่ง wifiMulti.run() เมื่อนำไปใส่ใน void loop() จะทำให้โปรแกรมภายใน void loop() ค้างไป เนื่องจากจะต้องรอสแกนหา WiFi แล้วเชื่อมต่อ WiFi ก่อน คำสั่ง wifiMulti.run() จึงจะจบการทำงาน ซึ่งหากภายใน void loop() มีคำสั่งที่ต้องอาศัยเวลาในการทำงาน เช่น จะต้องอ่านค่าจากเซ็นเซอร์ทุก ๆ 10 วินาที โดยเวลาจะคลาดเคลื่อนไม่ได้ ก็จะเป็นปัญหามาก เพราะติดคำสั่ง wifiMulti.run() อยู่ ทำให้ไม่สามารถไปคำสั่งอื่น ๆ ที่ต้องอ่านค่าจากเซ็นเซอร์ ส่งผลให้ 10 วินาที ไม่สามารถเป็นไปได้ (หาก WiFi ไม่ได้เชื่อมต่ออยู่)
การเขียนโปรแกรมจัดการเอง
การเขียนโปรแกรมจัดการเองช่วยให้ยืดหยุ่นในการจัดการการเชื่อมต่อ WiFi ได้มากกว่า โดยการแยก Task ของตัวจัดการ WiFi ออกมา จะทำให้ไม่มีปัญหาเรื่องโปรแกรมค้างภายใน void loop() ทำให้คำสั่งที่ต้องทำงานตามเวลา ยังทำงานได้ถูกต้องอยู่
Task คือแนวคิดการเขียนโปรแกรมบน OS โดยแบ่งงานออกเป็นส่วน ๆ มีข้อดีประการสำคัญคือแต่ละ Task จะไม่ส่งผลกระทบต่อกัน เช่น Task A ใช้ delay() เพื่อหยุดการทำงานของโปรแกรมในบางช่วง จะไม่ส่งผลให้ Task B โปรแกรมหยุดไปด้วย
แนวคิดการเขียนโปรแกรมภายใน Task คือแบบหนึ่งคือการใช้ State โดย State คือแนวคิดการมองงานเป็นขั้นตอน แต่ละขั้นตอนมีชื่อ State และมีเหตุการณ์ (Action) ที่ทำให้เกิดการเปลี่ยน State
สำหรับบทความนี้จะแบ่งงานจัดการเชื่อมต่อ WiFi เป็น 4 State คือ
สั่งเริ่มชื่อมต่อ WiFi - ใช้คำสั่ง WiFi.begin() สั่งเริ่มเชื่อมต่อ WiFi แล้วไป state: 2
รอเชื่อมต่อ WiFi - ใช้คำสั่ง WiFi.isConnected() ตรวจสอบว่ากำลังเชื่อมต่ออยู่หรือไม่ หากเชื่อมต่อแล้วไป state: 3
รอ WiFi หลุด - ใช้คำสั่ง WiFi.isConnected() ตรวจสอบว่ายังเชื่อมต่ออยู่หรือไม่ หากไม่ได้เชื่อมต่อแล้วให้ไป state: 4
หยุดชั่วคราว - หน่วงเวลาก่อนเชื่อมต่อรอบใหม่ เมื่อหน่วงเวลาจบให้กลับไป state: 1
จากหลักการดังกล่าวสามารถเขียนโค้ดใน WiFiConnectManagerTask() ได้ดังนี้
#include <WiFi.h>
const char* ssid = "@lamloeiWLAN";
const char* password = "@lamloeiWLAN";
TaskHandle_t WiFiConnectManagerTaskHandle = NULL;
void WiFiConnectManagerTask(void*) {
int state = 1;
while(1) {
if (state == 1) {
if (!WiFi.isConnected()) {
Serial.print("WiFi Connecting to ");
Serial.print(ssid);
WiFi.begin(ssid, password);
state = 2;
} else {
state = 3;
}
} else if (state == 2) {
if (WiFi.isConnected()) {
Serial.println(" connected.");
state = 3;
} else {
Serial.print(".");
}
} else if (state == 3) {
if (!WiFi.isConnected()) {
Serial.println("WiFi lost connect");
state = 4;
}
} else if (state == 4) {
delay(2000);
state = 1;
}
delay(100);
}
vTaskDelete(NULL);
}
void setup() {
Serial.begin(115200);
xTaskCreate(
WiFiConnectManagerTask,
"WiFiConnectManagerTask",
5 * 1024,
NULL,
20,
&WiFiConnectManagerTaskHandle
);
}
void loop() {
if (WiFi.isConnected()) {
// โค้ดโปรแกรมที่ต้องการให้ทำงานหากเชื่อมต่อ WiFi สำเร็จ
}
delay(10);
}
อัพโหลดโปรแกรมลงบอร์ด ได้ผลดังนี้
หลังจากเชื่อมต่อ WiFi ได้ครั้งแรก แล้วลองปิด Access Point แล้วเปิดใหม่ ผลที่ได้คือ WiFi เชื่อมต่อใหม่ได้อัตโนมัติ
สรุป
การจัดการให้ WiFi เชื่อมต่อใหม่ได้อัตโนมัติทำได้ 2 แบบ คือใช้ไลบารี่ WiFiMulti และสร้าง Task ขึ้นมาจัดการการเชื่อมต่อเอง
Comments