ESP8266開發之旅 網絡篇⑤ Scan WiFi——ESP8266WiFiScan庫的使用

1. 前言

    如今,一般,爲了讓手機連上一個WiFi熱點,基本上都是打開手機設置裏面的WiFi設置功能,而後會看到裏面有個WiFi熱點列表,而後選擇你要的鏈接上。 基本上你只要打開手機鏈接WiFi功能,都會發現附近有超級多的各類來路不明的WiFi熱點(鏈接有風險需謹慎),那麼手機是怎麼知道附近的WiFi的呢?
    一般,無線網絡提供的WiFi熱點,大部分都開放了SSID廣播(記得以前博主講過WiFi熱點也能夠隱藏的),Scan WiFi的功能就是掃描出全部附近的WiFi熱點的SSID信息,這樣一來,客戶端就能夠根據須要選擇不一樣的SSID連入對應的無線網絡中。緩存

2. scan WiFi功能

    通常掃描網絡須要幾百毫秒才能完成。
    而掃描WiFi過程包括:網絡

  • 觸發掃描過程
  • 等待完成
  • 提供結果

    那麼Scan WiFi庫提供了兩種方式實現上面的掃描過程:多線程

  1. 同步掃描:經過單個函數在一次運行中完成,須要等待完成全部操做才能繼續運行下面的操做。
  2. 異步掃描:把上面的過程分紅幾個步驟,每一個步驟由一個單獨函數完成,咱們能夠在掃描過程當中執行其餘任務。

    通常來講,學過多線程的讀者應該都知道同步和異步的區別,這裏就不細說,非本篇的重點內容。異步

3. ESP8266WiFiScan庫

    有了前面的理論基礎,那麼咱們開始詳解一下ESP8266 scan wifi功能專用庫——ESP8266WiFiScan庫,你們使用的時候不須要async

#include <ESP8266WiFiSTA.h>

只須要引入ide

#include<ESP8266WiFi.h>

    至於緣由,敬請回顧 ESP8266開發之旅 網絡篇② ESP8266 工做模式與ESP8266WiFi庫。 首先,對於Scan類庫的描述,能夠拆分爲兩個部分:函數

  1. 第一部分方法,掃描操做;
  2. 第二部分方法,獲取掃描結果;

    講解以前,先瀏覽一下博主整理的百度腦圖,以便有個總體認識:
imageoop

3.1 掃描操做方法

3.1.1 scanNetworks —— 同步掃描周邊有效wifi網絡

函數說明:測試

/**
 * 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");
}

3.1.2 scanNetworks(async ) —— 異步掃描周邊有效wifi網絡

函數說明:

/**
 * 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();
}

3.1.3 scanNetworksAsync —— 異步掃描周邊wifi網絡,並回調結果

函數說明:

/**
 * 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)

3.1.4 scanComplete —— 檢測異步掃描的結果

函數說明:

/**
 * 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();

3.1.5 scanDelete —— 從內存中刪掉最近掃描結果

函數說明:

/**
 * delete last scan result from RAM(從內存中刪除最近的掃描結果)
 */
void scanDelete();

注意點:

  • 若是不刪除,將會疊加上次掃描的結果;

3.2 掃描結果方法

3.2.1 SSID —— 獲取wifi網絡名字

函數說明:

/**
 * 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);

3.2.2 RSSI —— 獲取wifi網絡信號強度

函數說明:

/**
 * 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);

3.2.3 encryptionType —— 獲取wifi網絡加密方式

函數說明:

/**
 * 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);

3.2.4 BSSID —— 獲取wifi網絡mac地址

函數說明:

/**
 * 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);

3.2.5 getNetworkInfo —— 獲取總體網絡信息,名字,信號強度等

函數說明:

/**
 * 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);

注意點:

  • 入參前面多數加了&,意味着調完函數後外面獲取到詳細信息;

3.2.6 channel —— 獲取wifi網絡通道號

函數說明:

/**
 * return channel of scanned wifi(通道號)
 */
int32_t channel(uint8_t networkItem);

3.2.7 isHidden —— 判斷wifi網絡是不是隱藏網絡

函數說明:

/**
 * 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);

4. 實例操做

    上面博主講了一堆方法理論的知識,下面咱們開始講解操做實例,博主儘可能都在代碼中註釋,直接看代碼就好。

4.1 操做實例1:同步掃描

實例代碼:

/**
 * 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熱點):
image

4.2 操做實例2: 異步掃描方式1

實例代碼:

/**
 * 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();
  }
}

測試結果:
image

4.3 操做實例3:異步掃描方式2

實例代碼:

/**
 * 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() {
}

測試結果:
image

5. 總結

    掃描並非多複雜的功能,分爲同步掃描和異步掃描,通常樓主建議用異步掃描方式,不影響代碼運行。

相關文章
相關標籤/搜索