ESP8266 и Arduino IDE. Часть 2: Управление светодиодом в режиме AP
Примечание
Оригинал статьи: martyncurrey.com
Этот урок демонстрирует, как удалённо управлять светодиодом с помощью микроконтроллера ESP8266, настроенного в качестве WiFi точки доступа. Пользователи могут подключиться к сети устройства и использовать веб-интерфейс для включения и выключения светодиода с любого устройства с веб-браузером.
Режим точки доступа (Access Point)
ESP8266 создаёт собственную WiFi-сеть, а не подключается к существующей. IP-адрес по умолчанию — 192.168.4.1, который пользователи вводят в браузере для доступа к интерфейсу управления.
HTTP-запросы
Когда браузер запрашивает веб-страницу, он отправляет HTTP-запросы в виде обычного текста. В уроке объясняется, как разбирать эти запросы вручную, а не используя библиотеку веб-сервера, что помогает начинающим понять протокол связи.
Пример HTTP GET-запроса при нажатии кнопки «LED ON»:
GET /LEDON HTTP/1.1
Host: 192.168.4.1
Использование строк (String)
Хотя традиционная разработка Arduino не рекомендует использовать String из-за ограничений памяти, ESP8266 имеет достаточно памяти для гибкого использования как объектов String, так и массивов char.
Базовая структура веб-страницы
Начальный HTML-интерфейс содержит две простые формы с кнопками:
<!DOCTYPE html>
<html>
<head>
<title>LED Control</title>
</head>
<body>
<div id='main'>
<h2>LED Control</h2>
<form id='F1' action='LEDON'>
<input class='button' type='submit' value='LED ON' >
</form>
<br>
<form id='F2' action='LEDOFF'>
<input class='button' type='submit' value='LED OFF' >
</form>
</div>
</body>
</html>
Каждое нажатие кнопки отправляет различное действие (LEDON или LEDOFF), добавленное к IP-адресу.
Скетч 1: ESP8266_LED_Control_02
Базовая версия с двумя кнопками:
#include <ESP8266WiFi.h>
const char WiFiPassword[] = "12345678";
const char AP_NameChar[] = "LEDControl" ;
WiFiServer server(80);
String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
String html_1 = "<!DOCTYPE html><html><head><title>LED Control</title></head><body><div id='main'><h2>LED Control</h2>";
String html_2 = "<form id='F1' action='LEDON'><input class='button' type='submit' value='LED ON' ></form><br>";
String html_3 = "<form id='F2' action='LEDOFF'><input class='button' type='submit' value='LED OFF' ></form><br>";
String html_4 = "</div></body></html>";
String request = "";
int LED_Pin = D1;
void setup()
{
pinMode(LED_Pin, OUTPUT);
boolean conn = WiFi.softAP(AP_NameChar, WiFiPassword);
server.begin();
} // void setup()
void loop()
{
// Check if a client has connected
WiFiClient client = server.available();
if (!client) { return; }
// Read the first line of the request
request = client.readStringUntil('\r');
if ( request.indexOf("LEDON") > 0 ) { digitalWrite(LED_Pin, HIGH); }
else if ( request.indexOf("LEDOFF") > 0 ) { digitalWrite(LED_Pin, LOW); }
client.flush();
client.print( header );
client.print( html_1 );
client.print( html_2 );
client.print( html_3 );
client.print( html_4);
delay(5);
} // void loop()
Адаптация для мобильных устройств
Добавление мета-тегов viewport обеспечивает правильное отображение на мобильных устройствах:
<meta name='viewport' content='width=device-width, initial-scale=1.0'/>
<meta charset='utf-8'>
CSS-стилизация
body {font-size:140%;}
#main {display: table; margin: auto; padding: 0 10px 0 10px;}
h2 {text-align:center;}
.button {padding:10px 10px 10px 10px; width:100%; background-color: #4CAF50; font-size: 120%;}
Эти стили увеличивают текст, центрируют контент и стилизуют кнопки с зелёным фоном.
Скетч 2: ESP8266_LED_Control_02B — со статусом
Эта версия проверяет состояние пина светодиода и добавляет текстовое сообщение о статусе:
#include <ESP8266WiFi.h>
const char WiFiPassword[] = "12345678";
const char AP_NameChar[] = "LEDControl" ;
WiFiServer server(80);
String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
String html_1 = "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width, initial-scale=1.0'/><meta charset='utf-8'><style>body {font-size:140%;} #main {display: table; margin: auto; padding: 0 10px 0 10px; } h2,{text-align:center; } .button { padding:10px 10px 10px 10px; width:100%; background-color: #4CAF50; font-size: 120%;}</style><title>LED Control</title></head><body><div id='main'><h2>LED Control</h2>";
String html_LED = "";
String html_2 = "<form id='F1' action='LEDON'><input class='button' type='submit' value='LED ON' ></form><br>";
String html_3 = "<form id='F2' action='LEDOFF'><input class='button' type='submit' value='LED OFF' ></form><br>";
String html_4 = "</div></body></html>";
String request = "";
int LED_Pin = D1;
void setup()
{
pinMode(LED_Pin, OUTPUT);
boolean conn = WiFi.softAP(AP_NameChar, WiFiPassword);
server.begin();
} // void setup()
void loop()
{
// Check if a client has connected
WiFiClient client = server.available();
if (!client) { return; }
// Read the first line of the request
request = client.readStringUntil('\r');
if ( request.indexOf("LEDON") > 0 ) { digitalWrite(LED_Pin, HIGH); }
else if ( request.indexOf("LEDOFF") > 0 ) { digitalWrite(LED_Pin, LOW); }
// Get the LED pin status and create the LED status message
if (digitalRead(LED_Pin) == HIGH) { html_LED = "The LED is on<br><br>"; }
else { html_LED = "The LED is off<br><br>"; }
client.flush();
client.print( header );
client.print( html_1 );
client.print( html_LED );
client.print( html_2 );
client.print( html_3 );
client.print( html_4);
delay(5);
} // void loop()
Скетч 3: ESP8266_LED_Control_02C — динамическая кнопка
Финальная версия проверяет состояние пина и динамически обновляет интерфейс:
#include <ESP8266WiFi.h>
const char WiFiPassword[] = "12345678";
const char AP_NameChar[] = "LEDControl" ;
WiFiServer server(80);
String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
String html_1 = "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width, initial-scale=1.0'/><meta charset='utf-8'><style>body {font-size:140%;} #main {display: table; margin: auto; padding: 0 10px 0 10px; } h2,{text-align:center; } .button { padding:10px 10px 10px 10px; width:100%; background-color: #4CAF50; font-size: 120%;}</style><title>LED Control</title></head><body><div id='main'><h2>LED Control</h2>";
String html_2 = "";
String html_4 = "</div></body></html>";
String request = "";
int LED_Pin = D1;
void setup()
{
pinMode(LED_Pin, OUTPUT);
boolean conn = WiFi.softAP(AP_NameChar, WiFiPassword);
server.begin();
} // void setup()
void loop()
{
// Check if a client has connected
WiFiClient client = server.available();
if (!client) { return; }
// Read the first line of the request
request = client.readStringUntil('\r');
if ( request.indexOf("LEDON") > 0 ) { digitalWrite(LED_Pin, HIGH); }
else if ( request.indexOf("LEDOFF") > 0 ) { digitalWrite(LED_Pin, LOW); }
// Get the LED pin status and create the LED status message
if (digitalRead(LED_Pin) == HIGH)
{
// the LED is on so the button needs to say turn it off
html_2 = "<form id='F1' action='LEDOFF'><input class='button' type='submit' value='Turn of the LED' ></form><br>";
}
else
{
// the LED is off so the button needs to say turn it on
html_2 = "<form id='F1' action='LEDON'><input class='button' type='submit' value='Turn on the LED' ></form><br>";
}
client.flush();
client.print( header );
client.print( html_1 );
client.print( html_2 );
client.print( html_4);
delay(5);
} // void loop()
Это создаёт одну кнопку, которая меняет текст и действие в зависимости от текущего состояния светодиода, улучшая пользовательский опыт.