[TH] ESP8266WiFi

บทความนี้เป็นการเรียบเรียงข้อมูลที่เกี่ยวของกับคลาส ESP8266WiFi ซึ่งทำหน้าที่ด้านระบบ WiFi ของไมโครคอนโทรลเลอร์ ESP8266 โดยคลาสดังกล่าวนี้สามารถเข้าถึงผ่านทางวัตถุชื่อ WiFi ที่เป็นวัตถุที่ถถูกสร้างขึ้นสำหรับเข้าถึงโมดูลไร้สายของชิพ และต้องนำเข้าไฟล์ส่วนหัวชื่อ ESP8266WiFi.h

ไมโครคอนโทรลเลอร์ ESP8266 รองรับการทำงานของระบบสื่อสารไร้สาย IEEE802.11 b/g/n และมีรายการใช้กระแสดังนี้

  • 0.9mA เมื่ออยู่ในโหมด Standby
  • 135-215mA เมื่อส่งข้อมูล
  • 60mA เมื่อรับข้อมูล
  • 1mA เมื่ออยู่ในโหมดประหยัดพลังงาน
  • 0.5uA เมื่อปิดการใช้งาน WiFi

โครงสร้างของคลาส WiFi

คลาสย่อยที่อยู่ภายใต้คลาส ESP8266WiFi มีรายการดังนี้

  • BufferDataSource
  • BufferedStreamDataSource
  • ClientContext
  • DataSource
  • ESP8266WiFiAPClass
  • ESP8266WiFiClass
  • ESP8266WiFiGenericClass
  • ESP8266WiFiMulti
  • ESP8266WiFiScanClass
  • ESP8266WiFiSTAClass
  • ProgmemStream
  • SList
  • SSLContext
  • UdpContext
  • WiFiAPlist_t
  • WiFiClient
  • WiFiClientSecure
  • WiFiEventHandlerOpaque
  • WiFiEventModeChange
  • WiFiEventSoftAPModeProbeRequestReceived
  • WiFiEventSoftAPStationConnected
  • WiFiEventSoftAPStationDisconnected
  • WiFiEventStationModeAuthModeChanged
  • WiFiEventStationModeConnected
  • WiFiEventStationModeDisconnected
  • WiFiEventStationModeGetIP
  • WiFiServer
  • WiFiUDP

เริ่มต้นใช้งาน

การอ่านรหัสแม็คแอดเดรส (MAC address) ซึ่งเป็นค่าที่อุปกรณ์แต่ละชิ้นแตกต่างกัน (ยกเว้นทำการปลอมรหัส) เพื่อใช้เป็นตัวเลขอ้างอิงแทนชื่อของอุปกรณ์ โดยมีโครงสร้างเป็นเลขฐานสิบหกจำนวน 6 ชุด ดังรูปแบบต่อไปนี้

xx:xx:xx:xx:xx:xx

การเขียนโปรแกรมเพื่ออ่านค่าแม็คแอดเดรสของชิพ esp8266 ใช้คำสั่ง macAddress() ตามรูปแบบการใช้งานดังนี้

ค่าแม็คแอดเดรส = WiFi.macAddress()

ตัวอย่างโปรแกรมสำหรับแสดงค่าแม็คแอดเดรสเป็นดังนี้

#include <ESP8266WiFi.h>

void setup() {
  Serial.begin(115200);
  Serial.print("\n\nMAC Address:  ");
  Serial.println(WiFi.macAddress());
}

void loop() {

}

กรณีต้องการอ่านค่า MAC Address เป็นแถวลำดับของตัวอักษรให้สร้างตัวแปร uint8_t จำนวน 6 ตัวและเรียกใช้งานคำสั่งตามรูปแบบต่อไปนี้

uint8_t ตัวแปร[6];

WiFi.macAddress( ตัวแปร );

ถ้าต้องการตั้งค่าของ MAC Address ให้กับอุปกรณ์สามารถทำได้โดย

เมื่อต้องนำไมโครคอนโทรลเลอร์ esp8266 เชื่อมต่อเข้าระบบเครือข่ายไร้สายจะต้องอาศัยอุปกรณ์เชื่อมต่อที่เกี่ยวข้อง ได้แก่ AP (Access Point) และเครื่องลูกในเครือข่ายเดียวกันหรือจากในเครือข่ายอินเทอร์เน็ตดังภาพที่ 1 ซึ่งตัวชิพเองนั้นรองรับการทำงานทั้งในรูปแบบให้ตัวเองเป็นลูกข่ายภายในเครือข่ายไร้สาย และทำตัวเองเหมือนเป็น AP เพื่อให้บริการแก่ลูกข่ายอื่น ๆ

การทำงานในโหมด Station

