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. 总结

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

ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用的更多相关文章

  1. ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  2. ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  3. ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  4. ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  5. ESP8266开发之旅 网络篇⑩ UDP服务

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  6. ESP8266开发之旅 网络篇⑪ WebServer——ESP8266WebServer库的使用

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  7. ESP8266开发之旅 网络篇⑬ SPIFFS——ESP8266 SPIFFS文件系统

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  8. ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用

    1. 前言     在前面的篇章中,博主给大家讲解了ESP8266的软硬件配置以及基本功能使用,目的就是想让大家有个初步认识.并且,博主一直重点强调 ESP8266 WiFi模块有三种工作模式: St ...

  9. ESP8266开发之旅 网络篇③ Soft-AP——ESP8266WiFiAP库的使用

    1. 前言     在前面的篇章中,博主给大家讲解了ESP8266的软硬件配置以及基本功能使用,目的就是想让大家有个初步认识.并且,博主一直重点强调 ESP8266 WiFi模块有三种工作模式: St ...

随机推荐

  1. python接口测试(post,get)-传参(data和json之间的区别)

    python接口测试如何正确传参: POST 传data:data是python字典格式:传参data=json.dumps(data)是字符串类型传参 #!/usr/bin/env python3 ...

  2. Hadoop入门 之 Hadoop常识

    1.Hadoop是什么? 答:Hadoop是开源的分布式存储和分布式计算平台. 2.Hadoop的组成是什么? 答:Hadoop由HDFS和MapReduce这两个核心部分组成. HDFS(Hadoo ...

  3. [Leetcode] 第299题 猜数字游戏

    一.题目描述 请写出一个根据秘密数字和朋友的猜测数返回提示的函数,用 A 表示公牛,用 B 表示奶牛. 请注意秘密数字和朋友的猜测数都可能含有重复数字. 示例 1: 输入: secret = &quo ...

  4. redis实现网关限流(限制API调用次数1000次/分)

    添加maven依赖,使用springboot2.x版本 <dependency> <groupId>org.springframework.boot</groupId&g ...

  5. 小记redis持久化的机制

    刚学redis,就经常看到两种持久化机制在眼头晃,RDB和AOF,然而当时学的还知道这两东西是啥玩意,过段时间又忘了,中文记忆这两种概念总感觉有些别扭.今心血来潮翻看redis的配置文件,豁然开朗,仿 ...

  6. 1 Processing入门简介

    1 Processing入门简介 1.1 Before you start Processing是一个为开发面向图形的应用(visually oriented application)而生的简单易用的 ...

  7. 关于Python json解析过程遇到的TypeError: expected string or buffer

    关于Python json解析过程遇到的问题:(爬取天气json数据所遇到的问题http://tianqi.2345.com/) part.1 url——http://tianqi.2345.com/ ...

  8. (7)Cmake的使用简介

        CMake是一个跨平台的安装(编译)工具,是一个比Make更高级的的编译配置工具,可以根据不同平台.不同编译器,通过编写CmakeLists,可以控制生成的Makefile,从而控制编译过程. ...

  9. EF Core设置字段默认时间

    ---恢复内容开始--- 在EF的官方文档上只提到了用 Fluent API来设置默认值. 但是我们日常开发中,会把公用字段都写成基类.比如行创建时间 在需要默认时间的字段加上一个特性 [Databa ...

  10. UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 357: illegal multibyte sequence 错误解决方法(已解决)

    今天在搭建数据驱动测试框架的时候遇到这个错误: 好在我英语水平还不错(也就六级水平吧),根据英文提示说是多字节数据顺序是非法的 顺着错误往上找发现 File "C:\Users\Mr雷的电脑 ...