ESP8266:Прошивки/Arduino/Библиотеки/Библиотека ESP8266WiFi/Класс сканирования/Простое и асинхронное сканирование WiFi-сетей

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.



Простое и асинхронное сканирование WiFi-сетей[1]

Чтобы подключить мобильный телефон к точке доступа, вы, как правило, открываете меню WiFi, находите список доступных точек и затем выбираете ту, что вам нужна. Данная статья рассказывает, как проделать то же самое при помощи ESP8266.

Простое сканирование

Этот пример показывает минимум кода, необходимый для поиска доступных сетей.

Отключение

Чтобы начать, переключите модуль в режим станции и отключитесь от точки доступа.

WiFi.mode(WIFI_STA);
WiFi.disconnect();

Функция disconnect() разорвет соединение с точкой доступа, которое модуль автоматически установил, используя данные, сохраненные в прошлый раз.

Сканирование сетей

Сделав небольшую задержку, чтобы модуль успел отключиться, начинаем сканирование ближайших сетей:

int n = WiFi.scanNetworks();

Теперь просто проверяем значение в переменной n. Если оно больше нуля, выводим список доступных сетей:

for (int i = 0; i < n; i++)
{
  Serial.println(WiFi.SSID(i));
}

В общем, ничего сложного.

Пример целиком

В верхней части этого скетча обязательно должна быть строчка

#include <ESP8266WiFi.h>

Целиком это выглядит следующим образом:

#include "ESP8266WiFi.h"

void setup()
{
  Serial.begin(115200);
  Serial.println();

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
}

void loop()
{
  Serial.print("Scan start ... ");
           //  "Запускаем сканирование ... " 
  int n = WiFi.scanNetworks();
  Serial.print(n);
  Serial.println(" network(s) found");
             //  " сетей найдено" 
  for (int i = 0; i < n; i++)
  {
    Serial.println(WiFi.SSID(i));
  }
  Serial.println();

  delay(5000);
}

Пример в действии

Загрузите этот скетч на ESP8266 и откройте монитор порта. Если вокруг ESP8266 есть какие-то точки доступа, в мониторе порта начнет появляться повторяющаяся запись вроде этой:

Scan start ... 5 network(s) found
Tech_D005107
HP-Print-A2-Photosmart 7520
ESP_0B09E3
Hack-4-fun-net
UPC Wi-Free

Вы наверняка заметите, что между появлением в мониторе порта фраз «Scan start ... » и «X network(s) found» пройдет очень много времени. Дело в том, что выполнение функции WiFi.scanNetworks() отнимает время – скетч ждет, пока она завершится, и лишь затем переходит к следующей строчке кода. Но что, если в это время ESP8266 будет выполнять задачу, нарушать действие которой никак нельзя (например, анимацию)?

Но решение есть. Можно воспользоваться асинхронным режимом сканирования, о котором рассказывается в разделе ниже. В нем также рассказывается, как печатать не только SSID, но и другие параметры доступных сетей.

Асинхронное сканирование

В этом скетче мы запустим процесс сканирования, а затем вернемся к выполнению кода в блоке loop(). Когда сканирование завершится, мы выверим время и проверим, удалось ли найти какие-нибудь WiFi-сети. «Критически важный процесс» будет симулирован миганием светодиода 4 раза в секунду. Необходимо, чтобы процесс сканирования не нарушал паттерн мигания светодиода.

Без delay()

Чтобы реализовать такой функционал, мы должны отказаться от функции delay() внутри блока loop(). Вместо этого мы зададим период, запускающий определенное действие. Затем внутри блока loop() поставим функцию millis(), при помощи которой будет проверяться, истек ли заданный период, и если истек, то запустим нужное действие. Аналогичную технику можно применить для периодического сканирования WiFi-сетей.

Исходные настройки

Во-первых, нам нужно задать период сканирования и внутреннюю переменную lastScanMillis, в которой будет храниться время последнего сканирования.

#define SCAN_PERIOD 5000
long lastScanMillis;

Когда начать

Внутри блока loop() проверяем, истек ли период SCAN_PERIOD, чтобы знать, нужно ли запустить следующее сканирование:

if (currentMillis - lastScanMillis > SCAN_PERIOD)
{
  WiFi.scanNetworks(true);
  Serial.print("\nScan start ... ");
           //  "Запуск сканирования ... "
  lastScanMillis = currentMillis;
}

Обратите внимание, что функция WiFi.scanNetworks(true) имеет дополнительный параметр true, которого не было в примере выше. Этот параметр активирует сканирование в асинхронном режиме, т.е. запускает процесс сканирования, не дожидаясь результата (обработка будет выполняться в фоновом режиме) и сразу переходя к следующей строчке кода. Асинхронный режим необходим, иначе 250-миллисекундный паттерн будет нарушен, т.к. сканирование занимает больше 250 мс.

Проверяем, выполнено ли сканирование

Наконец, нам нужно периодически проверять, завершился ли процесс сканирования, чтобы знать, пора ли печатать результаты. Для этого нам понадобится функция WiFi.scanComplete(), которая после завершения сканирования возвращает количество найденных сетей. Если сканирование по-прежнему в процессе, она вернет «-1», а если сканирование еще даже не было запущено, то «-2».

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

Обратите внимание, что функция WiFi.scanDelete() удаляет результаты сканирования из памяти, поэтому результаты не будут печататься в мониторе порта с каждым проходом через цикл loop().

Пример целиком

Ниже – полая версия скетча. Код внутри блока setup() описан в предыдущем примере, за исключением дополнительной функции pinMode(), которая настраивает контакт светодиода на вывод данных.

#include "ESP8266WiFi.h"

#define BLINK_PERIOD 250
long lastBlinkMillis;
boolean ledState;

#define SCAN_PERIOD 5000
long lastScanMillis;


void setup()
 {
  Serial.begin(115200);
  Serial.println();

  pinMode(LED_BUILTIN, OUTPUT);

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
}

void loop()
{
  long currentMillis = millis();

  // мигаем светодиодом:
  if (currentMillis - lastBlinkMillis > BLINK_PERIOD)
  {
    digitalWrite(LED_BUILTIN, ledState);
    ledState = !ledState;
    lastBlinkMillis = currentMillis;
  }

  // запускаем сканирование WiFi-сетей:
  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();
  }
}

Пример в действии

Загрузите этот скетч на ESP8266 и откройте монитор порта. В мониторе порта должна появиться примерно такая запись:

Scan start ... 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)

Проверяем светодиод. Он должен, не прерываясь, мигать с частотой четыре раза в секунду.

Итого

Функции класса сканирования дают массу возможностей для сканирования в синхронном и асинхронном режимах. Благодаря им мы можем запустить фоновое сканирование, которое не будет мешать другим процессам, запущенным модулем ESP8266.

О функциях для сканирования WiFi-сетей модулем ESP8266 читайте в [ссылка этой статье].

См.также

Внешние ссылки