Освой Arduino играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Базовый минимальный пример
Получить IP-адреса
Узнать настройки Wi-Fi модуля
WiFiScan
Сканируем WiFi-сеть. Расширенный вариант
Точка доступа
Отслеживаем момент подключения и отключения устройства к точке доступа
Mac-адрес для точки доступа
Включаем поддержку IPv6
Сколько устройств подключено к точке доступа
Для работы с Wi-Fi понадобится встроенная библиотека WiFi.h (исходники). В большинстве примеров вам надо знать имя сети и пароль от него. После окончания работы желательно вызывать метод WiFi.disconnect(true);.
Сначала рассмотрим базовый пример для общего понимания. Все пояснения в комментариях.
// Подключаем библиотеку
#include "WiFi.h"
// Указываем идентификатор и пароль от своей WiFi-сети
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
void setup() {
Serial.begin(115200);
// Начинаем подключение к сети
WiFi.begin(ssid, password);
// Проверяем статус. Если нет соединения, то выводим сообщение о подключении
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Соединяемся к WiFi-сети...");
}
Serial.println("Есть подключение к WiFi-сети");
}
void loop() {}
В нашем примере соединение с сетью WiFi происходит лишь в функции setup(), которая активируется только один раз при включении платы. Соответственно, при перезагрузке маршрутизатора или потере WiFi-сигнала соединение не будет восстановлено. Чтобы этого избежать, нужно добавить в функцию loop() проверку на необходимость восстановления соединения.
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
WiFi.begin(ssid, password);
}
Для простых примеров это не требуется, но в реально действующем коде такая проверка желательна.
Теперь можно писать более сложные примеры.
В пассивном режиме без входа в сеть вы получите IP-адрес, равный 0.0.0.0. Если нужно получить реальный адрес, то скетч нужно переписать. Добавим возможность входа в сеть, используя учётные данные.
#include "WiFi.h"
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Hostname: ");
Serial.println(WiFi.getHostname());
Serial.print("ESP Mac Address: ");
Serial.println(WiFi.macAddress());
Serial.print("Subnet Mask: ");
Serial.println(WiFi.subnetMask());
Serial.print("Gateway IP: ");
Serial.println(WiFi.gatewayIP());
Serial.print("DNS: ");
Serial.println(WiFi.dnsIP());
}
void loop() {}
Теперь вы получите реальный IP-адрес. Узнав адрес через WiFi.localIP(), вы можете в командной строке ввести команду ping ESP_ADDRESS (подставьте ваш адрес), чтобы убедиться, что устройство находится в сети. Пригодится для отладки примеров.
Метод WiFi.getHostname() возвращает имя платы espressif. По идее по этому имени тоже можно обращаться через команду ping espressif, но у меня этот вариант не заработал.
Также привёл другие вызовы функций, которые встречаются в библиотеке.
Другой вариант получения IP-адреса через лямбда-функции.
#include "WiFi.h"
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
void setup()
{
Serial.begin(115200);
WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.println(WiFi.localIP());
Serial.println(WiFi.getHostname());
}, SYSTEM_EVENT_STA_GOT_IP);
WiFi.begin(ssid, password);
}
void loop() {}
Ещё один пример получения IP-адреса разными способами. На этот раз обойдёмся без лямбда-функции. Как и в предыдущем примере мы отслеживаем событие SYSTEM_EVENT_STA_GOT_IP и при его наступлении вычисляем адрес.
Адрес вычисляем тремя способами. Первый способ самый простой, вызываем функцию localIP() и получаем готовый результат. Второй способ - получаем информацию из WiFiEventInfo_t через его поле got_ip. Третий способ - используем класс IPAddress. Два последних способа даны для общего развития, пользуйтесь первым.
#include "WiFi.h"
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
void WiFiStationGotIP(WiFiEvent_t event, WiFiEventInfo_t info)
{
Serial.println(WiFi.localIP()); // первый способ
// второй способ
Serial.print(ip4_addr1(&(info.got_ip.ip_info.ip)));
Serial.print(".");
Serial.print(ip4_addr2(&(info.got_ip.ip_info.ip)));
Serial.print(".");
Serial.print(ip4_addr3(&(info.got_ip.ip_info.ip)));
Serial.print(".");
Serial.print(ip4_addr4(&(info.got_ip.ip_info.ip)));
Serial.println();
// третий способ
Serial.println(IPAddress(info.got_ip.ip_info.ip.addr));
}
void setup()
{
Serial.begin(115200);
WiFi.onEvent(WiFiStationGotIP, SYSTEM_EVENT_STA_GOT_IP);
WiFi.begin(ssid, password);
}
void loop() {}
Для скетча нам не понадобится вводить пароль от Wi-Fi, достаточно просто включить сам Wi-Fi на плате и узнать его Mac-адрес, запустить диагностику, узнать локальный адрес.
/*
ESP-32 Example,
start WiFi (without ssid and password)
and print the MAC address to Serial.
*/
#include <WiFi.h>
byte mac[6];
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.print("\nRun diagnostic...\n");
WiFi.printDiag(Serial);
Serial.println();
Serial.print("Program Start...");
WiFi.enableSTA(true);
WiFi.begin();
Serial.println("WiFi began");
WiFi.macAddress(mac);
Serial.print("MAC: ");
Serial.print(mac[0], HEX);
Serial.print(":");
Serial.print(mac[1], HEX);
Serial.print(":");
Serial.print(mac[2], HEX);
Serial.print(":");
Serial.print(mac[3], HEX);
Serial.print(":");
Serial.print(mac[4], HEX);
Serial.print(":");
Serial.println(mac[5], HEX);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Hostname: ");
Serial.println(WiFi.getHostname());
}
void loop() {}
Встроенный пример Examples/WiFi/WiFiScan служит для сканирования WiFi-сети. Выводит число найденных точек и их названия.
В скетче используются следующие функции:
#include "WiFi.h"
void setup()
{
Serial.begin(115200);
// Set WiFi to station mode and disconnect from an AP if it was previously connected
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.println("Setup done");
}
void loop()
{
Serial.println("scan start");
// WiFi.scanNetworks will return the number of networks found
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
} else {
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");
delay(10);
}
}
Serial.println("");
// Wait a bit before scanning again
delay(5000);
}
Чтобы просканировать текущую WiFi-сеть, нам понадобятся учётная запись для входа в неё (идентификатор и пароль). После успешного входа запускаем сканирование через функцию WiFi.scanNetworks(), которая вернёт информацию о всех точках доступа с сопутствующими свойствами.
Для удобства часть кода поместим в отдельные функции: scanNetworks() и connectToNetwork() (её можно использовать при использовании контроллера в качестве веб-клиента.
#include <WiFi.h>
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
String translateEncryptionType(wifi_auth_mode_t encryptionType) {
switch (encryptionType) {
case (WIFI_AUTH_OPEN):
return "Open";
case (WIFI_AUTH_WEP):
return "WEP";
case (WIFI_AUTH_WPA_PSK):
return "WPA_PSK";
case (WIFI_AUTH_WPA2_PSK):
return "WPA2_PSK";
case (WIFI_AUTH_WPA_WPA2_PSK):
return "WPA_WPA2_PSK";
case (WIFI_AUTH_WPA2_ENTERPRISE):
return "WPA2_ENTERPRISE";
}
}
void scanNetworks() {
int numberOfNetworks = WiFi.scanNetworks();
Serial.print("Number of networks found: ");
Serial.println(numberOfNetworks);
for (int i = 0; i < numberOfNetworks; i++) {
Serial.print("Network name: ");
Serial.println(WiFi.SSID(i));
Serial.print("Signal strength: ");
Serial.println(WiFi.RSSI(i));
Serial.print("MAC address: ");
Serial.println(WiFi.BSSIDstr(i));
Serial.print("Encryption type: ");
String encryptionTypeDescription = translateEncryptionType(WiFi.encryptionType(i));
Serial.println(encryptionTypeDescription);
Serial.println("-----------------------");
}
}
void connectToNetwork() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Соединяемся с Wi-Fi..");
}
Serial.println("Соединение с Wi-Fi установлено");
}
void setup() {
Serial.begin(115200);
scanNetworks();
connectToNetwork();
Serial.println(WiFi.macAddress());
Serial.println(WiFi.localIP());
WiFi.disconnect(true);
Serial.println(WiFi.localIP());
}
void loop() {}
Обратите внимание, что мы получаем IP-адрес два раза. Первый раз при выходе в интернет, а второй раз - когда закрываем WiFi-соединение. Во втором случае IP-адрес будет равен 0.0.0.0
В мониторе порта выводится следующая информация (часть данных я убрал в целях безопасности).
Network name: Keenetic-7247
Signal strength: -79
MAC address: *:*:*:*:*:0A
Encryption type: WPA2_PSK
-----------------------
Network name: how2make 2.3
Signal strength: -91
MAC address: *:*:*:*:*:90
Encryption type: WPA_WPA2_PSK
-----------------------
Network name: TP-Link_4A15
Signal strength: -91
MAC address: *:*:*:*:*:84
Encryption type: WPA_WPA2_PSK
-----------------------
Соединяемся с Wi-Fi..
Соединяемся с Wi-Fi..
Соединение с Wi-Fi установлено
*:*:*:*:*:20
192.163.2.21
0.0.0.0
Плата ESP32 может работать как точка доступа. Для первого знакомства получим базовую информацию о точке доступа через доступные функции. Мы можем установить собственные значения для SSID и пароля (пароль можно даже не указывать, чтобы сеть была открытой).
#include "WiFi.h"
const char* ssid = "ESP32Cat";
const char* password = "meow";
void setup() {
Serial.begin(115200);
// WiFi.softAP(ssid, password);
WiFi.softAP(ssid); // без пароля
Serial.println();
Serial.print("IP address: ");
Serial.println(WiFi.softAPIP());
}
void loop() {}
После загрузки скетча мы получим IP-адрес платы. В настройках компьютера или смартфона должна появиться созданная точка доступа.
Кстати, когда пробовал вариант с паролем, то точка доступа не создалась почему-то. Upd: читатель сайта прислал комментарий по этому поводу: Дело в том, что любая точка доступа в пароле должна иметь минимум 8 символов, если я правильно помню, а в примере всего 4, поэтому скетч ведёт себя некорректно. В этом вся проблема, указываете от 8 символов - код работает стабильно.
За соответствующие события отвечают SYSTEM_EVENT_AP_STACONNECTED и SYSTEM_EVENT_AP_STADISCONNECTED.
После загрузки скетчка в настройках телефона найдите созданную точку доступа и присоединитесь к ней. Момент подключения будет обнаружен и в мониторе порта появится сообщение о соединении.
#include "WiFi.h"
void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.println("Соединение установлено");
// что-то делаем, например, вычисляем mac-адрес
for (int i = 0; i < 6; i++) {
Serial.printf("%02X", info.sta_connected.mac[i]);
if (i < 5)Serial.print(":");
}
Serial.println("\n------------");
}
void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.println("Соединение разорвано");
// что-то делаем, например, снова вычисляем mac-адрес
for (int i = 0; i < 6; i++) {
Serial.printf("%02X", info.sta_disconnected.mac[i]);
if (i < 5)Serial.print(":");
}
Serial.println("\n------------");
}
void setup() {
Serial.begin(115200);
WiFi.softAP("ESP32Cat");
WiFi.onEvent(WiFiStationConnected, SYSTEM_EVENT_AP_STACONNECTED);
WiFi.onEvent(WiFiStationDisconnected, SYSTEM_EVENT_AP_STADISCONNECTED);
}
void loop() {}
В первом примере с получением настроек модуля мы вычисляли Mac-адрес через функцию WiFi.macAddress. Существует также функция WiFi.softAPmacAddress(), когда плата работает в режиме точки доступа.
#include "WiFi.h"
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_MODE_AP);
Serial.println(WiFi.softAPmacAddress());
}
void loop() {}
Мы можем включить поддержку IPv6 и получить адрес в этом формате. Включение поддержки IPv6 происходит при помощи функции softAPenableIpV6(). Вызовем функцию при событии SYSTEM_EVENT_AP_START, когда активируется точка доступа.
После включения поддержки в событии SYSTEM_EVENT_AP_STA_GOT_IP6 (получение адреса) узнаём IPv6-адрес.
#include "WiFi.h"
void WiFiApStarted(WiFiEvent_t event, WiFiEventInfo_t info) {
WiFi.softAPenableIpV6();
}
void WiFiGotIp(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.println(WiFi.softAPIPv6());
}
void setup() {
Serial.begin(115200);
WiFi.onEvent(WiFiApStarted, SYSTEM_EVENT_AP_START);
WiFi.onEvent(WiFiGotIp, SYSTEM_EVENT_AP_STA_GOT_IP6);
WiFi.softAP("ESP32Cat");
}
void loop() {}
Узнать число устройств, которые в данный момент подключены к точке доступа, можно через функцию softAPgetStationNum(). После запуска скетча подключите телефон и другие устройства к точке доступа, чтобы увидеть изменения.
#include "WiFi.h"
void setup() {
Serial.begin(115200);
WiFi.softAP("ESP32Cat");
}
void loop() {
Serial.print("Stations connected: ");
Serial.println(WiFi.softAPgetStationNum());
delay(5000);
}