В этом уроке мы создадим веб-сервер на базе ESP32 с использованием ESP-IDF. Веб-сервер сможет управлять встроенным светодиодом ESP32, подключенным к GPIO2. Плата ESP32 будет размещать HTML- и CSS-файлы в виде строк и отвечать на запросы веб-клиента этими HTML- и CSS-файлами. Аналогичным образом, она будет принимать HTTP-запросы от веб-клиента и управлять встроенным светодиодом.
Также на нашем сайте вы можете посмотреть аналогичный проект веб-сервера на модуле ESP32 для управления светодиодом на основе Arduino IDE.
Обзор веб-сервера на ESP32
Веб-сервер отвечает простыми HTML- и CSS-файлами, которые отображают кнопки управления светодиодами, состояние светодиодов, заголовок «ESP32 WEB SERVER» и символ лампы. Пользователь будет нажимать эти кнопки для управления выходом ESP32, который будет представлять собой GPIO2, через который подключен встроенный светодиод. Пользователь может получить доступ к веб-серверу по IP-адресу с помощью любого веб-клиента, например, веб-браузера на ноутбуке или мобильном телефоне.

Как работает веб-сервер?
Как уже упоминалось, ESP32 в нашем проекте выступает в роли веб-сервера и предоставляет HTML- и CSS-файлы веб-клиенту. Он также отвечает на запросы GET HTML для выполнения действий на GPIO2. В качестве клиента может выступать любой веб-браузер.
Мы создадим веб-сервер с помощью библиотеки HTTP-веб-сервера, доступной в esp-idf. Кроме того, мы создадим HTML- и CSS-файлы и сохраним их в ESP32 в виде массива символов. Когда пользователь отправит HTTP GET-запрос, введя IP-адрес в веб-браузере, ESP32 ответит буфером, содержащим HTML- и CSS-файлы.
На графическом интерфейсе пользователя есть две кнопки: “ON” («ВКЛ») и “OFF” («ВЫКЛ»). Пользователь сможет управлять выводами GPIO ESP32 с помощью этих кнопок. При нажатии кнопки «ВКЛ» URL-адрес перенаправляет на IP-адрес, за которым следует /led2on, и аналогично при нажатии кнопки «ВЫКЛ» URL-адрес перенаправляет на IP-адрес, за которым следует /led2off. Используя эти подпути URL-адреса, мы запускаем соответствующую функцию обратного вызова в нашем коде для управления светодиодом и отправки ответа веб-клиенту.
Веб-сервер на базе ESP32 с модулем ESP-IDF
В этом разделе мы создадим веб-сервер управления контактом ESP32 с использованием ESP-IDF. Плата ESP32 будет работать в режиме станции, подключаясь к сети Wi-Fi через маршрутизатор. После успешного подключения к точке доступа плате будет присвоен IP-адрес, который будет использоваться для доступа к веб-серверу.
Создание проекта
Откройте VS Code и перейдите в меню (View > Command Palette («Вид» > «Палитра команд»). Введите в строке поиска ESP-IDF: New Project и нажмите Enter.
Укажите название проекта и каталог. Мы назвали наш проект «ESP_IDF_WEB_SERVER». Для платы ESP-IDF мы выбрали опцию custom board («Пользовательская плата»). В качестве целевой платформы ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ («Выбрать шаблон»), чтобы продолжить.
В разделе Extension («Расширение») выберите опцию ESP-IDF:
На вкладке get-started («Начало работы») мы щелкнем по пункту «sample_project». Затем нажмем ‘Create project using template sample_project’ («Создать проект, используя шаблон sample_project»).
Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».
Это открывает наш проект ESP_IDF_WEB_SERVER, который мы создали на вкладке EXPLORER. Внутри папки проекта находится несколько папок. Это справедливо для каждого проекта, который вы создадите с помощью ESP-IDF Explorer.
Конфигурация проекта
Создайте новый файл с именем ' Kconfig.projbuild ' в основной папке. Скопируйте приведенный ниже код в этот новый файл.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
menu "Example Configuration" config ESP_WIFI_SSID string "WiFi SSID" default "myssid" help SSID (network name) for the example to connect to. config ESP_WIFI_PASSWORD string "WiFi Password" default "mypassword" help WiFi password (WPA or WPA2) for the example to use. config ESP_MAXIMUM_RETRY int "Maximum retry" default 5 help Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. endmenu |
Теперь перейдите в меню menuconfig. Щелкните значок, показанный ниже. Откроется редактор конфигурации ESP-IDF SDK.
Прокрутите вниз и откройте Example Configuration. Здесь мы можем установить параметры конфигурации для этого примера в соответствии с нашими потребностями. Это включает в себя SSID сети Wi-Fi, пароль сети Wi-Fi и максимальное количество попыток повтора. Укажите SSID и пароль вашей сети Wi-Fi, к которой будет подключаться плата ESP32. По умолчанию максимальное количество попыток установлено на 5. Вы можете изменить это значение по своему усмотрению. После указания параметров конфигурации нажмите кнопку «Сохранить» вверху.
Код веб-сервера для управления контактом GPIO на ESP32
В основной папке находится исходный код, то есть файл main.c будет расположен именно здесь .
Перейдите в папку main > main.c и откройте её. Скопируйте приведённый ниже код в свой файл main.c. Этот код создаст веб-сервер, размещённый на ESP32, с помощью которого пользователь сможет переключать встроенный светодиод с помощью кнопок.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
#include <stdio.h> #include <stdlib.h> #include <string.h> //Requires by memset #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" #include "esp_spi_flash.h" #include <esp_http_server.h> #include "esp_wifi.h" #include "esp_event.h" #include "freertos/event_groups.h" #include "esp_log.h" #include "nvs_flash.h" #include "esp_netif.h" #include "driver/gpio.h" #include <lwip/sockets.h> #include <lwip/sys.h> #include <lwip/api.h> #include <lwip/netdb.h> #define LED_PIN 2 char on_resp[] = "<!DOCTYPE html><html><head><style type=\"text/css\">html { font-family: Arial; display: inline-block; margin: 0px auto; text-align: center;}h1{ color: #070812; padding: 2vh;}.button { display: inline-block; background-color: #b30000; //red color border: none; border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}.button2 { background-color: #364cf4; //blue color}.content { padding: 50px;}.card-grid { max-width: 800px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));}.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);}.card-title { font-size: 1.2rem; font-weight: bold; color: #034078}</style> <title>ESP32 WEB SERVER</title> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> <link rel=\"icon\" href=\"data:,\"> <link rel=\"stylesheet\" href=\"https://use.fontawesome.com/releases/v5.7.2/css/all.css\" integrity=\"sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr\" crossorigin=\"anonymous\"> <link rel=\"stylesheet\" type=\"text/css\" ></head><body> <h2>ESP32 WEB SERVER</h2> <div class=\"content\"> <div class=\"card-grid\"> <div class=\"card\"> <p><i class=\"fas fa-lightbulb fa-2x\" style=\"color:#c81919;\"></i> <strong>GPIO2</strong></p> <p>GPIO state: <strong> ON</strong></p> <p> <a href=\"/led2on\"><button class=\"button\">ON</button></a> <a href=\"/led2off\"><button class=\"button button2\">OFF</button></a> </p> </div> </div> </div></body></html>"; char off_resp[] = "<!DOCTYPE html><html><head><style type=\"text/css\">html { font-family: Arial; display: inline-block; margin: 0px auto; text-align: center;}h1{ color: #070812; padding: 2vh;}.button { display: inline-block; background-color: #b30000; //red color border: none; border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}.button2 { background-color: #364cf4; //blue color}.content { padding: 50px;}.card-grid { max-width: 800px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));}.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);}.card-title { font-size: 1.2rem; font-weight: bold; color: #034078}</style> <title>ESP32 WEB SERVER</title> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> <link rel=\"icon\" href=\"data:,\"> <link rel=\"stylesheet\" href=\"https://use.fontawesome.com/releases/v5.7.2/css/all.css\" integrity=\"sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr\" crossorigin=\"anonymous\"> <link rel=\"stylesheet\" type=\"text/css\"></head><body> <h2>ESP32 WEB SERVER</h2> <div class=\"content\"> <div class=\"card-grid\"> <div class=\"card\"> <p><i class=\"fas fa-lightbulb fa-2x\" style=\"color:#c81919;\"></i> <strong>GPIO2</strong></p> <p>GPIO state: <strong> OFF</strong></p> <p> <a href=\"/led2on\"><button class=\"button\">ON</button></a> <a href=\"/led2off\"><button class=\"button button2\">OFF</button></a> </p> </div> </div> </div></body></html>"; static const char *TAG = "espressif"; // TAG for debug int led_state = 0; #define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID #define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD #define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY /* FreeRTOS event group to signal when we are connected*/ static EventGroupHandle_t s_wifi_event_group; /* The event group allows multiple bits for each event, but we only care about two events: * - we are connected to the AP with an IP * - we failed to connect after the maximum amount of retries */ #define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 static int s_retry_num = 0; static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { esp_wifi_connect(); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { esp_wifi_connect(); s_retry_num++; ESP_LOGI(TAG, "retry to connect to the AP"); } else { xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); } ESP_LOGI(TAG, "connect to the AP fail"); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } } void connect_wifi(void) { s_wifi_event_group = xEventGroupCreate(); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); esp_event_handler_instance_t instance_any_id; esp_event_handler_instance_t instance_got_ip; ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip)); wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS, /* Setting a password implies station will connect to all security modes including WEP/WPA. * However these modes are deprecated and not advisable to be used. Incase your Access point * doesn't support WPA2, these mode can be enabled by commenting below line */ .threshold.authmode = WIFI_AUTH_WPA2_PSK, }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); ESP_LOGI(TAG, "wifi_init_sta finished."); /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY); /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually * happened. */ if (bits & WIFI_CONNECTED_BIT) { ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } else if (bits & WIFI_FAIL_BIT) { ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); } vEventGroupDelete(s_wifi_event_group); } esp_err_t send_web_page(httpd_req_t *req) { int response; if (led_state == 0) response = httpd_resp_send(req, off_resp, HTTPD_RESP_USE_STRLEN); else response = httpd_resp_send(req, on_resp, HTTPD_RESP_USE_STRLEN); return response; } esp_err_t get_req_handler(httpd_req_t *req) { return send_web_page(req); } esp_err_t led_on_handler(httpd_req_t *req) { gpio_set_level(LED_PIN, 1); led_state = 1; return send_web_page(req); } esp_err_t led_off_handler(httpd_req_t *req) { gpio_set_level(LED_PIN, 0); led_state = 0; return send_web_page(req); } httpd_uri_t uri_get = { .uri = "/", .method = HTTP_GET, .handler = get_req_handler, .user_ctx = NULL}; httpd_uri_t uri_on = { .uri = "/led2on", .method = HTTP_GET, .handler = led_on_handler, .user_ctx = NULL}; httpd_uri_t uri_off = { .uri = "/led2off", .method = HTTP_GET, .handler = led_off_handler, .user_ctx = NULL}; httpd_handle_t setup_server(void) { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); httpd_handle_t server = NULL; if (httpd_start(&server, &config) == ESP_OK) { httpd_register_uri_handler(server, &uri_get); httpd_register_uri_handler(server, &uri_on); httpd_register_uri_handler(server, &uri_off); } return server; } void app_main() { // Initialize NVS esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); connect_wifi(); // GPIO initialization gpio_pad_select_gpio(LED_PIN); gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT); led_state = 0; ESP_LOGI(TAG, "LED Control Web Server is running ... ...\n"); setup_server(); } |
Как работает код?
Для начала мы подключим необходимые библиотеки, включая библиотеки FreeRTOS для генерации задержек, создания задач и групп событий. Это esp_http_server.h для настройки HTTP-веб-сервера, esp_wifi.h для включения Wi-Fi-соединения, esp_event.h для мониторинга событий Wi-Fi, esp_log.h в качестве библиотеки для логирования, библиотека driver/gpio.h для управления цифровыми выходными контактами ESP32 и т.д.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <stdio.h> #include <stdlib.h> #include <string.h> //Requires by memset #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" #include "esp_spi_flash.h" #include <esp_http_server.h> #include "esp_wifi.h" #include "esp_event.h" #include "freertos/event_groups.h" #include "esp_log.h" #include "nvs_flash.h" #include "esp_netif.h" #include "driver/gpio.h" #include <lwip/sockets.h> #include <lwip/sys.h> #include <lwip/api.h> #include <lwip/netdb.h> |
Встроенный светодиод ESP32 подключен к выводу GPIO2. Поэтому мы определим переменную с именем 'LED_PIN', которая будет хранить значение GPIO2. Она будет использоваться позже в коде для управления светодиодом.
|
1 |
#define LED_PIN 2 |
HTML и CSS для создания веб-сервера
Затем у нас есть массив, содержащий HTML и CSS скрипт для ответа на включение. Он включает в себя заголовок веб-сервера, иконку лампочки вместе с управляемым GPIO, абзац, описывающий состояние GPIO, и две кнопки (ВКЛ и ВЫКЛ).
|
1 |
char on_resp[] = "<!DOCTYPE html><html><head><style type=\"text/css\">html { font-family: Arial; display: inline-block; margin: 0px auto; text-align: center;}h1{ color: #070812; padding: 2vh;}.button { display: inline-block; background-color: #b30000; //red color border: none; border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}.button2 { background-color: #364cf4; //blue color}.content { padding: 50px;}.card-grid { max-width: 800px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));}.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);}.card-title { font-size: 1.2rem; font-weight: bold; color: #034078}</style> <title>ESP32 WEB SERVER</title> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> <link rel=\"icon\" href=\"data:,\"> <link rel=\"stylesheet\" href=\"https://use.fontawesome.com/releases/v5.7.2/css/all.css\" integrity=\"sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr\" crossorigin=\"anonymous\"> <link rel=\"stylesheet\" type=\"text/css\" ></head><body> <h2>ESP32 WEB SERVER</h2> <div class=\"content\"> <div class=\"card-grid\"> <div class=\"card\"> <p><i class=\"fas fa-lightbulb fa-2x\" style=\"color:#c81919;\"></i> <strong>GPIO2</strong></p> <p>GPIO state: <strong> ON</strong></p> <p> <a href=\"/led2on\"><button class=\"button\">ON</button></a> <a href=\"/led2off\"><button class=\"button button2\">OFF</button></a> </p> </div> </div> </div></body></html>"; |
HTML-код задаётся внутри тегов <html></html>. Внутри тегов <style></style> задаётся стиль веб-страницы. Это включает в себя семейство шрифтов, размер шрифта, позиционирование текста, размер и цвет кнопок и т.д.
Как вы могли заметить, весь текст набран шрифтом Arial и выровнен по центру веб-страницы. Цвет и отступы заголовка h1 также заданы. На нашей веб-странице две кнопки. Одна — кнопка «ВКЛ», а вторая — кнопка «ВЫКЛ». Обе кнопки имеют разные цвета, но остальное оформление одинаково, включая радиус скругления углов, цвет текста, отступы, курсор и т. д. Кроме того, карточка содержит состояние GPIO, кнопки и значок лампочки. Мы задаем размер и цвет заголовка карточки, а также общее оформление карточки, включая цвет фона, тень и т. д.
|
1 |
<style type=\"text/css\">html { font-family: Arial; display: inline-block; margin: 0px auto; text-align: center;}h1{ color: #070812; padding: 2vh;}.button { display: inline-block; background-color: #b30000; //red color border: none; border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}.button2 { background-color: #364cf4; //blue color}.content { padding: 50px;}.card-grid { max-width: 800px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));}.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);}.card-title { font-size: 1.2rem; font-weight: bold; color: #034078}</style> |
После этого мы указываем заголовок веб-страницы. Он размещается внутри тегов <title> </title>. В нашем случае мы установили заголовок веб-страницы как «ESP32 WEB SERVER». Он будет отображаться в строке заголовка браузера.
|
1 |
<title>ESP32 WEB SERVER</title> |
Следующий метатег позволит отображать наш веб-сервер на разных устройствах.
|
1 |
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> |
Как мы уже упоминали, мы хотим добавить на нашу веб-страницу иконку лампочки. Поэтому следующий тег ссылки получит иконку из FontAwesome .
|
1 |
<link rel=\"icon\" href=\"data:,\"> <link rel=\"stylesheet\" href=\"https://use.fontawesome.com/releases/v5.7.2/css/all.css\" integrity=\"sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr\" crossorigin=\"anonymous\"> |
Внутри тегов <body> </body> будут размещены заголовок, абзацы и кнопки.
|
1 |
<body> <h2>ESP32 WEB SERVER</h2> <div class=\"content\"> <div class=\"card-grid\"> <div class=\"card\"> <p><i class=\"fas fa-lightbulb fa-2x\" style=\"color:#c81919;\"></i> <strong>GPIO2</strong></p> <p>GPIO state: <strong> ON</strong></p> <p> <a href=\"/led2on\"><button class=\"button\">ON</button></a> <a href=\"/led2off\"><button class=\"button button2\">OFF</button></a> </p> </div> </div> </div></body> |
Заголовок нашего веб-сервера — «ESP32 WEB SERVER», он размещен внутри тегов <h2></h2>.
|
1 |
<h2>ESP32 WEB SERVER</h2> |
После заголовка следует абзац, в котором отображается значок лампы и контакт GPIO2, которым мы управляем.
|
1 |
<p><i class=\"fas fa-lightbulb fa-2x\" style=\"color:#c81919;\"></i> <strong>GPIO2</strong></p> |
Для создания шрифта мы будем использовать сайт Fontawesome. Иконка лампы взята с этого сайта. Давайте покажем, как это сделать. Сначала откройте сайт Fontawesome. Теперь введите ‘light’, как показано ниже, и нажмите Enter.
В зависимости от результатов поиска будут отображаться различные значки. Щелкните по тому, который хотите добавить. Ссылка появится в окне.
Этот код будет использоваться внутри нашего HTML-скрипта, как показано ниже:
|
1 |
<p><i class=\"fas fa-lightbulb fa-2x\" style=\"color:#c81919;\"></i> <strong>GPIO2</strong></p> |
Во втором абзаце будет отображено состояние GPIO, которое в данном случае равно «ВКЛ».
|
1 |
<p>GPIO state: <strong> ON</strong></p> |
Наконец, у нас есть абзац, описывающий две кнопки. Первая кнопка отображает текст «ВКЛ» и при нажатии перенаправляет на веб-страницу по адресу /led2on. Вторая кнопка отображает текст «ВЫКЛ» и перенаправляет на веб-страницу по адресу /led2off.
|
1 |
<p> <a href=\"/led2on\"><button class=\"button\">ON</button></a><a href=\"/led2off\"><button class=\"button button2\">OFF</button></a> </p> |
Затем у нас есть массив, содержащий HTML и CSS скрипт для ответа «ВЫКЛ». Он похож на массив ответа «ВКЛ», определенный ранее, однако на этот раз в абзаце, отображающем состояние GPIO, будет указано «ВЫКЛ».
|
1 |
char off_resp[] = "<!DOCTYPE html><html><head><style type=\"text/css\">html { font-family: Arial; display: inline-block; margin: 0px auto; text-align: center;}h1{ color: #070812; padding: 2vh;}.button { display: inline-block; background-color: #b30000; //red color border: none; border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}.button2 { background-color: #364cf4; //blue color}.content { padding: 50px;}.card-grid { max-width: 800px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));}.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);}.card-title { font-size: 1.2rem; font-weight: bold; color: #034078}</style> <title>ESP32 WEB SERVER</title> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> <link rel=\"icon\" href=\"data:,\"> <link rel=\"stylesheet\" href=\"https://use.fontawesome.com/releases/v5.7.2/css/all.css\" integrity=\"sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr\" crossorigin=\"anonymous\"> <link rel=\"stylesheet\" type=\"text/css\"></head><body> <h2>ESP32 WEB SERVER</h2> <div class=\"content\"> <div class=\"card-grid\"> <div class=\"card\"> <p><i class=\"fas fa-lightbulb fa-2x\" style=\"color:#c81919;\"></i> <strong>GPIO2</strong></p> <p>GPIO state: <strong> OFF</strong></p> <p> <a href=\"/led2on\"><button class=\"button\">ON</button></a> <a href=\"/led2off\"><button class=\"button button2\">OFF</button></a> </p> </div> </div> </div></body></html>"; |
Этот код использует информационное логирование. Функция логирования принимает два аргумента. Первый аргумент — это тег, а второй — отформатированная строка. Поэтому эта глобальная переменная будет полезна при вызове функций ESP_LOGI(). Здесь «espressif» — это тег, который будет использоваться при логировании.
|
1 2 |
static const char *TAG = "espressif"; // TAG for debug int led_state = 0; |
Кроме того, целочисленная переменная 'led_state' хранит текущее состояние светодиода. Изначально она имеет значение 0.
|
1 |
int led_state = 0; |
Далее мы определили параметры конфигурации, которые задали в menuconfig. Если вы уже определили эти параметры в конфигурации проекта, то нет необходимости жестко прописывать значения здесь. Однако, если вы хотите определить эти параметры в файле main.c, то укажите их в двойных кавычках. Например: #define EXAMPLE_ESP_WIFI_SSID “YOUR_SSID”
|
1 2 3 |
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID #define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD #define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY |
Подключение через Wi-Fi
Далее мы объявляем переменную 's_wifi-event_group' для хранения созданной группы событий FreeRTOS. Эта группа событий FreeRTOS используется для оповещения о подключении к Wi-Fi.
|
1 |
static EventGroupHandle_t s_wifi_event_group; |
Затем мы определяем два бита для важных для нас событий Wi-Fi. К ним относятся бит, обозначающий успешное подключение к точке доступа Wi-Fi, и бит, обозначающий неудачное подключение к точке доступа Wi-Fi после истечения максимального количества попыток.
|
1 2 |
#define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 |
event_handler()
Затем у нас есть функция event_handler(), которая обрабатывает события Wi-Fi. Она выступает в качестве функции обратного вызова при возникновении события Wi-Fi или события IP.
Событие IP происходит, когда плата ESP32 подключается к нашей точке доступа, и маршрутизатор назначает ей IP-адрес. События IP могут быть одного из следующих типов. Но здесь мы используем только IP_EVENT_STA_GOT_IP.
|
1 2 3 4 5 6 7 8 9 10 11 |
/** IP event declarations */ typedef enum { IP_EVENT_STA_GOT_IP, /*!< station got IP from connected AP */ IP_EVENT_STA_LOST_IP, /*!< station lost IP and the IP is reset to 0 */ IP_EVENT_AP_STAIPASSIGNED, /*!< soft-AP assign an IP to a connected station */ IP_EVENT_GOT_IP6, /*!< station or ap or ethernet interface v6IP addr is preferred */ IP_EVENT_ETH_GOT_IP, /*!< ethernet got IP from connected AP */ IP_EVENT_ETH_LOST_IP, /*!< ethernet lost IP and the IP is reset to 0 */ IP_EVENT_PPP_GOT_IP, /*!< PPP interface got IP */ IP_EVENT_PPP_LOST_IP, /*!< PPP interface lost IP */ } ip_event_t; |
Во-первых, когда происходят события Wi-Fi (WIFI_EVENT и WIFI_EVENT_STA_START), мы подключаем ESP32 к точке доступа. Для этого мы используем функцию esp_wifi_connect().
Если плата ESP32 не может подключиться к точке доступа в течение установленного максимального количества попыток, она снова пытается подключиться к точке доступа и регистрирует сообщение «повторная попытка подключения к точке доступа». Однако, если ESP32 не может установить соединение с точкой доступа после истечения максимального количества попыток, она регистрирует сообщение «сбой подключения к точке доступа» и устанавливает бит WIFI_FAIL_BIT. Теперь, если плата ESP32 успешно подключается к точке доступа, это означает, что произошли оба события IP (IP_EVENT и IP_EVENT_STA_GOT_IP). В этом случае она выводит IP-адрес в качестве результата. Кроме того, она также устанавливает бит WIFI_CONNECTED_BIT.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { esp_wifi_connect(); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { esp_wifi_connect(); s_retry_num++; ESP_LOGI(TAG, "retry to connect to the AP"); } else { xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); } ESP_LOGI(TAG, "connect to the AP fail"); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } } |
connect_wifi()
Функция connect_wifi() будет вызываться внутри функции app_main() для инициализации Wi-Fi в режиме станции для ESP32.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
void connect_wifi(void) { s_wifi_event_group = xEventGroupCreate(); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); esp_event_handler_instance_t instance_any_id; esp_event_handler_instance_t instance_got_ip; ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip)); wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS, /* Setting a password implies station will connect to all security modes including WEP/WPA. * However these modes are deprecated and not advisable to be used. Incase your Access point * doesn't support WPA2, these mode can be enabled by commenting below line */ .threshold.authmode = WIFI_AUTH_WPA2_PSK, }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); ESP_LOGI(TAG, "wifi_init_sta finished."); /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY); /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually * happened. */ if (bits & WIFI_CONNECTED_BIT) { ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } else if (bits & WIFI_FAIL_BIT) { ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); } vEventGroupDelete(s_wifi_event_group); } |
Для начала создадим группу событий FreeRTOS для мониторинга соединения. Эта функция возвращает дескриптор группы событий.
|
1 |
s_wifi_event_group = xEventGroupCreate(); |
ESP-IDF предоставляет полезный макрос ESP_ERROR_CHECK(), который используется для проверки наличия или отсутствия ошибки. Если функция, переданная в него, не возвращает ESP_OK, то мы проверяем наличие ошибки и записываем её в лог.
Здесь мы инициализируем lwIP с помощью функции esp_netif_init() и создаём задачу IwIP, также известную как задача TCP/IP. lwIP — это стек библиотек TCP/IP, предоставляемый ESP-IDF, который используется для выполнения различных протоколов, таких как TCP, UDP, DHCP и т. д.
|
1 |
ESP_ERROR_CHECK(esp_netif_init()); |
Далее мы создаём цикл обработки событий по умолчанию, который позволяет отправлять системные события в задачу обработки событий.
|
1 |
ESP_ERROR_CHECK(esp_event_loop_create_default()); |
Кроме того, следующая строка используется для инициализации Wi-Fi по умолчанию в режиме станции. Этот API используется для инициализации, а также регистрации обработчиков событий для интерфейса по умолчанию, которым в нашем случае является станция. Он создает экземпляр сетевого интерфейса, связывающий драйвер Wi-Fi и стек TCP/IP. Когда станция находится в процессе подключения к точке доступа, различные процессы автоматически обрабатываются с помощью этой функции.
|
1 |
esp_netif_create_default_wifi_sta(); |
Затем мы инициализируем ресурс выделения Wi-Fi для драйвера Wi-Fi. Он отвечает за запуск задачи Wi-Fi. Он принимает единственный параметр cfg, который является указателем на уже инициализированную структуру конфигурации Wi-Fi, установленную в значение WIFI_INIT_CONFIG_DEFAULT(), так что инициализация конфигурации происходит со значениями по умолчанию. Здесь wifi_init_config_t — это структура, обозначающая параметры конфигурации стека Wi-Fi, которые передаются в функцию esp_wifi_init().
|
1 2 |
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); |
Далее мы создаём два обработчика событий: один с именем 'instance_any_id' для всех событий Wi-Fi, а другой с именем 'instance_any_ip' — для событий, когда станция получает IP-адрес.
|
1 2 |
esp_event_handler_instance_t instance_any_id; esp_event_handler_instance_t instance_got_ip; |
Далее, у нас есть два регистра для экземпляров обработчика событий, которые мы настроили. Таким образом, задача приложения может зарегистрироваться для обратного вызова, который будет прослушивать события для Wi-Fi и TCP/IP. Первое событие — «ESP_EVENT_ANY_ID», а второе — «IP_EVENT_STA_GOT_IP». Следовательно, она будет прослушивать все события Wi-Fi (ESP_EVENT_ANY_ID) и событие IP, когда станция получит свой IP-адрес (IP_EVENT_STA_GOT_IP). Таким образом, функция обратного вызова event_handler будет вызвана, если произойдет любое из этих двух событий.
|
1 2 3 4 5 6 7 8 9 10 |
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip)); |
Другие события Wi-Fi, которые мы можем использовать в нашем коде, включают:
|
1 2 3 4 5 6 |
typedef enum { WIFI_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */ WIFI_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */ WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */ WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ } mdns_used_event_t; |
В этой части мы задаём SSID и пароль сети, к которой хотим подключить наш ESP32, а также назначаем параметры безопасности.
|
1 2 3 4 5 6 7 |
wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS, .threshold.authmode = WIFI_AUTH_WPA2_PSK, }, }; |
Кроме того, мы устанавливаем режим Wi-Fi как «станция». Для этого мы используем функцию esp_wifi_set_mode() и передаем в качестве параметра параметр WiFI_MODE_STA.
|
1 |
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); |
Затем мы назначаем SSID и пароль нашей сети. Таким образом, драйвер Wi-Fi настраивается с использованием учетных данных сети точки доступа и режима Wi-Fi. После этого мы запускаем Wi-Fi-соединение с заданными параметрами.
|
1 2 |
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); ESP_ERROR_CHECK(esp_wifi_start() ); |
На этом этапе в журнале информации появляется сообщение «wifi_init_sta finished». Процесс инициализации Wi-Fi в режиме станции завершен.
|
1 |
ESP_LOGI(TAG, "wifi_init_sta finished."); |
Далее приложение переходит в заблокированное состояние, ожидая установки одного из битов в группе событий. Это происходит после инициализации и запуска Wi-Fi. Приложение остается в заблокированном состоянии до тех пор, пока не будет установлено соединение Wi-Fi (контролируется битом WIFI_CONNECTED_BIT) или пока соединение Wi-Fi не будет разорвано в течение максимального количества попыток (контролируется битом WIFI_FAIL_BIT).
Если функция event_handler() устанавливает значение WIFI_CONNECTED_BIT, указывающее на успешное подключение ESP32 к точке доступа, то в информационном журнале будет указано, что соединение установлено с SSID и паролем указанной точки доступа. Если же функция event_handler() устанавливает значение WIFI_FAIL_BIT, указывающее на невозможность подключения ESP32 к точке доступа даже после достижения максимального количества попыток, то в информационном журнале будет указано, что соединение с SSID и паролем указанной точки доступа не удалось.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY); if (bits & WIFI_CONNECTED_BIT) { ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } else if (bits & WIFI_FAIL_BIT) { ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); } |
Кроме того, мы удаляем группу событий 's_wifi_event_group' с помощью функции vEventGroupDelete(). Она была создана ранее с помощью вызова функции xEventGroupCreate().
|
1 |
vEventGroupDelete(s_wifi_event_group); |
API-интерфейсы esp_http_server.h для размещения веб-сервера на ESP32
Функция send_web_page() отвечает за отправку полного HTTP-ответа путем вызова функции httpd_resp_send(). API httpd_resp_send() принимает три параметра. Первый параметр — это запрос, на который должен быть дан ответ. Второй параметр — это буфер, из которого необходимо получить контекст. Третий параметр — это длина буфера. В функции send_web_page() возвращается HTTP-ответ 'off_resp', если состояние светодиода равно 0. В противном случае возвращается HTTP-ответ 'on_resp'.
|
1 2 3 4 5 6 7 8 9 |
esp_err_t send_web_page(httpd_req_t *req) { int response; if (led_state == 0) response = httpd_resp_send(req, off_resp, HTTPD_RESP_USE_STRLEN); else response = httpd_resp_send(req, on_resp, HTTPD_RESP_USE_STRLEN); return response; } |
Ниже представлена структура обработчика uri-get. Выбранный метод — HTTP_GET, URL — «/», а обработчик — get_req_handler, который возвращает ответ send_web_page().
|
1 2 3 4 5 6 7 8 9 10 |
httpd_uri_t uri_get = { .uri = "/", .method = HTTP_GET, .handler = get_req_handler, .user_ctx = NULL}; esp_err_t get_req_handler(httpd_req_t *req) { return send_web_page(req); } |
У нас есть структура uri_on, показанная ниже. Выбранный метод — HTTP_GET, URL — «/led2on», а обработчик для этого — led_on_handler, который возвращает ответ send_web_page() и устанавливает уровень LED_PIN и 'led_state' в 1.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
httpd_uri_t uri_on = { .uri = "/led2on", .method = HTTP_GET, .handler = led_on_handler, .user_ctx = NULL}; esp_err_t led_on_handler(httpd_req_t *req) { gpio_set_level(LED_PIN, 1); led_state = 1; return send_web_page(req); } |
У нас есть структура uri_off, показанная ниже. Выбранный метод — HTTP_GET, URL — «/led2off», а обработчик для этого — led_off_handler, который возвращает ответ send_web_page() и устанавливает уровень LED_PIN и 'led_state' в 0.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
httpd_uri_t uri_off = { .uri = "/led2off", .method = HTTP_GET, .handler = led_off_handler, .user_ctx = NULL}; esp_err_t led_off_handler(httpd_req_t *req) { gpio_set_level(LED_PIN, 0); led_state = 0; return send_web_page(req); } |
Следующая функция запустит HTTP-веб-сервер и вернет сервер, который будет являться HTTP-дескриптором.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
httpd_handle_t setup_server(void) { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); httpd_handle_t server = NULL; if (httpd_start(&server, &config) == ESP_OK) { httpd_register_uri_handler(server, &uri_get); httpd_register_uri_handler(server, &uri_on); httpd_register_uri_handler(server, &uri_off); } return server; } |
Процесс начинается с определения конфигурации по умолчанию и присваивает пустое значение дескриптору HTTP-сервера. Оно устанавливается как NULL.
Функция httpd_start() запускает HTTP-сервер. Она принимает два параметра: конфигурацию для нового экземпляра сервера и дескриптор этого экземпляра. Если экземпляр был успешно создан, что означает, что функция вернула ESP_OK, то мы регистрируем обработчики URI. Функция принимает два параметра. Первый параметр — это дескриптор экземпляра HTTP-сервера, в данном случае 'server'. Второй параметр — это указатель на обработчик, который мы хотим зарегистрировать. Мы регистрируем три обработчика URI: uri_get, uri_on и uri_off.
app_main()
Внутри функции app_main() сначала инициализируется NVS путем вызова функции nvs_flash_init(). Затем проверяется, не содержит ли раздел NVS пустых страниц или содержит ли он данные в формате, отличном от текущей версии кода. Если выполняется хотя бы одно из этих условий, то с помощью функции nvs_flash_erase() происходит очистка флэш-памяти NVS и повторная инициализация.
|
1 2 3 4 5 6 7 |
esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); |
Затем мы выведем в терминале “ESP_WIFI_MODE_STA” и вызовем функцию connect_wifi() для подключения к Wi-Fi в режиме станции.
|
1 2 |
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); connect_wifi(); |
Следующий шаг — настройка контакта LED_PIN в качестве выхода GPIO. Для этого мы воспользуемся функцией gpio_pad_select_gpio(). Укажите вывод LED_PIN в качестве параметра внутри этой функции. Затем мы установим направление вывода как выходное с помощью функции gpio_set_direction(). Эта функция принимает два аргумента. Первый аргумент — это вывод GPIO, а второй — режим (вход или выход), в котором мы хотим установить вывод. В нашем случае мы хотим установить вывод LED_PIN как выходной вывод.
|
1 2 |
gpio_pad_select_gpio(LED_PIN); gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT); |
Переменная led_state устанавливается в значение 0. В этот момент терминал выводит сообщение «Веб-сервер управления светодиодами запущен… …». Вызывается функция setup_server() для запуска HTTP-веб-сервера.
|
1 2 3 |
led_state = 0; ESP_LOGI(TAG, "LED Control Web Server is running ... ...\n"); setup_server(); |
Компиляция скетча
Для прошивки микросхемы введите следующую команду в последовательном терминале. Не забудьте заменить COM-порт на тот, через который подключена ваша плата.
|
1 |
idf.py -p COMX flash monitor |
После успешной прошивки кода вы можете просмотреть все информационные журналы. Сначала инициализируется Wi-Fi станции. Затем мы можем просмотреть esp_netif_handlers, который включает IP-адрес, маску и адрес шлюза. Затем мы получаем запись «получен IP-адрес», за которой следует сам IP-адрес. Мы будем использовать этот IP-адрес для доступа к веб-серверу.
Откройте новый веб-браузер и введите IP-адрес, полученный в терминале, затем нажмите Enter. Откроется веб-сервер ESP32, на экране которого отобразятся две кнопки для управления GPIO2. Изначально светодиод выключен, что также отображается на веб-сервере.
Теперь нажмите кнопки ВКЛ и ВЫКЛ, и светодиод будет включаться/выключаться соответственно. Аналогичным образом, состояние GPIO2 также будет непрерывно обновляться на веб-сервере.