ภาพที่ 1 โหมดทำงานแบบ STA ของ ESP8266
ที่มา : https://arduino-esp8266.readthedocs.io/en/latest/_images/esp8266-station.png

คลาส Station

จากภาพที่ 1 การเริ่มต้นทำงานโหมด Station หรือ STA เป็นเชื่อมต่อกับเครือข่ายไร้สายที่มี AP ซึ่งถูกระบุด้วยชื่อของ AP ที่เรียกว่า SSID (Service Set IDentifier) และรหัสการเข้าใช้งาน โดยใช้คำสั่ง begin( ) ตามรูปแบบต่อไปนี้ โดย AP_NAME คือ ชื่อของ AP ที่ต้องการเชื่อมต่อ และ AP_PASSWD คือ รหัสผ่านสำหรับเข้าใช้ AP

WiFi.begin( AP_NAME, AP_PASSWD )

นอกจากนี้ ในบางกรณีผู้เขียนโปรแกรมต้องการเชื่อมต่อโดยระบุช่องสื่อสาร (Channel) BBSID (ค่า MAC Address ของ SSID) และการสั่งให้เชื่อมต่อในทันทีหรือไม่ทำโดยใช้คำสั่ง begin เช่นเดียวกันแต่อาร์กิวเมนต์เหล่านี้ถูกตั้งค่าเบื้องต้นไว้ ดังนั้น คำสั่ง begin จึงมีรูปแบบการสั่งงานดังนี้

WiFi.begin( AP_NAME, AP_PASSWD, channel, bbsid, conect )

การกำหนดโหมดทำงานให้เป็น STA ใช้คำสั่ง mode() พร้อมทั้งส่งอาร์กิวเมนต์เป็น WIFI_STA ดังนี้

WiFi.mode( WIFI_STA )

ประเภทของโหมดการทำงานของ WiFi มีทั้งหมดดังนี้

  • WIFI_AP สำหรับกำหนดให้เป็น Access Point
  • WIFI_STA สำหรับกำหนดทำงานเป็นเครื่องลูกในเครือข่ายที่มี Access Point อยู่แล้ว
  • WIFI_AP_STA สำหรับทำงานทั้งโหมด AP และ STA
  • WIFI_OFF สำหรับปิดการทำงานระบบ WiFi ของไมโครคอนโทรลเลอร์

การตรวจสอบสถานะของการร้องขอเพื่อเข้าใช้เครื่องข่ายไร้สายของ AP ต้องใช้คำสั่ง status() ซึ่งคำสั่งนี้จะคืนค่าเป็น WL_CONNECTED เมื่อการเชื่อมต่อสำเร็จ โดยคำสั่งมีรูปแบบการใช้งานดังนี้

ผลลัพธ์ของการเชื่อมต่อ = WiFi.status()

ผลลัพธ์ของสถานะได้แก่

  • 0 หรือ WL_IDLE_STATUS ถ้ามีเหตุการเปลี่ยนการทำงานของ WiFi ขณะมีการอ่านสถานะ
  • 1 หรือ WL_NO_SSID_AVAIL ถ้าไม่พบชื่อของ AP ที่กำหนด
  • 3 หรือ WL_CONNECTED ถ้าเชื่อมต่อสำเร็จ
  • 4 หรือ WL_CONNECT_FAILED ถ้าไม่สามารถเชื่อมต่อได้สำหรับ
  • 6 หรือ WL_CONNECT_WRONG_PASSWORD ถ้ากำหนดรหัสผ่านผิด
  • 7 หรือ WL_DISCONNECTED ถ้าโมดูลไม่ได้ตั้งค่าโหมดทำงานอยู่ในโหมด STA

การบริหารจัดการการเชื่อมต่อ

คำสั่งสำหรับบริหารจัดการการเชื่อมต่อได้แก่คำสั่งการยกเลิกการเชื่อมต่อ คำสั่งให้เชื่อมต่ออีกครั้ง คำสั่งตรวจสอบสถานะการเชื่อมต่อ คำสั่งตั้งค่าให้เชื่อมต่ออัตโนมัติ คำสั่งอ่านสถานะของการเชื่อมต่ออัตโนมัติ คำสั่งตั้งค่าการเชื่อมต่ออีกครั้งแบบอัตโนมัติ และคำสั่งรอผลการเชื่อมต่อ ดังรายละเอียดของแต่ละคำสั่งใช้งานต่อไปนี้

การออกจากการเชื่อมต่อกระทำได้ด้วยการใช้คำสั่งต่อไปนี้ ซึ่งทำหน้าที่ตั้งค่าให้กับค่า AP_NAME และ AP_PASSWD มีค่าเป็น null

WiFi.disconnect()

