如今,一般,爲了讓手機連上一個WiFi熱點,基本上都是打開手機設置裏面的WiFi設置功能,而後會看到裏面有個WiFi熱點列表,而後選擇你要的鏈接上。 基本上你只要打開手機鏈接WiFi功能,都會發現附近有超級多的各類來路不明的WiFi熱點(鏈接有風險需謹慎),那麼手機是怎麼知道附近的WiFi的呢?
一般,無線網絡提供的WiFi熱點,大部分都開放了SSID廣播(記得以前博主講過WiFi熱點也能夠隱藏的),Scan WiFi的功能就是掃描出全部附近的WiFi熱點的SSID信息,這樣一來,客戶端就能夠根據須要選擇不一樣的SSID連入對應的無線網絡中。緩存
通常掃描網絡須要幾百毫秒才能完成。
而掃描WiFi過程包括:網絡
那麼Scan WiFi庫提供了兩種方式實現上面的掃描過程:多線程
通常來講,學過多線程的讀者應該都知道同步和異步的區別,這裏就不細說,非本篇的重點內容。異步
有了前面的理論基礎,那麼咱們開始詳解一下ESP8266 scan wifi功能專用庫——ESP8266WiFiScan庫,你們使用的時候不須要async
#include <ESP8266WiFiSTA.h>
只須要引入ide
#include<ESP8266WiFi.h>
至於緣由,敬請回顧 ESP8266開發之旅 網絡篇② ESP8266 工做模式與ESP8266WiFi庫。 首先,對於Scan類庫的描述,能夠拆分爲兩個部分:函數
講解以前,先瀏覽一下博主整理的百度腦圖,以便有個總體認識:
oop
函數說明:測試
/** * Start scan WiFi networks available * @param async run in async mode(是否啓動異步掃描) * @param show_hidden show hidden networks(是否掃描隱藏網絡) * @param channel scan only this channel (0 for all channels)(是否掃描特定通道) * @param ssid* scan for only this ssid (NULL for all ssid's)(是否掃描特定的SSID) * @return Number of discovered networks */ int8_t scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL);
應用實例:ui
//實例代碼 這只是部分代碼 不能直接使用 //同步掃描 int n = WiFi.scanNetworks();//不須要填任何參數 Serial.println("scan done"); if (n == 0) { Serial.println("no networks found"); } else { Serial.println(" networks found"); }
函數說明:
/** * Start scan WiFi networks available * @param async run in async mode(是否啓動異步掃描) * @param show_hidden show hidden networks(是否掃描隱藏網絡) * @param channel scan only this channel (0 for all channels)(是否掃描特定通道) * @param ssid* scan for only this ssid (NULL for all ssid's)(是否掃描特定的SSID) * @return Number of discovered networks */ int8_t scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL);
應用實例:
//實例代碼 這只是部分代碼 不能直接使用 //異步掃描 WiFi.scanNetworks(true); // print out Wi-Fi network scan result uppon completion int n = WiFi.scanComplete(); if(n >= 0){ Serial.printf("%d network(s) found\n", n); for (int i = 0; i < n; i++){ Serial.printf("%d: %s, Ch:%d (%ddBm) %s\n", i+1, WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : ""); } //打印一次結果以後把緩存中的數據清掉 WiFi.scanDelete(); }
函數說明:
/** * Starts scanning WiFi networks available in async mode * @param onComplete the event handler executed when the scan is done * @param show_hidden show hidden networks */ void scanNetworksAsync(std::function<void(int)> onComplete, bool show_hidden = false);
應用實例:
//實例代碼 #include "ESP8266WiFi.h" void prinScanResult(int networksFound) { Serial.printf("%d network(s) found\n", networksFound); for (int i = 0; i < networksFound; i++) { Serial.printf("%d: %s, Ch:%d (%ddBm) %s\n", i + 1, WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : ""); } } void setup() { Serial.begin(115200); Serial.println(); WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); WiFi.scanNetworksAsync(prinScanResult); } void loop() {} //應該會打印以下相似的顯示 //5 network(s) found //1: Tech_D005107, Ch:6 (-72dBm) //2: HP-Print-A2-Photosmart 7520, Ch:6 (-79dBm) //3: ESP_0B09E3, Ch:9 (-89dBm) open //4: Hack-4-fun-net, Ch:9 (-91dBm) //5: UPC Wi-Free, Ch:11 (-79dBm)
函數說明:
/** * called to get the scan state in Async mode(異步掃描的結果函數) * @return scan result or status * -1 if scan not find * -2 if scan not triggered */ int8_t scanComplete();
函數說明:
/** * delete last scan result from RAM(從內存中刪除最近的掃描結果) */ void scanDelete();
注意點:
函數說明:
/** * Return the SSID discovered during the network scan. * @param i specify from which network item want to get the information * @return ssid string of the specified item on the networks scanned list */ String SSID(uint8_t networkItem);
函數說明:
/** * Return the RSSI of the networks discovered during the scanNetworks(信號強度) * @param i specify from which network item want to get the information * @return signed value of RSSI of the specified item on the networks scanned list */ int32_t RSSI(uint8_t networkItem);
函數說明:
/** * Return the encryption type of the networks discovered during the scanNetworks(加密方式) * @param i specify from which network item want to get the information * @return encryption type (enum wl_enc_type) of the specified item on the networks scanned list * ............ Values map to 802.11 encryption suites..................... * AUTH_OPEN ----> ENC_TYPE_WEP = 5, * AUTH_WEP ----> ENC_TYPE_TKIP = 2, * AUTH_WPA_PSK ----> ENC_TYPE_CCMP = 4, * ........... except these two, 7 and 8 are reserved in 802.11-2007....... * AUTH_WPA2_PSK ----> ENC_TYPE_NONE = 7, * AUTH_WPA_WPA2_PSK ----> ENC_TYPE_AUTO = 8 */ uint8_t encryptionType(uint8_t networkItem);
函數說明:
/** * return MAC / BSSID of scanned wifi (物理地址) * @param i specify from which network item want to get the information * @return uint8_t * MAC / BSSID of scanned wifi */ uint8_t * BSSID(uint8_t networkItem); /** * return MAC / BSSID of scanned wifi (物理地址) * @param i specify from which network item want to get the information * @return uint8_t * MAC / BSSID of scanned wifi */ String BSSIDstr(uint8_t networkItem);
函數說明:
/** * loads all infos from a scanned wifi in to the ptr parameters * @param networkItem uint8_t * @param ssid const char** * @param encryptionType uint8_t * * @param RSSI int32_t * * @param BSSID uint8_t ** * @param channel int32_t * * @param isHidden bool * * @return (true if ok) */ bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel, bool &isHidden);
注意點:
函數說明:
/** * return channel of scanned wifi(通道號) */ int32_t channel(uint8_t networkItem);
函數說明:
/** * return if the scanned wifi is Hidden (no SSID)(判斷掃描到的wifi是不是隱藏wifi) * @param networkItem specify from which network item want to get the information * @return bool (true == hidden) */ bool isHidden(uint8_t networkItem);
上面博主講了一堆方法理論的知識,下面咱們開始講解操做實例,博主儘可能都在代碼中註釋,直接看代碼就好。
實例代碼:
/** * Demo: * STA模式下,演示同步掃描Scan wifi功能 * @author 單片機菜鳥 * @date 2019/09/03 */ #include <ESP8266WiFi.h> //如下三個定義爲調試定義 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) void setup() { //設置串口波特率,以便打印信息 DebugBegin(115200); //延時5s 爲了演示效果 delay(5000); // 我不想別人鏈接我,只想作個站點 WiFi.mode(WIFI_STA); //斷開鏈接 WiFi.disconnect(); delay(100); DebugPrintln("Setup done"); } void loop() { DebugPrintln("scan start"); // 同步掃描,等待返回結果 int n = WiFi.scanNetworks(); DebugPrintln("scan done"); if (n == 0){ DebugPrintln("no networks found"); }else{ DebugPrint(n); DebugPrintln(" networks found"); for (int i = 0; i < n; ++i){ DebugPrint(i + 1); DebugPrint(": "); //打印wifi帳號 DebugPrint(WiFi.SSID(i)); DebugPrint(","); DebugPrint(String("Ch:")+WiFi.channel(i)); DebugPrint(","); DebugPrint(WiFi.isHidden(i)?"hide":"show"); DebugPrint(" ("); //打印wifi信號強度 DebugPrint(WiFi.RSSI(i)); DebugPrint("dBm"); DebugPrint(")"); //打印wifi加密方式 DebugPrintln((WiFi.encryptionType(i) == ENC_TYPE_NONE)?"open":"*"); delay(10); } } DebugPrintln(""); // 延時5s以後再次掃描 delay(5000); }
測試結果(博主附近潛在的WiFi熱點):
實例代碼:
/** * Demo: * STA模式下,演示異步掃描Scan wifi功能 * @author 單片機菜鳥 * @date 2019/09/03 */ #include <ESP8266WiFi.h> //如下三個定義爲調試定義 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) //定義一個掃描時間間隔 #define SCAN_PERIOD 5000 long lastScanMillis; void setup() { //設置串口波特率,以便打印信息 DebugBegin(115200); //延時5s 爲了演示效果 delay(5000); // 我不想別人鏈接我,只想作個站點 WiFi.mode(WIFI_STA); //斷開鏈接 WiFi.disconnect(); delay(100); DebugPrintln("Setup done"); } void loop() { long currentMillis = millis(); //觸發掃描 if (currentMillis - lastScanMillis > SCAN_PERIOD){ WiFi.scanNetworks(true); Serial.print("\nScan start ... "); lastScanMillis = currentMillis; } // 判斷是否有掃描結果 int n = WiFi.scanComplete(); if(n >= 0){ Serial.printf("%d network(s) found\n", n); for (int i = 0; i < n; i++){ Serial.printf("%d: %s, Ch:%d (%ddBm) %s\n", i+1, WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : ""); } //打印完一次掃描結果以後 刪除內存保存結果 WiFi.scanDelete(); } }
測試結果:
實例代碼:
/** * Demo: * STA模式下,演示異步掃描Scan wifi功能 * @author 單片機菜鳥 * @date 2019/09/03 */ #include <ESP8266WiFi.h> //如下三個定義爲調試定義 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) /** * 打印掃描結果 * @param networksFound 結果個數 */ void prinScanResult(int networksFound){ Serial.printf("%d network(s) found\n", networksFound); for (int i = 0; i < networksFound; i++) { Serial.printf("%d: %s, Ch:%d (%ddBm) %s\n", i + 1, WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : ""); } } void setup() { //設置串口波特率,以便打印信息 DebugBegin(115200); //延時5s 爲了演示效果 delay(5000); // 我不想別人鏈接我,只想作個站點 WiFi.mode(WIFI_STA); //斷開鏈接 WiFi.disconnect(); delay(100); DebugPrintln("Setup done"); Serial.print("\nScan start ... "); WiFi.scanNetworksAsync(prinScanResult); } void loop() { }
測試結果:
掃描並非多複雜的功能,分爲同步掃描和異步掃描,通常樓主建議用異步掃描方式,不影響代碼運行。