Найти в Дзене
Паяльник и код

ESP8266 (ESP32) асинхронный веб-сервер. Версия 2

Рассмотрим программу скелет для микроконтроллера ESP8266 (ESP32), которую в дальнейшем можно будет использовать для своих проектов. Программа выполняет условия: 1. Выбор WiFi сети
2. Подключение к WiFi сети
2. Управление через веб сервер
3. Одновременный доступ с разных устройств
4. Текущее состояние в реальном времени отображается на всех устройствах
5. Проверка подключения к сети Для примера будем включать/отключать встроенный светодиод на плате. Регулировать его яркость с помощью веб страницы Справка находится в первой статье: Поэтому сразу рассмотрим исходный код Подключаем библиотеки #include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h> Для ESP32
//#include <WiFi.h>
//#include <AsyncTCP.h> #include <ESPAsyncWebServer.h> Объявление переменных и констант byte size = 3; //количество сетей к которым будем коннектиться
char * ssid[] = {"net1","net2","net3"}; //сети
char * password[] = {"pas1","pas2","pas3"}; //пароли
byte connect0 = 0; //с какой сетью соединение
byte attempts = 20; // кол
Оглавление

Рассмотрим программу скелет для микроконтроллера ESP8266 (ESP32), которую в дальнейшем можно будет использовать для своих проектов. Программа выполняет условия:

1. Выбор WiFi сети
2. Подключение к WiFi сети
2. Управление через веб сервер
3. Одновременный доступ с разных устройств
4. Текущее состояние в реальном времени отображается на всех устройствах
5. Проверка подключения к сети

Для примера будем включать/отключать встроенный светодиод на плате. Регулировать его яркость

-2

с помощью веб страницы

-3

Справка находится в первой статье:

Поэтому сразу рассмотрим исходный код

Скетч

Подключаем библиотеки

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>

Для ESP32
//#include <WiFi.h>
//#include <AsyncTCP.h>

#include <ESPAsyncWebServer.h>

Объявление переменных и констант

byte size = 3; //количество сетей к которым будем коннектиться
char * ssid[] = {"net1","net2","net3"}; //сети
char * password[] = {"pas1","pas2","pas3"}; //пароли
byte connect0 = 0; //с какой сетью соединение
byte attempts = 20; // количество попыток соединения
int LED = LED_BUILTIN; // пин светодиода
int ledState = HIGH; // статус светодиода
int brightness = 0; // статус яркости от 0 - 255
const char* PARAM_INPUT_1 = "state1"; //
константа для функции update
const char* PARAM_INPUT_2 = "state2";
//константа для функции update
AsyncWebServer server(80); // порт веб сервера

Здесь код HTML страницы, которая будет загружаться при заходе на веб сервер устройства
PROGMEM – записывается на флэш память
в <style> задаем размер чекбокса
%CHECKBOXPLACEHOLDER%, %RANGEPLACEHOLDER% - сюда при заходе
на сервер будут помещаться компоненты с текущим состоянием
toggleCheckbox – функция AJAX для вкл/выкл светодиода
toggleRange - функция AJAX для изменения яркости светодиода
+две функции которые через AJAX будут получать текущие состояние светодиода, и менять параметры на странице, если произошло изменение на другом клиенте одна будет выполняться с интервалом в 1 сек, другая 5 сек

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta charset="UTF-8">
<title>LED_1</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
#output1{
transform:scale(1.3);
opacity:0.9;
cursor:pointer;
}
</style>
</head>
<body>
<p><big>Лампочка1:</big>&nbsp;&nbsp;%CHECKBOXPLACEHOLDER%</p>
<p><big>Яркость:</big>&nbsp;&nbsp;%RANGEPLACEHOLDER%</p>
<script>
function toggleCheckbox(element) {
var xhr = new XMLHttpRequest();
if(element.checked){ xhr.open("GET", "/update?state1=1", true); }
else { xhr.open("GET", "/update?state1=0", true); }
xhr.send();
}
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var inputChecked;
if( this.responseText == 1){
inputChecked = false;
}else {
inputChecked = true;
}
document.getElementById("output1").checked = inputChecked;
}};
xhttp.open("GET", "/state1", true);
xhttp.send();
}, 1000 ) ;
function toggleRange(element) {
var xhr = new XMLHttpRequest();
if(document.getElementById("output1").checked){ xhr.open("GET", "/update?state2="+document.getElementById("output2").value, true); }
xhr.send();
}
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var inputChecked = this.responseText;
document.getElementById("output2").value = inputChecked;
}};
xhttp.open("GET", "/state2", true);
xhttp.send();
}, 5000 ) ;
</script></body></html>
)rawliteral";

