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-адресу.

Веб-сервер ESP8266

Скетч 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%;}

Эти стили увеличивают текст, центрируют контент и стилизуют кнопки с зелёным фоном.

Мобильная версия - LED OFF Мобильная версия - LED ON

Скетч 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()

Это создаёт одну кнопку, которая меняет текст и действие в зависимости от текущего состояния светодиода, улучшая пользовательский опыт.

Динамическая кнопка управления