การสั่งให้ทำการเชื่อมต่ออีกครั้งเพื่อซึ่งเป็นการเชื่อมต่อโดยใช้การตั้งค่าเดิมจากที่เคยได้รับมาจากการ begin() ก่อนหน้านี้ มีรูปแบบคำสั่งการใช้งานดังนี้ และหลังจากสั่ง reconect() ให้วนรอบรอการเชื่อมต่อด้วย status() เหมือนกับการใช้คำสั่ง begin()

WiFi.reconect()

วิธีการตรวจสอบสถานะของการเชื่อมต่อใช้คำสั่ง isConnected() ซึ่งจะคืนค่ากลับเป็น true ถ้าไมโครคอนโทรลเลอร์ยังเชื่อมต่อกับระบบเครือข่าย และคืนค่า false ถ้าไม่ได้เชื่อมต่อกับเครือข่าย ดังรูปแบบการใช้งานต่อไปนี้

สถานะของการเชื่อมต่อ = WiFi.isConnected()

กรณีที่ต้องการให้อุปกรณ์ทำการเชื่อมต่ออัตโนมัติเข้ากับ AP ตัวหลังสุดที่เข้าใช้งานต้องใช้คำสั่ง setAutoConnect พร้อมด้วยอาร์กิวเมนต์การตั้งค่าให้เป็น true หรือ false เพื่อเปิดหรือปิดการทำงานเชื่อมต่ออัติโนมัติดังนี้

WiFi.setAutoConnect( ค่ากำหนดการทำงานของการเชื่อมต่ออัตโนมัติ )

การตรวจสอบว่าได้กำหนดตั้งค่าให้อุปกรณ์ทำการเชื่อมต่ออัตโนมัติเอาไว้หรือไม่สามารถใช้คำสั่ง getAutoConnect() เป็นคำสั่งสำหรับอ่านค่าสถานะนั้นกลับมาดังนี้ ซึ่งถ้าเป็น true หมายถึง ได้เปิดให้การเชื่อมต่ออัตโนมัติทำงาน และ false หมายถึงปิดการเชื่อมตออัตโนมัติไว้

สถานะ = WiFi.getAutoConnect()

กรณีที่ได้ยกเลิกการเชื่อมต่อด้วย disconnect() และต้องการเชื่อมต่อใหม่อีกครั้งให้ใช้คำสั่ง reconnect() อีกครั้ง แต่ถ้าผู้เขียนโปรแกรมต้องการให้ไมโครคอนโทรลเลอร์ esp8266 ทำการเชื่อมต่ออีกครั้งโดยอัติโนมัติจะต้องเรียกใช้การตั้งค่าการทำงานนี้ผ่านทาง setAutoReconnect() ด้วยอาร์กิวเมนต์ true และยกเลิกการทำงานอัตโนมัติด้วยการส่งอาร์กิวเมนต์ false ตามรูปแบบของคำสั่งดังนี้

WiFi.setAutoReconnect( การเปิดหรือปิดการทำงานอัตโนมัติ )

คำสั่งสำหรับให้รอจนกว่า esp8266 จะถูกเชื่อมต่อกับ AP และคืนค่าสถานะดังนี้ คือคำสั่ง waitForConnectResult()

  • 0 หรือ WL_IDLE_STATUS กำลังจะดำเนินการเชื่อมต่อ
  • 1 หรือ WL_NO_SSID_AVAIL ถ้าไม่พบชื่อของ AP ที่กำหนด
  • 3 หรือ WL_CONNECTED ถ้าเชื่อมต่อสำเร็จ
  • 4 หรือ WL_CONNECT_FAILED ถ้าไม่สามารถเชื่อมต่อได้สำหรับ
  • 6 หรือ WL_CONNECT_WRONG_PASSWORD ถ้ากำหนดรหัสผ่านผิด
  • 7 หรือ WL_DISCONNECTED ถ้าโมดูลไม่ได้ตั้งค่าโหมดทำงานอยู่ในโหมด STA
  • -1 เกิดการ Timeout

รูปแบบของคำสั่งคือ

สถานะ = WiFi.waitForConnectResult()

ข้อมูลของการเชื่อมต่อเครือข่าย

กรณีที่เข้าใช้เครือข่ายไร้สายได้สำเร็จ ตัวเครื่องให้บริการจะให้หมายเลขไอพี (IP Address) แก่อุปกรณ์เพื่อใช้แทนค่าที่อยู่ของอุปกรณ์บนระบบเครือข่ายไร้สาย ซึ่งคำสั่งสำหรับอ่านค่าหมายเลขไอพีคือ

ค่าหมายเลขไอพี = WiFi.localIP()

