ESP8266 и Arduino IDE. Часть 8: Авто-обновление веб-страницы
Примечание
Оригинал статьи: martyncurrey.com
Этот урок демонстрирует, как создавать самообновляющиеся веб-страницы на ESP8266 с использованием трёх различных подходов: HTML meta refresh, JavaScript page reload и AJAX с частичным обновлением страницы.
Метод 1: HTML Meta Refresh
Старые веб-сайты требовали взаимодействия пользователя для обновления контента. HTML-тег refresh обеспечивает автоматическую перезагрузку страницы:
<meta http-equiv="refresh" content="30">
Этот подход перезагружает всю страницу каждые 30 секунд, но считается «неуклюжим» и имеет минимальный интервал в 1 секунду.
Скетч: ESP8266_Part8_01_AutoUpdate_HTML
/*
* Sketch: ESP8266_Part8_01_AutoUpdate_HTML
* 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'>
<meta http-equiv='refresh' content='5'>
<style>
body {font-size:100%;}
#main {display: table; margin: auto; padding: 0 10px 0 10px; }
h2 {text-align:center; }
p { text-align:center; }
</style>
<title>Auto Update Example Using HTML</title>
</head>
<body>
<div id='main'>
<h2>Auto Update Example Using HTML</h2>
<div id='count'>
<p>Count = %count%</p>
</div>
</div>
</body>
</html>
)=====";
#include <ESP8266WiFi.h>
char ssid[] = "NetworkName";
char pass[] = "password";
WiFiServer server(80);
String tmpString = "";
unsigned int count = 0;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Serial started at 115200");
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; }
count ++;
tmpString = html_1;
tmpString.replace("%count%", String(count) );
client.flush();
client.print( header );
client.print( tmpString );
Serial.print("count = "); Serial.println(count);
delay(5);
}
Метод 2: JavaScript setTimeout
JavaScript предоставляет больше контроля с setTimeout() и setInterval():
function refresh(refreshPeriod) {
setTimeout('location.reload(true)', refreshPeriod);
}
window.onload = refresh(5000);
Этот метод даёт больше гибкости, но по-прежнему перезагружает всю страницу, что может вызвать проблемы с производительностью.
Метод 3: AJAX с setInterval
Наиболее эффективный подход использует AJAX с setInterval() для обновления только определённых элементов страницы:
setInterval(updateCount, 5000);
Вместо перезагрузки всей страницы AJAX-запросы получают только необходимые данные, обеспечивая более плавные визуальные обновления.
Скетч: ESP8266_Part8_03_AutoUpdate_Javascript_AJAX
/*
* Sketch: ESP8266_Part8_03_AutoUpdate_Javascript_AJAX
* 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:100%;}
#main {display: table; margin: auto; padding: 0 10px 0 10px; }
h2 {text-align:center; }
p { text-align:center; }
</style>
<script>
function updateCount() {
ajaxLoad('getCount');
}
var ajaxRequest = null;
if (window.XMLHttpRequest) { ajaxRequest =new XMLHttpRequest(); }
else { ajaxRequest =new ActiveXObject("Microsoft.XMLHTTP"); }
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;
document.getElementById('count_P').textContent = ajaxResult;
}
}
ajaxRequest.send();
}
setInterval(updateCount, 5000);
</script>
<title>Auto Update Example Using Javascript 2</title>
</head>
<body>
<div id='main'>
<h2>Auto Update Example Using Javascript 2</h2>
<div id='count_DIV'>
<p id='count_P'>Count = 0</p>
</div>
</div>
</body>
</html>
)=====";
#include <ESP8266WiFi.h>
char ssid[] = "NetworkName";
char pass[] = "password";
WiFiServer server(80);
String request = "";
unsigned int count = 0;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Serial started at 115200");
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');
if ( request.indexOf("getCount") > 0 ) {
count ++;
client.print( header );
client.print( "Count = " );
client.print( count );
Serial.print("Count=");
Serial.println(count);
}
else {
client.flush();
client.print( header );
client.print( html_1 );
count = 0;
}
delay(5);
}
Практический пример: монитор температуры и влажности
Урок завершается практическим примером с датчиком DHT11. Веб-страница отображает:
Текущее время (обновляется каждую секунду локально)
Температуру в Цельсиях и Фаренгейтах (обновляется каждые 5 секунд через AJAX)
Влажность в процентах (обновляется каждые 5 секунд через AJAX)
Схема подключения
Скетч: ESP8266_Part8_04_AutoUpdate_DHT11
/*
* Sketch: ESP8266_Part8_04_AutoUpdate_DHT11
* 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:100%;}
#main {display: table; margin: auto; padding: 10px 10px 10px 10px; }
#content { border: 5px solid blue; border-radius: 15px; padding: 10px 0px 10px 0px;}
h2 {text-align:center; margin: 10px 0px 10px 0px;}
p { text-align:center; margin: 5px 0px 10px 0px; font-size: 120%;}
#time_P { margin: 10px 0px 15px 0px;}
</style>
<script>
function updateTime() {
var d = new Date();
var t = "";
t = d.toLocaleTimeString();
document.getElementById('P_time').textContent = t;
}
function updateTemp() {
ajaxLoad('getTemp');
}
var ajaxRequest = null;
if (window.XMLHttpRequest) { ajaxRequest =new XMLHttpRequest(); }
else { ajaxRequest =new ActiveXObject("Microsoft.XMLHTTP"); }
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;
var tmpArray = ajaxResult.split("|");
document.getElementById('temp_C').textContent = tmpArray[0];
document.getElementById('temp_F').textContent = tmpArray[1];
document.getElementById('hmd').textContent = tmpArray[2];
}
}
ajaxRequest.send();
}
var myVar1 = setInterval(updateTemp, 5000);
var myVar2 = setInterval(updateTime, 1000);
</script>
<title>Temperature & Humidity Monitor</title>
</head>
<body>
<div id='main'>
<h2>Temperature & Humidity Monitor</h2>
<div id='content'>
<p id='P_time'>Time</p>
<h2>Temperature</h2>
<p> <span id='temp_C'>--.-</span> °C - <span id='temp_F'>--.-</span> °F </p>
<h2>Humidity</h2>
<p> <span id='hmd'>--</span> % </p>
</div>
</div>
</body>
</html>
)=====";
#include <ESP8266WiFi.h>
char ssid[] = "myNetworkName";
char pass[] = "password";
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
float tempF = 0;
float tempC = 0;
float humid = 0;
WiFiServer server(80);
String request = "";
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Serial started at 115200");
Serial.println();
dht.begin();
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.println(request);
Serial.println("");
if ( request.indexOf("getTemp") > 0 ) {
Serial.println("getTemp received");
humid = dht.readHumidity();
tempC = dht.readTemperature();
tempF = dht.readTemperature(true);
if ( !isnan(humid) && !isnan(tempC) && !isnan(tempC) ) {
client.print( header );
client.print( tempC );
client.print( "|" );
client.print( tempF );
client.print( "|" );
client.print( humid );
Serial.println("data sent");
}
else {
Serial.println("Error reading the sensor");
}
}
else {
client.flush();
client.print( header );
client.print( html_1 );
Serial.println("New page served");
}
delay(5);
}
Результат
Сервер различает начальные запросы страницы и последующие AJAX-запросы данных, проверяя наличие строки «getTemp» в запросе. В зависимости от этого возвращается либо полный HTML, либо данные датчика.