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
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() включает асинхронные запросы, предотвращая блокировку браузера.
Примечание
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" );
}
Процесс работы версии с подтверждением
Нажатие кнопки переводит состояние в «Turning on/off»
AJAX-запрос отправляется (
LEDONилиLEDOFF)ESP8266 обрабатывает запрос и переключает светодиод
Сервер отправляет подтверждение (
LED is onилиLED is off)JavaScript обновляет текст кнопки на основе ответа
Доступные скетчи
ESP8266_LED_CONTROL_AJAX_01: базовая настройка с переформатированным HTML
ESP8266_LED_CONTROL_AJAX_02: рабочая реализация AJAX
ESP8266_LED_CONTROL_AJAX_03: с обратной связью от сервера
Это даже не поверхностное знакомство с возможностями JavaScript и AJAX. Если вы не знакомы с ними, стоит почитать онлайн-материалы или даже купить пару книг. Ресурсы: W3Schools и TutorialsPoint.