นอกจากการใช้ IP Address เป็นตัวอ้างอิงในเครือข่ายแล้ว ผู้เขียนโปรแกรมสามารถตั้งชื่อของอุปกรณ์หรือเรียกว่า hostname (ปกติสามารถเข้าถึงด้วยชื่อแทน IP Address ได้ด้วยการตั้งค่าชื่อไว้ใน DNS) ด้วยคำสั่ง hostname() โดยรูปแบบของการใช้งานมี 2 ลักษณะคือ อ่านชื่อที่ตั้งไว้ และกำหนดชื่อให้กับอุปกรณ์ดังรูปแบบต่อไปนี้ ซึ่งปกติชื่อของ hostname จะถูกกำหนดเป็น “ESP-” ตามด้วย 3 ตัวหลังของ MAC Address เช่น “ESP-123121” นั่นหมายความว่า 12:31:21 เป็นเลข 3 ชุดสุดท้ายของ MAC Address

ชื่อที่ตั้งไว้ = WiFi.hostname()

WiFi.hostname( ชื่อของอุปกรณ์ )

ส่วนค่า sub netmask และ gateway สามารถอ่านค่าได้ด้วยคำสั่งต่อไปนี้

ค่าสับเน็ตแมสค์ = WiFi.subnetMask()

ค่าเกตเวย์ = WiFi.gatewayIP();

การแสดงรายการข้อมูลจาก WiFi เพื่อแสดงค่า เหล่านี้ทางพอร์ตสื่อสารอนุกรม

  • Mode
  • PHY mode
  • Channel
  • AP id
  • Status
  • Auto connect
  • SSID
  • Passphase
  • BSSID set

มีรูปแบบการใช้งานดังนี้

WiFi.printDiag( Serial )

ดังนั้น ตัวอย่างโปรแกรมสำหรับขอเข้าใช้บริการเครือข่ายไร้สาย และแสดงรหัสหมายเลขไอพีที่ได้แจกจ่ายกลับมาจึงเขียนได้ดังนี้

#include <ESP8266WiFi.h>

#define AP_NAME "ชื่อ AP"
#define AP_PASSWD "รหัสผ่าน"

void setup() {
  Serial.begin(115200);
  Serial.println("\n\n");
  WiFi.begin( AP_NAME, AP_PASSWD );
  int countLimit = 200;
  while (WiFi.status() != WL_CONNECTED) {
    delay(250);
    if (countLimit == 0) {
      break;
    }
    countLimit--;
  }
  if (countLimit > 0) {
    Serial.println(WiFi.localIP());
    WiFi.printDiag(Serial);
  }
  WiFi.disconnect();
}

void loop() {
}

คำสั่งสำหรับอ่านค่า DNS1 และ 2 โดยระบุหมายเลขของ DNS เป็น 0 หรือ 1 มีรูปแบบของคำสั่งดังนี้

ค่าคืนกลับ = WiFi.dnsIP( หมายเลขของDNS )

การอ่านชื่อ SSID และรหัสผ่าน (PSK: Pre-shared Key) สามารถเข้าถึงด้วยคำสั่งต่อไปนี้

ชื่อAP = WiFi.SSID()

รหัสผ่านAP = WiFi.psk()

ถ้าต้องการอ่านค่า MAC Address ของ SSID หรือที่เรียกว่า BSSID (Basic Service Set Identifier) จะได้ค่า Pointer ที่ชี้ไปยังตำแหน่ง แต่ ESP8266 มีคำสั่งแปลงเป็นสสตริงให้ใช้งานด้วยเช่นกัน ดังนี้

ค่าตำแหน่งของBSSID = WiFi.BSSID()

ค่าMACAddress = WiFi.BSSIDstr()

การอ่านค่า RSSI (Received Signal Strength Indication) ซึ่งเป็นค่าความเข้มของสัญญาณไร้สายมีหน่วยเป็น dBm สามารถใช้งานดังนี้

ค่าความเข้มของสัญญาณ = WiFi.RSSI()

ในบางเครือข่ายไร้สายได้กำหนดให้ข้อมูลมีการเข้ารหัส การเขียนอ่านประเภทของการเข้ารหัสกระทำได้ด้วยคำสั่งต่อไปนี้ ซึ่งโดยปกติจะคืนค่าเป็น ENC_TYPE_NONE

วิธีการเข้ารหัส = WiFi.encryptionType()

ค่าประเภทของการเข้ารหัสมีดังนี้

  • 2 หรือ ENC_TYPE_TKIP หรือ WPA/SPK
  • 4 หรือ ENC_TYPE_CCMP หรือ WPA2/PSK
  • 5 หรือ ENC_TYPE_WEP หรือ WEP
  • 7 หรือ ENC_TYPE_NONE หรือ Open
  • 8 หรือ ENC_TYPE_AUTO หรือ WPA/WPA2/PSK