Функция берет текущие значения состояния светодиода, и проставляет на страницу загрузки веб сервера

String processor(const String& var){
String buttons ="";
if(var == "CHECKBOXPLACEHOLDER"){
String outputStateValue = outputState1();
buttons+= "<input type=\"checkbox\" onchange=\"toggleCheckbox(this)\"
id=\"output1\" " + outputStateValue + ">";
return buttons;
} else
if(var == "RANGEPLACEHOLDER"){
buttons+= "<input type=\"range\" onchange=\"toggleRange(this)\"
id=\"output2\" min=\"0\" max=\"200\" value=\""+String(brightness)+"\" >";
return buttons;
}
return String();
}

Получить состояние светодиода

String outputState1(){
if(ledState == HIGH){
return "";
}else {
return "checked";
}
return "";
}

Функция поиска доступной сети

boolean scanWIFI(){
Serial.println("");
Serial.println("Scan WiFi");
uint8_t n = WiFi.scanNetworks();
for (uint8_t i = 0; i < n; i++) {
String ssidWiFi = WiFi.SSID(i);
for (uint8_t j = 0; j < size; j++){
String ssidMy = ssid[j];
if (ssidMy == ssidWiFi){
connect0 = j+1;
return true; }}
}
return false;
}

Функция подключения к сети

void WiFiConnect(){
connect0 = 0;
byte attempts_ = attempts;
if (scanWIFI()){
WiFi.begin(ssid[connect0-1],password[connect0-1]);
while(--attempts_ && WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}}
if(WiFi.status() != WL_CONNECTED){
connect0 = 0;
}
if(connect0 == 0){
Serial.println("");
Serial.println("Non Connecting");
} else {
Serial.println("");
Serial.println("Connected");
Serial.print("IP:");
Serial.println(WiFi.localIP());
}}

При загрузке устройства настройка параметров

void setup() {
Serial.begin(115200);
pinMode(LED, OUTPUT);
digitalWrite(LED, ledState);
// первоначальное состояние светодиода
WiFiConnect(); // подключение к сети
//имя нашего проекта, чтобы искать устройство в сети
server.on("/name", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", "LED_1");
});
// формирование главной страницы
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// обновляем значения состояния светодиода. Получаем их от клиента
// PARAM_INPUT_1 – вкл/выкл
// PARAM_INPUT_2 - яркость
server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage;
if (request->hasParam(PARAM_INPUT_1)) {
inputMessage = request->getParam(PARAM_INPUT_1)->value();
digitalWrite(LED, !inputMessage.toInt());
ledState = !ledState;
brightness = 0;
} else
if (request->hasParam(PARAM_INPUT_2)) {
inputMessage = request->getParam(PARAM_INPUT_2)->value();
int brig = inputMessage.toInt();
if(brig<0) brig =0;
if(brig>255) brig =255;
analogWrite(LED,brig);
brightness = brig;
}else {
inputMessage = "No message sent";
}
request->send(200, "text/plain", "OK");
});
// текущие состояние вкл/выкл светодиода
server.on("/state1", HTTP_GET, [] (AsyncWebServerRequest *request) {
if(ledState == HIGH) request->send(200, "text/plain", "1");
else request->send(200, "text/plain", "0");
});
// текущие состояние яркости
server.on("/state2", HTTP_GET, [] (AsyncWebServerRequest *request) {
request->send(200, "text/plain", String(brightness).c_str());
});
//запуск сервера
server.begin();
}

Проверяем состояние подключения. В случаи разрыва, пытаемся снова подключиться

unsigned long tim;
int timemil = 10000;
void loop() {
if(millis() - tim > timemil){
tim = millis();
if(WiFi.status() == WL_CONNECTED){
timemil = 60000;
} else {
WiFiConnect();
timemil = 10000;
}
}
}

Главные отличие от предыдущей версии это поиск доступных сетей. Это дает возможность переносить устройство среди своих сетей. Так же добавлена возможность автоматического подключения при разрыве сети. Это проблема была описана в статье https://dzen.ru/a/ZuFmp7IwdWcjSZF3. Теперь будет исправлена на устройстве

Ссылки

Скетч

esp8266_blink_v2.ino