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库,大家使用的时候不需要

#include <ESP8266WiFiSTA.h>

只需要引入

#include<ESP8266WiFi.h>

    至于原因,敬请回顾 ESP8266开发之旅 网络篇② ESP8266 工作模式与ESP8266WiFi库。 首先,对于Scan类库的描述,可以拆分为两个部分:

  1. 第一部分方法,扫描操作;
  2. 第二部分方法,获取扫描结果;

    讲解之前,先浏览一下博主整理的百度脑图,以便有个整体认识:

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

应用实例:

//实例代码 这只是部分代码 不能直接使用
//同步扫描
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热点):

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

测试结果:

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

测试结果:

5. 总结

    扫描并不是多复杂的功能,分为同步扫描和异步扫描,一般楼主建议用异步扫描方式,不影响代码运行。

最新文章

  1. shared jedis 在spring中的配置
  2. showModalDialog 的重要提示
  3. 根据显示的字符多少来做Label的自适应高度
  4. Angularjs,WebAPI 搭建一个简易权限管理系统 —— WebAPI项目主体结构(四)
  5. sql 查询练习
  6. Navicat 导入导出
  7. 主流智能手机屏幕材质介绍 及 LCD闪屏现象分析
  8. Freemarker日期函数处理【转】
  9. 转: sublime text 2 前端编码神器-快捷键与使用技巧介绍
  10. linux上kafka模拟客户端发送、接受消息
  11. 硬核机器学习干货,手把手教你写KNN!
  12. set 数据类型
  13. Java:JavaBean和BeanUtils
  14. LOJ #2359. 「NOIP2016」天天爱跑步(倍增+线段树合并)
  15. TF之AE:AE实现TF自带数据集数字真实值对比AE先encoder后decoder预测数字的精确对比—Jason niu
  16. Linux文件系统命令 cd
  17. folly无锁队列,尝试添加新的函数
  18. Nginx服务器报 &quot;Too Many Open Files&quot;
  19. Mysql截取和拆分字符串函数用法
  20. Cacheable redis 宕机

热门文章

  1. ActiveMQ JMX使用
  2. class命名归类
  3. github博客Hexo引流到微信
  4. 深入探究js中的隐式变量声明
  5. Java Map知识点
  6. Basic Example using SMTP (for PHPMailer v5.0.0 and up)
  7. 设计模式——统一建模语言UML
  8. Linux上编译安装PHP
  9. 10个值得深思的_PHP_面试问题
  10. redis安装详细