การคอนฟิก

ในบางกรณีที่ AP ปิดการให้บริการ DHCP ที่ทำหน้ที่แจกจ่ายค่า IPAddress, DNS1, DNS2, subnetmask และ gateway IP Adress ผู้เขียนโปรแกรมสามารถสั่งตั้งค่าเหล่านี้เองด้วยคำสั่ง config ตามรูปแบบการใช้งานดังนี้

WiFi.config( IPAddress, gatewayIP, subnetmask, DNS1, DNS2 )

โดยให้เรียกใช้ config() ก่อนทำการ begin()

WPS

WPS หรือ WiFi Protected Setup เดิมเรียกว่า WiFi Simple Config ซึ่งเป็นโพรโทคอลที่ออกแบบเพื่อใช้กับเครือข่ายไร้สายภายในบ้านทำให้อุปกรณ์ทำงานโดยไม่ต้องป้อนรหัสผ่านที่ใช้กับ AP โดยในปัจจุบัน ESP8266 รองรับเฉพาะโหมด push-button (WPS_TYPE_PBC) โดยรูปแบบของคำสั่งการตั้งค่าเป็นดังนี้

ผลของการตั้งค่า = WiFi.beginWPSConfig()

ตัวอย่างของการใช้งานเป็นดังนี้

#include <ESP8266WiFi.h>

