ESP8266 и Arduino IDE. Часть 6: JavaScript и AJAX

Примечание

Оригинал статьи: martyncurrey.com

Этот урок демонстрирует, как управлять светодиодом через веб-интерфейс с использованием AJAX и JavaScript, устраняя необходимость полной перезагрузки страницы.

Веб-страница работает хорошо, но перезагружается целиком для обновления кнопки, а управление одним светодиодом — не самое впечатляющее применение.

Начальный интерфейс

Схема

Используется светодиод, подключённый к пину D1 ESP8266, с добавленным переключателем сброса для удобства разработки.

Схема подключения

Скетч 1: ESP8266_LED_CONTROL_AJAX_01

Скетч использует raw string literals (синтаксис R"=====(...)=====") для встраивания HTML, что делает код более читабельным и предотвращает проблемы компилятора со специальными символами.

/*
 * Sketch: ESP8266_LED_CONTROL_AJAX_01
 * Intended to be run on an ESP8266
 */

String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";

String html_1 = R"=====(
<!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: #50FF50; font-size: 120%;}
 </style>

 <title>LED Control</title>
</head>
<body>
 <div id='main'>
  <h2>LED Control</h2>
)=====";

String html_2 = "";

String html_4 = R"=====(
  </div>
 </body>
</html>
)=====";


#include <ESP8266WiFi.h>

char ssid[] = "NetworkName";
char pass[] = "password";

WiFiServer server(80);

String request = "";
int LED_Pin = D1;


void setup()
{
    pinMode(LED_Pin, OUTPUT);

    Serial.begin(115200);
    Serial.println();
    Serial.println("Serial started at 115200");
    Serial.println("ESP8266_LED_CONTROL_AJAX_01");
    Serial.println();

    Serial.print(F("Connecting to "));  Serial.println(ssid);
    WiFi.begin(ssid, pass);

    while (WiFi.status() != WL_CONNECTED)
    {
        Serial.print(".");
        delay(500);
    }

    Serial.println("");
    Serial.println(F("[CONNECTED]"));
    Serial.print("[IP ");
    Serial.print(WiFi.localIP());
    Serial.println("]");

    server.begin();
    Serial.println("Server started");

}



void loop()
{
    WiFiClient client = server.available();
    if (!client)  {  return;  }

    request = client.readStringUntil('\r');

    Serial.print("request: "); Serial.println(request);

    if       ( request.indexOf("LEDON") > 0 )  { digitalWrite(LED_Pin, HIGH);  }
    else if  ( request.indexOf("LEDOFF") > 0 ) { digitalWrite(LED_Pin, LOW);   }

    if (digitalRead(LED_Pin) == HIGH)
    {
       html_2 = "  <form id='F1' action='LEDOFF'><input class='button' type='submit' value='Turn of the LED' ></form><br>\r\n";
    }
    else
    {
        html_2 = "  <form id='F1' action='LEDON'><input class='button' type='submit' value='Turn on the LED' ></form><br>\r\n";
    }

    client.flush();

    client.print( header );
    client.print( html_1 );
    client.print( html_2 );
    client.print( html_4);

    delay(5);

}
Интерфейс AJAX_01

Реализация AJAX

AJAX использует JavaScript и представляет собой способ для веб-сайтов получать данные без загрузки всей страницы.

Функция переключения LED

function switchLED()
{
     var button_text = document.getElementById("LED_button").value;
   if (button_text=="Turn on the LED")
   {
     document.getElementById("LED_button").value = "Turn off the LED";
     ajaxLoad('LEDON');
   }
   else
   {
     document.getElementById("LED_button").value = "Turn on the LED";
     ajaxLoad('LEDOFF');
   }
}

Создание объекта AJAX-запроса

var ajaxRequest = null;
if (window.XMLHttpRequest)  { ajaxRequest =new XMLHttpRequest(); }
else                        { ajaxRequest =new ActiveXObject("Microsoft.XMLHTTP"); }

Функция AJAX-загрузки

function ajaxLoad(ajaxURL)
{
  if(!ajaxRequest){ alert("AJAX is not supported."); return; }

  ajaxRequest.open("GET",ajaxURL,true);
  ajaxRequest.onreadystatechange = function()
  {
    if(ajaxRequest.readyState == 4 && ajaxRequest.status==200)
    {
      var ajaxResult = ajaxRequest.responseText;
    }
  }
  ajaxRequest.send();
}

Код проверяет readyState === 4 (запрос завершён) и status === 200 (успешный ответ). Использование true в ajaxRequest.open() включает асинхронные запросы, предотвращая блокировку браузера.

Интерфейс AJAX_02 Детали AJAX

Примечание

Firefox на Android повторяет AJAX-запросы до 10 раз за один клик, поэтому для тестирования рекомендуются другие браузеры.

Скетч 3: ESP8266_LED_CONTROL_AJAX_03 — с подтверждением

Эта версия добавляет обратную связь от сервера. Когда данные получены, JavaScript обновляет текст кнопки и отображает ответ сервера на странице.

Обработчик ответа сервера:

function ajaxLoad(ajaxURL)
{
  if(!ajaxRequest){ alert("AJAX is not supported."); return; }

  ajaxRequest.open("GET",ajaxURL,true);
  ajaxRequest.onreadystatechange = function()
  {
    if(ajaxRequest.readyState == 4 && ajaxRequest.status==200)
    {
      var ajaxResult = ajaxRequest.responseText;
      if ( ajaxResult == "LED is on" ) {
        document.getElementById("LED_button").value = "Turn off the LED";
      }
      else if ( ajaxResult == "LED is off" ) {
        document.getElementById("LED_button").value = "Turn on the LED";
      }
      document.getElementById("reply").textContent = ajaxResult;
    }
  }
  ajaxRequest.send();
}

Серверная часть — ответ ESP8266:

if ( request.indexOf("LEDON") > 0 )
{
    digitalWrite(LED_Pin, HIGH);
    client.print( header );
    client.print( "LED is on" );
}
else if ( request.indexOf("LEDOFF") > 0 )
{
    digitalWrite(LED_Pin, LOW);
    client.print( header );
    client.print( "LED is off" );
}
AJAX с подтверждением

Процесс работы версии с подтверждением

  1. Нажатие кнопки переводит состояние в «Turning on/off»

  2. AJAX-запрос отправляется (LEDON или LEDOFF)

  3. ESP8266 обрабатывает запрос и переключает светодиод

  4. Сервер отправляет подтверждение (LED is on или LED is off)

  5. JavaScript обновляет текст кнопки на основе ответа

Процесс AJAX Детали процесса

Доступные скетчи

  • ESP8266_LED_CONTROL_AJAX_01: базовая настройка с переформатированным HTML

  • ESP8266_LED_CONTROL_AJAX_02: рабочая реализация AJAX

  • ESP8266_LED_CONTROL_AJAX_03: с обратной связью от сервера

Это даже не поверхностное знакомство с возможностями JavaScript и AJAX. Если вы не знакомы с ними, стоит почитать онлайн-материалы или даже купить пару книг. Ресурсы: W3Schools и TutorialsPoint.