void setup() {
  Serial.begin(115200);
  Serial.println("\n\r---------------------\n\r");
  WiFi.mode(WIFI_STA);
  bool wpsStatus = WiFi.beginWPSConfig();
  if (wpsStatus) {
    Serial.println("WPS success.");
    while (WiFi.status() != WL_CONNECTED) {
      delay(330);
    }
    Serial.print("IP Address : ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("WPS failed!!!");
  }
}

void loop() {
}

จากตัวอย่างจะพบว่าเราใช้ beginWPSConfig() แทนการใช้ begin() เพื่อเชื่อมต่อกับ AP ที่รองรับ WPS และจะพบว่าสามารถเข้าถึงได้โดยไม่ต้องใส่รหัสผ่าน

การสแกน AP

การสแกน AP ต้องเริ่มด้วยการเปิดโหมดทำงาน WIFI_STA หลังจากนั้นสั่ง disconnect() เพื่อเริ่มต้นทำงาน ดังนี้

WiFi.mode( WIFI_STA );

WiFi.disconnect();

การนับจำนวน AP ที่สามารถสแกนได้ทำโดยเรียกใช้คำสั่ง scanNetworks() และได้ค่าคืนกลับเป็นจำนวน AP ดังนี้ ซึ่งมีการใช้งาน 2 รูปแบบ คือ เรียกใช้แบบการทำงานปกติ และเรียกโดยกำหนดค่า async และ hidden เป็น true หรือ false โดย async เป็นการกำหนดให้ทำการสแกนเป็นฉากหลังและตรวจสอบผลการทำงานด้วย scanComplete() และ hidden เป็นการกำหนดให้สแกนรายการ AP ที่ซ่อน

จำนวนAPที่พบ = WiFi.scanNetworks()

จำนวนAPที่พบ = WiFi.scanNetworks( async, hidden )

กรณีที่สแกนด้วย async เป็น true จะทำให้หน่วยประมวลผลไม่ต้องรอการสแกนจนเสร็จและทำคำสั่งถัดไป ด้วยเหตุนี้ผู้เขียนโปรแกรมจะต้องตรวจสอบสถานะการสแกนผ่านฟังก์ชัน scanComplete() ดังรูปแบบต่อไปนี้

ผลลัพธ์ = WiFi.scanComplete()

ผลลัพธ์ของการเรียกใช้คำสั่งมี 2 ลักษณะ คือ ถ้าคำตอบที่ได้มากหรือเท่ากับ 0 หมายถึงจำนวน AP ที่พบ และถ้าต่ำกว่า 0 หมายถึงเกิดความผิดพลาด โดย -1 หมายถึง กำลังสแกน และ -2 หมายถึง การสแกนไม่ถูกกระตุ้นให้ทำงาน (Scanning has not been triggered)

ข้อมูลของการสแกน AP จะถูกเก็บไว้ในหน่วยความจำ (เป็นเหตุให้หน่วยความจำกึ่งหนึ่งของ esp8266 หายไป เพราะกันไว้สำหรับการทำงานของ WiFi) ซึ่งสามารถลบออกด้วยคำสั่งต่อไปนี้

WiFi.scanDelete()

การสั่งให้ทำการสแกนแบบ Asynchronous โดยระบุฟังก์ชันตอบสนองเพื่อจะได้ไม่ต้องคอยตรวจสอบจาก scanComplete() สามารถทำเองได้ด้วย 2 ขั้นตอน คือ

  1. สร้างฟังก์ชันตอบสนอง ตามรูปแบบนี้
    void ชื่อฟังก์ชัน( int networksFound ) {
    // สิ่งที่ทำ
    }
  2. เรียกใช้คำสั่ง scanNetworksAsync() ตามรูปแบบต่อไปนี้ โดย hidden เป็น true หรือ false เพื่อกำหนดให้สแกน AP ที่ซ่อนไว้ด้วยหรือไม่
    WiFi.scanNetworksAsync( ชื่อฟังก์ชัน, hidden )

การตรวจสอบว่า AP นั้นซ่อนไว้หรือไม่สามารถตรวจสอบได้จาก isHidden() ตามรูปแบบการใช้งานต่อไปนี้

สถานะการซ่อน = WiFi.isHidden( ลำดับที่พบ )

การอ่านค่า SSID, BSSID, channel, RRSI, encryptionType ของ AP สามารถใช้คำสั่ง SSID(), channel(), RSSI(), BSSID()/BSSIDstr() และ encryptionType() โดยใส่ลำดับ AP เป็นอาร์กิวเมนต์หรือใช้คำสั่งต่อไปนี้มาเก็บในบัฟเฟอร์

WiFi.getNetworkInfo( ลำดับAP, &ssid, &encryptionType, &RSSI, *&BSSID, &channel, &isHidden)

การสแกนรายชื่อ AP ที่สามารถเข้าถึงได้เขียนเป็นตัวอย่างโปรแกรมได้ดังนี้

#include <ESP8266WiFi.h>

void showAPs( int networksFound ) {
  Serial.printf("Found %d AP(s)\n", networksFound);
  for (int i = 0; i < networksFound; i++)  {
    Serial.print("AP No.");
    Serial.print(i + 1);
    Serial.print(" : ");
    Serial.print(WiFi.SSID(i));
    if (WiFi.isHidden( i )) {
      Serial.print("*");
    }
    Serial.print(" Ch:");
    Serial.print(WiFi.channel(i));
    Serial.print(" S:");
    Serial.print(WiFi.RSSI(i));
    Serial.print("dBm ENC:");
    switch (WiFi.encryptionType(i)) {
      case ENC_TYPE_TKIP:
        Serial.print("WPA/PSK");
        break;
      case ENC_TYPE_CCMP:
        Serial.print("WPA2/PSK");
        break;
      case ENC_TYPE_WEP:
        Serial.print("WEP");
        break;
      case ENC_TYPE_NONE:
        Serial.print("Open");
        break;
      case ENC_TYPE_AUTO:
        Serial.print("WPA/WPA2/PSK");
        break;
      default:
        Serial.print("Unknown");
    }
    Serial.print(" BSSID:");
    Serial.println(WiFi.BSSIDstr(i));
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n\r\n\r");
  WiFi.mode( WIFI_STA );
  WiFi.disconnect();
  delay(100);
  WiFi.scanNetworksAsync( showAPs, true );
}

void loop() {
}

ESP8266WiFiMulti

ในกรณีที่ผู้พัฒนาโปรแกรมต้องการกำหนดให้ระบบมีการเชื่อมต่อกับ AP ตัวอื่นเมื่อ AP ตัวปัจจุบันที่กำหนดไว้ไม่สามารถเข้าถึงได้ ตัวคลาส ESP8266WiFiMulti จะรองรับประเด็นนี้ได้ โดยให้ผู้เขียนโปรแกรมเพิ่ม AP เข้าไปเป็นรายการ AP ที่ให้เข้าถึงเมื่อตัวอื่นเข้าถึงไม่ได้ โดยการใช้จะต้องนำเข้าไฟล์ส่วนหัวเพิ่มเติมดังนี้

#include <ESP8266WiFiMulti.h>

การสร้างวัตถุประเภท ESP8266WiFiMulti สั่งสร้างได้ดังนี้

ESP8266WiFiMulti ชื่อวัตถุ;

การเพิ่มรายการ AP เข้าไปในวัตถุจะต้องระบุ SSID และ PSK ของแต่ละรายการเป็นอาร์กิวเมนต์ของ addAP() ดังนี้

ชื่อวัตถุ.addAP( SSID, PSK )

การเชื่อมต่อจะต้องเปลี่ยนวิธีการจากที่ใช้ begin() ต้องเปลี่ยนเป็น run() ดังนี้

ผลการเชื่อมต่อ=ชื่อวัตถุ.run()

ตัวอย่างโปรแกรมเป็นดังนี้

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

ESP8266WiFiMulti  wifiMulti;

void doConnect() {
  if (wifiMulti.run() != WL_CONNECTED) {
    delay(500);
  } 
  else  {
    Serial.printf("SSID : %s\n", WiFi.SSID());

    Serial.print("Hostname :");
    Serial.println(WiFi.hostname());
    Serial.print("\nMAC Address:  ");
    Serial.println(WiFi.macAddress());
    Serial.print("IP Address :");
    Serial.println(WiFi.localIP());
    Serial.print("subnetmask :");
    Serial.println(WiFi.subnetMask());
    Serial.print("Gateway :");
    Serial.println(WiFi.gatewayIP());
    Serial.print("DNS:");
    Serial.print(WiFi.dnsIP(0));
    Serial.print(", ");
    Serial.println(WiFi.dnsIP(1));
    Serial.print("SSID :");
    Serial.print(WiFi.SSID());
    Serial.print(" PSK:");
    Serial.println(WiFi.psk());
    Serial.printf("BBSD: %s\n",WiFi.BSSIDstr().c_str());
    Serial.printf("RSSI: %s dBm\n", WiFi.RSSI());
    Serial.println();
    WiFi.printDiag(Serial);
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n\n");
  wifiMulti.addAP( "SSID1", "PASSWD1" );
  wifiMulti.addAP( "SSID2", "PASSWD2" );
  wifiMulti.addAP( "SSID3", "PASSWD3" );
  wifiMulti.addAP( "SSID4", "PASSWD4" );
  wifiMulti.addAP( "SSID5", "PASSWD5" );
}

void loop() {
  doConnect();
  delay(5000);
}

การทำงานในโหมด SoftAP

โหมดการทำงานแบบ SoftAP ดังภาพที่ 2 จะพบว่าตัว ESP8266 ทำตัวเองเป็น AP เพื่อให้บริการกับ Station อื่น ซึ่งการทำแบบนี้ไม่ได้เน้นการเข้าอินเทอร์เน็ตแต่เป็นการสร้างเครือข่ายภายในที่ทำงานผ่านโพรโทคอลอินเทอร์เน็ต หรือสร้างข่ายงานแบบเสช (Mesh networks) สำหรับสร้างข่ายของเซ็นเซอร์ (network sensors) และรองรับจำนวนลูกข่ายที่เชื่อมต่อได้ไม่เกิน 8 โหนด ซึ่งปกติตั้งค่าเริ่มต้นไว้ 4 โหนด

ภาพที่ 2 การทำงานในโหมด SoftAP
ที่มา : https://arduino-esp8266.readthedocs.io/en/latest/_images/esp8266-soft-access-point.png

การบริหารจัดการ softAP

การกำหนดชื่อ SSID ให้แก่ esp8266 ทำโดยใช้คำสั่ง softAP() ดังนี้ โดยคืนค่าการทำงานเป็น true หรือ false

ผลการทำงาน = WiFi.softAP( ชื่อ )

หรือสร้างโดยกำหนดรายละเอียดการทำงานเกี่ยวกับ SSID, PSK, channel, hidden และ max_connection เพื่อตั้งชื่อ (ไม่เกิน 32 ตัวอักษร) รหัสผ่าน (ไม่เกิน 64 ตัวอักษร และไม่ต่ำกว่า 8 ตัวอักษร) ช่องสัญญาณที่ใช้ (กำหนดได้เป็นตัวเลข 1 ถึง 13 โดยปกติใช้ค่าเป็น 1) สถานะการซ่อน (ถ้ากำหนดเป็น true จะซ่อนAP) และจำนวนโหนดที่เชื่อมต่อได้สูงสุด (เป็นค่าตัวเลข 0 ถึง 8) ด้วยคำสั่ง softAP() ที่กำหนดอาร์กิวเมนต์ดังนี้

ผลการทำงาน = WiFi.softAP( SSID, PSK, channel, hidden, max_connection )

เมื่อเริ่มทำงานเป็น AP สำเร็จ ตัว ESP8266 จะกำหนดหมายเลขไอพีให้กับตัวเองเป็นค่า 192.168.4.1 ซึ่งสามารถเปลี่ยนแปลงได้ด้วยคำสั่ง softAPConfig()

เมื่อทำงานเสร็จและต้องการยกเลิกตัวเองจากโหมด softAP ให้เรียกใช้คำสั่ง softAPdisconnect() ดังนี้

WiFi.softAPdisconnect()

การตรวจสอบจำนวนลูกข่ายหรือโหนดที่เชื่อมต่อกับไมโครคอนโทรลเลอร์ที่ตั้งเป็น softAP ใช้คำสั่งดังนี้

จำนวนลูกข่าย = WiFi.softAPgetStationNum()

สำหรับการอ่านค่า MAC Address ให้เรียกใช้ softAPmacAddress() และให้สร้างตัวแปรแถวลำดับแบบ uint8_t จำนวน 6 สมาชิกสำหรับเก็บค่าของแต่ละหลัก หรือเรียกใช้ฟังก์ชันเพื่อนำค่าคืนกลับไปใช้ ดังนี้

uint8_t myMACaddr[6];
WiFi.softAPmacAddress( myMACaddr );

ค่าแม็คแอดเดรส = WiFi.softAPmacAddress();

คลาส IPAddress

คลาส IPAddress เป็นคลาสสำหรับจัดการกับโครงสร้างข้อมูลสำหรับ IP Address ด้วยเหตุนี้ ถ้ามีการสร้างวัตถุหรือตัวแปรสำหรับค่าตำแหน่งไอพี หรือ IP Address ให้ใช้คลาสนี้เป็นตัวจัดการ

คำสั่งสำหรับกำหนดค่าตำแหน่งไอพีให้แก่ไมโครคอนโทรลเลอร์ในโหมด SoftAP กระทำด้วยคำสั่ง softAPConfig() ตามรูปแบบการใช้งานดังนี้ และคืนค่าผลการทำงานเป็น true และ false

IPAddress ค่าตำแหน่งไอพี(xx, xx, xx, xx );

IPAddress ค่าตำแหน่งไอพีของเกตเวย์( xx, xx, xx, xx );

IPAddress ค่าสับเน็ตมาสค์( xx, xx, xx, xx );

ผลการทำงาน = WiFi.softAPConfig( ค่าตำแหน่งไอพี, ค่าตำแหน่งไอพีของเกตเวย์, ต่าสับเน็ตมาสก์ );

การอ่านค่าตำแหน่งไอพีของ softAP ต้องใช้คำสั่ง softAPIP() ดังนี้

ค่าตำแหน่งไอพี = WiFi.softAPIP()

ตัวอย่างโปรแกรมการสร้าง softAP ที่กำหนดค่า IP Address เป็น 192.168.4.54 กำหนดเกตเวย์เป็น 192.168.4.11 และทำงานในคลาส C พร้อมทั้งตั้งชื่อ AP เป็น “JarutEx” รหัสผ่าน ‘123456789″ ใช้ช่องสัญญาณลำดับที่ 8 ให้ซ่อนตัวเอง และยินยอมให้โหนดลูกเข้าใช้ได้ 3 โหนด เป็นดังนี้

#include <ESP8266WiFi.h>

IPAddress myIP(192, 168, 4, 54);
IPAddress gwIP(192, 168, 4, 11);
IPAddress subnet(255, 255, 255, 0);
uint8_t myMACaddr[6] = {99, 99, 99, 99, 99, 99};

void setup() {
  Serial.begin(115200);
  Serial.println("\n\r\n\r");
  WiFi.softAPmacAddress( myMACaddr );
  Serial.print("MAC Address : ");
  Serial.println(WiFi.softAPmacAddress());
  Serial.printf("%d:%d:%d:%d\n\n",
                myMACaddr[0],
                myMACaddr[1],
                myMACaddr[2],
                myMACaddr[3],
                myMACaddr[4],
                myMACaddr[5]);
  if (WiFi.softAPConfig( myIP, gwIP, subnet )) {
    if (WiFi.softAP("JarutEx", "123456789", 8, true, 3)) {
      Serial.print("IP Address : ");
      Serial.println(WiFi.softAPIP());
      Serial.print(WiFi.softAPgetStationNum());
      Serial.println(" connected.");
      WiFi.softAPdisconnect();
    } else {
      Serial.println("softAP() failed!!");
    }
  } else {
    Serial.println("softAPConfig() failed!");
  }
}

void loop() {
}

สรุป

จากบทความนี้ผู้เขียนหวังว่าคงได้ประโยชน์ในการทำความเข้าใจในการใช้งานความสามารถด้าน WiFi ของไมโครคอนโทรลเลอร์ ESP8266 กันมากขึ้น ซึ่งจะพบว่าตัวชิพนี้ทำงานได้ทั้ง 2 แบบ คือ เป็นลูกข่ายของเครือข่ายที่มีอยู่แล้ว หรือตั้งตัวเป็น AP เพื่อสร้างเครือข่ายสำหรับใช้งานเอง ซึ่งการนำไปประยุกต์ใช้จะเขียนถึงในบทความต่อไป

สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

แหล่งอ้างอิง

  1. ESP8266 Arduino Core: ESP8266WiFi Library
  2. ESP8266 Arduino Core: Station class
  3. WiKiperia: Wi-Fi Protected Setup

(C) 2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-07-30, 2021-07-31, 2021-08-01